I have the below method and I need to unit test it using JUNIT and Mockito. I am confused how to test the foreach method which returns void.
public List<Data> extractOutPutResponse(List<SearchHit> searchHits) {
List<Data> outputData = new ArrayList<>();
Gson gson = new Gson();
searchHits.forEach(hit -> outputData.add(gson.fromJson(hit.getSourceAsString(), Data.class)));
return outputData;
}
Related
I have a custom jackson serializer, and it works for serializing single pojos. Im trying to serialize a list of objects. Without the custom serializer I can just do:
public List<Sale> getAllSales() {
return saleRepository.getAll();
}
which works fine, but I want to return a very specific set of data, so I made a custom serializer, which also works but only for single objects:
public Sale getSale(int id) {
ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addSerializer(Sale.class, new SaleSerializer());
mapper.registerModule(module);
Sale sale = saleRepository.findById(1).orElse(null);
return mapper.writeValueAsString(sale);
}
How do I do the implement the custom serializer for a list of objects?
I'm not sure if this is the best way to do this, but I ended up doing it this way.
public ArrayNode getAllSalesToday() throws JsonProcessingException {
LocalDate localDate = LocalDate.now();
LocalDateTime startOfDay = localDate.atStartOfDay();
LocalDateTime endOfDay = localDate.atTime(LocalTime.MAX);
ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addSerializer(Sale.class, new SaleSerializer());
mapper.registerModule(module);
List<Sale> saleList = saleRepository.getAllByInitialDepositDateIsBetween(startOfDay,endOfDay);
ArrayNode arrayNode = mapper.createArrayNode();
for (Sale sale: saleList){
String x = mapper.writeValueAsString(sale);
JsonNode jsonNode = mapper.readTree(x);
arrayNode.add(jsonNode);
}
return arrayNode;
}
I am new to testing and i am trying to write a unit test cases on a Flink Datastream which takes input a jsonobject and passes the json object to a processfuntion and it returns a valid or invalid jsonobject when certain rule conditions are met below is the junit test case, below i am trying to compare the output jsonobject from process function with the jsonobject of the input file
#Test
public void testcompareInputAndOutputDataJSONSignal() throws Exception {
org.json.JSONObject jsonObject = toJsonObject();
String input = jsonObject.toString();
String output = JSONDataStreamOutput();
assertEquals(mapper.readTree(input), mapper.readTree(output));
}
below is my toJSONObject and JSONDataStream meathods
public static JSONObject toJsonObject() throws IOException, ParseException {
JSONParser jsonParser = new JSONParser();
FileReader fileReader = new FileReader(getFileFromResources("input.json"));
JSONObject obj = (JSONObject) jsonParser.parse(fileReader);
return obj;
}
public String SignalDataStreamOutput() throws Exception {
final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
DataStream<JSONObject> validSignal = env.fromElements(toJsonObject())
.process(new JsonFilter());
String outputFolder = "output";
validSignal.writeAsText(outputFolder).setParallelism(1);
env.execute();
String content = new String(Files.readAllBytes(Paths.get("output.txt")));
return content;
}
What i am doing is i am converting a jsonfile to jsonobject using the toJSONObject method and sending to a data stream using SignalDataStreamOutput method which will intern send it to a process function in JsonFilter class and validate it against a set of rules and if it's valid it will return a jsonobject and when trying to access the jsonobject directly from stream i am getting value like org.apache.flink#994jdkeiri so i am trying to write the output to a file and trying to read it back to a string and comparing it in test method but this is a work around process and i found a link to use Mockito framework here i changed it to use json object like below
final Collector<JSONObject> collectorMock = (Collector<JSONObject>)Mockito.mock(JsonFilter.class);
final Context contextMock = Mockito.mock(Context.class);
#Test
public void testcompareInputAndOutputDataForValidSignal() throws Exception {
org.json.JSONObject jsonObject = convertToJsonObject();
Mockito.verify(collectorMock).collect(jsonObject);
}
but the above approach is also not working can you suggest me simplified approach to test the json object
Using spring hateoas 1.0.3 with a traverson client is causing problems when the rest-entity has an attribute of type "java.time.Instant".
The error i get is
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `java.time.Instant`
I found that the HttpMessageConverter used inside of the RestTemplate in traverson has only the Jackson2HalModule registered.
Is there a way that i can also register the jackson-modules-java8 module in traverson?
Or is there a way that i can register the Jackson2HalModule in my restTemplate outside of traverson?
Following worked for me in spring-hateoas 1.1.2.RELEASE
private static RestTemplate getRestTemplate() {
List<HttpMessageConverter<?>> httpMessageConverters = SpringFactoriesLoader.loadFactories(TraversonDefaults.class,
Traverson.class.getClassLoader()).get(0).getHttpMessageConverters(Collections.singletonList(MediaTypes.HAL_JSON));
Optional<HttpMessageConverter<?>> first = httpMessageConverters.stream().filter(i -> i instanceof MappingJackson2HttpMessageConverter)
.findFirst();
if (first.isPresent()) {
MappingJackson2HttpMessageConverter httpMessageConverter = (MappingJackson2HttpMessageConverter) first.get();
httpMessageConverter.getObjectMapper().registerModule(new JavaTimeModule());
}
return new RestTemplateBuilder().messageConverters(httpMessageConverters).build();
}
and then using it:
Traverson traverson = new Traverson(URI.create("http://localhost:8080"), MediaTypes.HAL_JSON);
traverson.setRestOperations(getRestTemplate());
After some investigation i found a solution that works for me.
The background is that the traverson client registers a MappingJackson2HttpMessageConverter with contains the Jackson2HalModule.
To fix the problem i had to register also the JavaTimeModule.
I did the following
RestTemplateBuilder genericBuilder = this.restTemplateBuilder
.setConnectTimeout(Duration.ofMillis(configuration.getSecurityRestConnectTimeout()))
.setReadTimeout(Duration.ofMillis(configuration.getSecurityRestReceiveTimeout()));
// my normal restTemplate
RestTemplateBuilder restTemplate = genericBuilder
.defaultMessageConverters()
.build();
// HAL specific restTemplate
RestTemplateBuilder restTemplateHal = genericBuilder
.messageConverters(getHalConverter(Arrays.asList(MediaTypes.HAL_JSON)))
.build();
The HalConverter is generated like this (registering also JavaTimeModule):
private static HttpMessageConverter<?> getHalConverter(List<MediaType> halFlavours) {
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new Jackson2HalModule());
mapper.registerModule(new JavaTimeModule());
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
converter.setObjectMapper(mapper);
converter.setSupportedMediaTypes(halFlavours);
return converter;
}
Then you can use Traverson in setting the just generated restTemplateHal
Traverson traverson = new Traverson(uri, MediaTypes.HAL_JSON);
traverson.setRestOperations(restTemplateHal);
MyClass myclass = traverson.follow().toObject(MyClass.class);
I want to write basic test to execute a POST request on a /users URL with JSON payload to create a user. I cannot find how to convert a new object to JSON, and so far have this much, it's obviously wrong but explains the purpose:
#Test public void createUser() throws Exception {
String userJson = new User("My new User", "myemail#gmail.com").toJson();
this.mockMvc.perform(post("/users/").contentType(userJson)).andExpect(status().isCreated());
You can use jackson object mapper and then user writeValueAsString method.
So
#Autowired
ObjectMapper objectMapper;
// or ObjectMapper objectMapper = new ObjectMapper(); this with Spring Boot is useless
#Test public void createUser() throws Exception {
User user = new User("My new User", "myemail#gmail.com");
this.mockMvc.perform(post("/users/")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(user)))
.andExpect(status().isCreated());
}
I hope this can help you
I can't seem to find out how to serialize Hibernate's implementation of constraint violations using Gson.
Here's what I've tried so far.
Approach 1
MyPojo aPojo = new MyPojo();
Gson gson = new Gson();
Set<ConstraintViolation<MyPojo>> violations = validator.validate(aPojo);
System.out.println(gson.toJson(violations));
Fails with this error:
java.lang.UnsupportedOperationException:
Attempted to serialize java.lang.Class: com.bar.baz.MyPojo.
Forgot to register a type adapter?
at com.google.gson.internal.bind.TypeAdapters$1.write(TypeAdapters.java:67)
at com.google.gson.internal.bind.TypeAdapters$1.write(TypeAdapters.java:61)
at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:68)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.write(ReflectiveTypeAdapterFactory.java:89)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:195)
at com.google.gson.internal.bind.ObjectTypeAdapter.write(ObjectTypeAdapter.java:107)
at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:68)
at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.write(CollectionTypeAdapterFactory.java:96)
at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.write(CollectionTypeAdapterFactory.java:60)
at com.google.gson.Gson.toJson(Gson.java:593)
at com.google.gson.Gson.toJson(Gson.java:572)
at com.google.gson.Gson.toJson(Gson.java:527)
at com.google.gson.Gson.toJson(Gson.java:507)
Approach 2
Gson gson = new Gson();
Set<ConstraintViolation<MyPojo>> violations = validator.validate(MyPojo);
System.out.println(
gson.toJson(violations,
new TypeToken<ConstraintViolation<MyPojo>>() {}.getType())
);
Fails by not serializing MyPojo's properties:
Output: {}.
Approach 3
I was expecting this approach to delegate serialization to my custom Serializer but it still fails:
GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapter(
new TypeToken<ConstraintViolation<MyPojo>>() {}.getType(),
new JsonSerializer<ConstraintViolation<MyPojo>>() {
#Override
public JsonElement serialize(ConstraintViolation<MyPojo> src, Type typeOfSrc, JsonSerializationContext context) {
JsonObject result = new JsonObject();
result.addProperty("aTestProperty", "A Test Value");
return result;
}
});
Gson gson = builder.create();
Set<ConstraintViolation<MyPojo>> violations = validator.validate(MyPojo);
System.out.println(gson.toJson(violations));
However it fails with this error:
java.lang.UnsupportedOperationException:
Attempted to serialize java.lang.Class:
com.bar.baz.MyPojo.
Forgot to register a type adapter?
at com.google.gson.internal.bind.TypeAdapters$1.write(TypeAdapters.java:67)
at com.google.gson.internal.bind.TypeAdapters$1.write(TypeAdapters.java:61)
at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:68)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.write(ReflectiveTypeAdapterFactory.java:89)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:195)
at com.google.gson.internal.bind.ObjectTypeAdapter.write(ObjectTypeAdapter.java:107)
at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:68)
at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.write(CollectionTypeAdapterFactory.java:96)
at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.write(CollectionTypeAdapterFactory.java:60)
at com.google.gson.Gson.toJson(Gson.java:593)
at com.google.gson.Gson.toJson(Gson.java:572)
at com.google.gson.Gson.toJson(Gson.java:527)
at com.google.gson.Gson.toJson(Gson.java:507)
Approach 4
Looking at the error message, I though this might work:
GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapter(
new TypeToken<ConstraintViolation<MyPojo>>() {}.getType(),
new JsonSerializer<ConstraintViolation<MyPojo>>() {
#Override
public JsonElement serialize(ConstraintViolation<MyPojo> src, Type typeOfSrc, JsonSerializationContext context) {
JsonObject result = new JsonObject();
result.addProperty("aTestProperty", "A Test Value");
return result;
}
});
builder.registerTypeAdapter(
new TypeToken<MyPojo>() {}.getType(),
new JsonSerializer<MyPojo>() {
#Override
public JsonElement serialize(MyPojo src, Type typeOfSrc, JsonSerializationContext context) {
JsonObject result = new JsonObject();
result.addProperty("anotherTestProperty", "Another Test Value");
return result;
}
});
Gson gson = builder.create();
Set<ConstraintViolation<MyPojo>> violations = validator.validate(MyPojo);
System.out.println(gson.toJson(violations));
But it fails with a similar error.
Approach 5: Working but ugly
The only thing that I've managed to make work is to register the serializer with the type of the vendor (Hibernate) specific implementation for ConstraintViolation:
Set<ConstraintViolation<MyPojo>> violations = validator.validate(MyPojo);
GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapter(
new TypeToken<ConstraintViolationImpl>() {}.getType(),
new JsonSerializer<ConstraintViolation<MyPojo>>() {
#Override
public JsonElement serialize(ConstraintViolation<MyPojo> src, Type typeOfSrc, JsonSerializationContext context) {
JsonObject result = new JsonObject();
result.addProperty("aTestProperty", "A Test Value");
return result;
}
});
Gson gson = builder.create();
System.out.println(gson.toJson(violations));
Is there a way to make this work without relying on the concrete implementation of ConstraintViolation (i.e. org.hibernate.validator.internal.engine.ConstraintViolationImpl)?
There doesn't seem to be a reasonable approach to serialize javax.validation.ConstraintViolation objects. In fact, even Jackson errs while trying to serialize the set:
Exception in thread "main" com.fasterxml.jackson.databind.JsonMappingException: fromIndex(0) > toIndex(-1) (through reference chain: java.util.HashSet[0]->org.hibernate.validator.internal.engine.ConstraintViolationImpl["propertyPath"]->org.hibernate.validator.internal.engine.path.PathImpl["pathWithoutLeafNode"]->org.hibernate.validator.internal.engine.path.PathImpl["pathWithoutLeafNode"]->org.hibernate.validator.internal.engine.path.PathImpl["pathWithoutLeafNode"])
at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:232)
For the time being, I just convert the set of errors into a set of custom POJOs I've written and serialize that instead.
Custom ValidationError POJO:
public class ValidationError {
private String className;
private String propertyPath;
private String errorMessage;
public static Set<ValidationError> fromViolations(Set violations) {
Set<ValidationError> errors = new HashSet<ValidationError>();
for (Object o : violations) {
ConstraintViolation v = (ConstraintViolation) o;
ValidationError error = new ValidationError();
error.setClassName(v.getRootBeanClass().getSimpleName());
error.setErrorMessage(v.getMessage());
error.setPropertyPath(v.getPropertyPath().toString());
errors.add(error);
}
return errors;
}
public String getClassName() {
return className;
}
public void setClassName(String className) {
this.className = className;
}
public String getPropertyPath() {
return propertyPath;
}
public void setPropertyPath(String propertyPath) {
this.propertyPath = propertyPath;
}
public String getErrorMessage() {
return errorMessage;
}
public void setErrorMessage(String errorMessage) {
this.errorMessage = errorMessage;
}
#Override
public String toString() {
return "ValidationError{" +
"className='" + className + '\'' +
", propertyPath='" + propertyPath + '\'' +
", errorMessage='" + errorMessage + '\'' +
'}';
}
}
Sample usage:
Set<ConstraintViolation<MyBean>> violations = validator.validate(myBean);
Set<ValidationError> errors = ValidationError.fromViolations(violations);
GsonBuilder gsonBuilder = new GsonBuilder();
Gson gson = gsonBuilder.create();
System.out.println(gson.toJson(errors));
Update
For the sake of record, it is worth mentioning that XStream can serialize the set of constraint violations like a charm:
XStream xstream = new XStream(new JettisonMappedXmlDriver());
xstream.setMode(XStream.NO_REFERENCES);
System.out.println(xstream.toXML(violations));
However the generated the object graph is way too much verbose and is not suitable for use in production anyway. You can see the sample output here.