Consuming Hateoas: Non-matching JSON-request generated - java

Hello dear Stack Overflow!!! :)
I have a bit of a problem. I am attempting to consume a Hateoas-based application in a project and I'm having issues with Hateoas and it generating a faulty JSON-request for a test. I will provide some code examples!
Basically, I use a JSONconverter that tries to convert my request body(post) to JSON but it throws an error with what I actually get. Some information and code:
Here is my ObjectMapper that I am using:
ObjectMapper objectMapper = (ObjectMapper) bean;
objectMapper.registerModules(new Jackson2HalModule());
Here is my converter config where I plug the objectmapper and the supported media types:
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
converter.setSupportedMediaTypes(Arrays.asList(MediaTypes.HAL_JSON, MediaType.APPLICATION_OCTET_STREAM, MediaType.APPLICATION_JSON_UTF8));
converter.setObjectMapper(objectMapper);
Here is my RestTemplate where I plug the Jackson 2 Http Converter I just made:
#Bean
public RestTemplate uttagRestTemplate(RestTemplateBuilder builder) {
return builder.messageConverters(mappingJackson2HttpMessageConverter, new StringHttpMessageConverter(Charset.forName("UTF-8")))
Here is the test I run with the output:
mockServer.expect(requestTo(url + "/person/" + id + "/links")).andExpect(header("Content-type", MediaType.APPLICATION_JSON_UTF8.toString()))
.andExpect(header("accept", MediaType.APPLICATION_JSON_UTF8.toString()))
.andExpect(content().string(jsonConverter.toJson(Arrays.asList(link)))).andExpect(method(HttpMethod.POST)).andRespond(withSuccess());
Finally, here is my test output(don't mind the data, it's just test data):
Expected :[{"id":2112,"rel":"EZyb","href":"dspK0XickvvcMw0","type":"RaAmwWkZHlagrcQ","length":992539719,"title":"OuaRoPRClRpvprg"}]
Actual :"[{\"id\":2112,\"rel\":\"EZyb\",\"href\":\"dspK0XickvvcMw0\",\"type\":\"RaAmwWkZHlagrcQ\",\"length\":992539719,\"title\":\"OuaRoPRClRpvprg\"}]"
It seems to do something really weird with the "actual" json-generated body. I'd like to have it match my expected, but no luck.
I've tried solving this, and if I remove the MediaType.HAL_JSON from my MappingJacksonConverter somehow it works in my tests, but then I can't consume the hateoas client. I need the media type there for it to work.
I've also tried writing my expected JSON with my MappingJackson writer, but it produces the exact same expected output.
Does anybody know what's going on here and can help me with this? Do you know how I may generate correct JSON-body to get the assert to work? Frankly it's doing my head in - and choosing between functioning tests without the media type and being able to consume the hateoas application with it obviously isn't an option for me. :(
Cheers for reading if you made it this far! :) Any pointers are welcome.

I figured out what it was. With the new config, it seems that the application automatically converts to json and I didn't need to use my own jsonConverter anymore. So what was going on as basically a toJson conversion on an already jsonified object.
After removing my own jsonconverter implementation, it now functions correctly.

Related

String Array returning [[object Object]] at restTemplate

I'm trying to use one api that in the response body we have this structure:
{"flag": false,
"codes":[
"a3f2b9ddf8886b04993632"]}
At Postman, and executing a curl, the response is exactly this one.
But when I use restTemplate.exchange(...) to return the response body,it's always returning for codes: [[object Object]]
UriComponentsBuilder builder = UriComponentsBuilder.fromUri(URL...); //cannot show partner's url here
header.add("Accept", MediaType.APPLICATION_JSON_VALUE);
header.add("Content-Type", MediaType.APPLICATION_JSON_VALUE);
ResponseEntity<String> resourceHttpEntity = restTemplate.exchange(
builder.toUriString(),
HttpMethod.GET,
new HttpEntity<>(header), String.class); //header also has an authorization bearer token that is in another class
System.out.println(resourceHttpEntity.getBody());
Response body from this:
{"flag":false,"codes":["[object Object]"]}
I saw some examples that this occurs, but in Javascript, and we use JSON.stringfy to solve it.
But at Java we don't have this option. I don't know if is a miss-configuration or something.
Even I try to get this response body with the class model using String[], ArrayList for this property. Tried to convert in String.class, JSonNode.class, and it's returning this way.
I tried to use objectMapper to convert, and even test with HTTPURLConnection to confirm and it's happening the same thing. I have the same result.
Any suggestions?
If you need to print the content of a generic object in Json format you can print it as follow:
ObjectWriter ow = new ObjectMapper().writer().withDefaultPrettyPrinter();
System.out.println(ow.writeValueAsString(object));
// Or better log.info(ow.writeValueAsString(object);
If you don't need to format your output you can call directly writeValueAsString on the objectMapper:
Method that can be used to serialize any Java value as a String
System.out.println(new ObjectMapper().writeValueAsString(object));
Updated answer after the update on the question.
It seems that the remote service that you are invoking is returning exactly the body that you showed in the updated answer.
Your code is treating the body as a simple string, so there is no manipulation on the client-side (your code). It means that is possible that for particular values the server-side (the web service that you are invoking) is performing some strange operation (probably a bean to json conversion) that will generate this output.
You have many ways to check it:
make the same call using postman
make the same call using curl
add a sniffer between your client and the server and use it to log the passing data
For the first two alternatives you have to be sure to use exactly the same data used by the java code. And execute them from the same machine (may be that a proxy can change the behaviour of the call).
We discover that the RestTemplate #Bean that we already have in code, was causing this issue. So I just instantiate a new RestTemplate from scratch, and the issue was resolved.
Thank you for your time.
Create Java class with below attributes and use as response entity type.
Public class Response{
boolean flag;
List<String> codes;
}
ResponseEntity<Response> resourceHttpEntity =
restTemplate.exchange(
builder.toUriString(),
HttpMethod.GET,
new HttpEntity<>(header), Response.class);

IDE can't resolve writeValue() method for Jackson ObjectMapper

All my life I worked with C++, but recently decided to play a bit with Java. I have started with learning Jackson serialier/desirialer library. The basic example looks like that
ObjectMapper objectMapper = new ObjectMapper();
Car car = new Car("yellow", "renault");
objectMapper.writeValue(new File("target/car.json"), car);
It looks pretty easy and no problems should arise here. My IDE is IntelliJ, so before running the code I used Maven to get next libraries
com.fasterxml.jackson.core:jackson-annotations:2.9.4
com.fasterxml.jackson.core:jackson-core:2.9.4
com.fasterxml.jackson.core:jackson-databind:2.9.4
Taking into account that class Car is implemented somewhere above it should now work. However when I try to build the code I get an error that compiler can't resolve the symbol writeValue(). Autocomplition faces the same problem. My first assumption is that not all external libraries are correclty resolved, but when I open the source code for ObjectMapper in IDE I clearly see method writeValue(). Even more if I try to call this method just after the creating object with operator new autocomplition is able to recognize it. If I remove the line with
writeValue() call code successfully compiles.
From C++ prospective it looks like madness, so please suggest why it happens and how it can be resolved?

Serializing and deserializing XText Model Instance to OutputStream

I have the following use case. I need to transfer an XText model instance via the network in some serialized format. For this purpose I need to serialize the model on the client side, send it as the body of some kind of POST request and deserialize it on the server side.
At the time I issue the send request I do only have access to the object structure of my model. I do not have the files I created the model from any more (it would be possible, but it would destroy the cleanliness of my architecture and makes testing very complex).
I created the following code for serializing the model based on some threads here on StackOverflow and tutorials available via other Websites to serialize an XText-Model
Resource.Factory.Registry.INSTANCE.getExtensionToFactoryMap( ).put("xtextbin", new XMIResourceFactoryImpl());
Injector injector = Guice.createInjector(new ScenarioRuntimeModule());
Serializer serializer = injector.getInstance(Serializer.class);
System.out.println(serializer.serialize(scenario));
However it does not work and I get the following error:
com.google.inject.CreationException: Guice creation errors:
1) Error injecting constructor, org.eclipse.emf.common.util.WrappedException: org.eclipse.emf.ecore.resource.impl.ResourceSetImpl$1DiagnosticWrappedException: com.sun.org.apache.xerces.internal.impl.io.MalformedByteSequenceException: Ungültiges Byte 1 von 1-Byte-UTF-8-Sequenz.
The problem most likely lies with the XMIResourceFactoryImpl, which I do not know how to use properly.
Another approach might be to use:
String serializedScenario = ModelUtils.serialize(scenario);
But I do not know how to deserialize the result of this serialize call.
My question however is more basic, since the code above might be a completely wrong approach. Unfortunately I did not find very much about this in the documentation or anywhere else on the Web.
TL;DR:
What is the best way to serialize an XText object model and to deserialize it again?
The first line doesn't belong here at all, just remove it.
How did you create/obtain the object 'scenario'?
If it was parsed with Xtext already you can obtain the serializer like this:
((XtextResource)scenario.eResource()).getResourceServiceProvider
.get(ISerializer.class)

Parsing Jersey inputstream to JacksonObject

I have a REST WS implemented using Jersey/Jackson. The method which has been implemented is PUT and it is working fine until i get an empty or null body.
After googling a bit, I realized that it is a known issue and there are couple of work arounds available. One of the work around that i found (and implemented) is using ContentRequestFilter to intercept calls, do basic checks and decide what to do.
But in that case, I have to check if the call is for that specific method. I don't like this since what if the method changes in future ?
What i want is to receive as InputStream instead of parsed JacksonObject (Its a custom POJO object created using Jackson Annotations) and parse the inputstream to do that. However, I am unable to find a reference to do that i.e., parsing a jackson object, out of input stream (based on input media type) and return the respective object.
Can someone direct me to some helpful resources or help me here ?
This is an easy way of getting the contents from a request handled by Resource. Just replace Map.class with your annotated POJO:
#POST
public void handle(String requestBody) throws IOException {
ObjectMapper om = new ObjectMapper();
Map result = om.readValue(requestBody, Map.class);
}
With this approach you are free to handle a null value in any way you find suitable.

How do I disable fail_on_empty_beans in Jackson?

Using jackson 2.1, how do I disable the fail_on_empty beans that the error message seems to want me to disable?
I'm assuming this is just the simplest thing in the world, but hell it is late and I haven't been able to find a simple tutorial or anything particularly obvious from the api. SerializationFactory? Why would they make it so unintuitive and then make the error message seem so straightforward?
Although I do like the error message, I mean, it is better than an NPE.
I'm assuming there is a way to do this using annotations - but I'm not keen on using them at all for the simplistic work I'm doing!
You can do this per class or globally, I believe.
For per class, try #JsonSerialize above class declaration.
For a mapper, here's one example:
ObjectMapper mapper = new ObjectMapper();
mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
// do various things, perhaps:
String someJsonString = mapper.writeValueAsString(someClassInstance);
SomeClass someClassInstance = mapper.readValue(someJsonString, SomeClass.class)
The StackOverflow link below also has an example for a Spring project.
For REST with Jersey, I don't remember off the top off my head, but I believe it's similar.
Couple of links I dug up: (edited 1st link due to Codehaus shutting down).
https://web.archive.org/web/20150513164332/https://jira.codehaus.org/browse/JACKSON-201
Jackson serializationConfig
If you are using Spring Boot, you can set the following property in application.properties file.
spring.jackson.serialization.FAIL_ON_EMPTY_BEANS=false
If you wish to get JSON object without any extra fields - please add this annotation to your class, it worked perfect for me.
#JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
You can also add in your application.properties file this row, but it will add an extra field to your JSON.
spring.jackson.serialization.FAIL_ON_EMPTY_BEANS=false
You can also get the same issue if your class doesn't contain any public methods/properties. I normally have dedicated DTOs for API requests and responses, declared public, but forgot in one case to make the methods public as well - which caused the "empty" bean in the first place.
You can also probably annotate the class with #JsonIgnoreProperties(ignoreUnknown=true) to ignore the fields undefined in the class
In Jersey Rest Services just use the JacksonFeatures annotation ...
#JacksonFeatures(serializationDisable = {SerializationFeature.FAIL_ON_EMPTY_BEANS})
public Response getSomething() {
Object entity = doSomething();
return Response.ok(entity).build();
}
T o fix this issue configure your JsonDataFormat class like below
ObjectMapper mapper = new ObjectMapper();
mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
which is almost equivalent to,
mapper.configure(SerializationConfig.Feature.FAIL_ON_EMPTY_BEANS, false);
I don't fully understand the reason behind this exception, but for Spring Boot projects adding the following to the properties file works a treat
application.yml
spring:
jackson:
serialization:
FAIL_ON_EMPTY_BEANS: false
application.properties
spring.jackson.serialization.FAIL_ON_EMPTY_BEANS = false
In my case, I missed to write #JsonProperty annotation in one of the fields which was causing this error.
If you use org.codehaus.jackson.map.ObjectMapper, then pls. use the following lines
mapper.configure(SerializationConfig.Feature.FAIL_ON_EMPTY_BEANS, false);
Adding a solution here for a different problem, but one that manifests with the same error... Take care when constructing json on the fly (as api responses or whatever) to escape literal double quotes in your string members. You may be consuming your own malformed json.
ObjectMapper mapper = new ObjectMapper();
Hi,
When I use mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false)
My json object values come '' blank in angular page mean in response
Solved with the help of only below settings
mapper.setVisibility(mapper.getSerializationConfig().getDefaultVisibilityChecker().
withFieldVisibility(JsonAutoDetect.Visibility.ANY).withGetterVisibility(JsonAutoDetect.Visibility.NONE)
.withSetterVisibility(JsonAutoDetect.Visibility.NONE)
.withCreatorVisibility(JsonAutoDetect.Visibility.NONE));
If it is a Spring App, just paste the code in config class
#Bean
public ObjectMapper getJacksonObjectMapper() {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.findAndRegisterModules();
objectMapper.configure(
com.fasterxml.jackson.databind.SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
return objectMapper;
}
I get the same error when I return InvoiceDTO as a response to the client. The problem was when I used the bean (Customer) in the DTO (InvoiceDTO). So, to solve I changed the bean (Customer) to DTO (CustomerDTO) to disable serialization and it is worked fine.
In my case I didnt need to disable it , rather I had to put this code on top of my class : (and this solved my issue)
#JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class)//this is what was added
#Value //this was there already
#Builder//this was there already
public class NameOfClass {
//some code in here.
}

Categories

Resources