JSON : Unrecognized field "value" (<objectClass>), not marked as ignorable - java

Can someone help me to figure out what's need to be added?
JSON :
{"value":{"keyword":"better","correct":"","page":0,"size":10,"cost":51,"total":1107}}
Object class
#JsonAutoDetect
#JsonSerialize(include = Inclusion.NON_NULL)
#JsonRootName(value = "value")
public class Response {
private int page;
private int size;
private int total;
private int cost;
private int result;
private String keyword;
private String correct;
Still it gets the "Servlet.service() for servlet appServlet threw exception
org.codehaus.jackson.map.exc.UnrecognizedPropertyException:
Unrecognized field "value" (), not marked as ignorable"

Try adding this to your mapper config
mapper.configure(SerializationConfig.Feature.WRAP_ROOT_VALUE, true);
mapper.configure(DeserializationConfig.Feature.UNWRAP_ROOT_VALUE, true);
If you use RestTemplate you will need to configure the underlying jackson mapper. You can do this by configuring your mapper and setting it in the converter. See code below.
ObjectMapper mapper = new ObjectMapper();
mapper.configure(SerializationConfig.Feature.WRAP_ROOT_VALUE, true);
mapper.configure(DeserializationConfig.Feature.UNWRAP_ROOT_VALUE, true);
MappingJacksonHttpMessageConverter messageConverter = new MappingJacksonHttpMessageConverter();
messageConverter.setObjectMapper(mapper);
List<HttpMessageConverter<?>> messageConverters = new ArrayList<HttpMessageConverter<?>>();
messageConverters.add(messageConverter);
RestTemplate restTemplate = new RestTemplate();
restTemplate.setMessageConverters(messageConverters);
See here for more details: https://jira.springsource.org/browse/ANDROID-45

Related

How do I ignore the root node when reading in a json rest api?

I am reading in a rest api that returns a Json file. I need to ignore the "result" and "optionChain" nodes. I am using Spring Boot with Jackson to deal with the mapping of objects.
Thanks in Advance!
For the Json File click here
Here is my Main:
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.http.*;
import org.springframework.web.client.RestTemplate;
import java.util.Collections;
#SpringBootApplication
public class OptionsImpliedMovementApplication implements CommandLineRunner {
public static void main(String[] args) {
SpringApplication.run(OptionsImpliedMovementApplication.class, args);
}
#Override
public void run(String... args) throws Exception {
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
String resourceURL = url;
HttpEntity<String> entity = new HttpEntity<>(headers);
ResponseEntity<String> response = restTemplate.exchange(resourceURL, HttpMethod.GET,entity, String.class);
String rawJson = response.getBody();
ObjectMapper mapper = new ObjectMapper();
//need to read in json ignoring root node
}
Since you're already getting JSON response , then would recommend to use
restTemplate.exchange(URL, HttpMethod.GET, requestEntity, MyPOJO.class);
instead of String.class define your own POJO based on JSON response coming as you have attached in file.json.
In a handy way you can generate your POJO against your JSON from : http://www.jsonschema2pojo.org/ quickly and easily.
So it should look like :
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonPropertyOrder({
"optionChain"
})
public class MyPOJO {
#JsonProperty("optionChain")
private OptionChain optionChain;
// getters and setters
}
And another one :
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonPropertyOrder({
"result",
"error"
})
public class OptionChain {
#JsonProperty("result")
private List<Result> result = null;
#JsonProperty("error")
private Object error;
// getter and setters
}
And other like :
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonPropertyOrder({
"expirationDate",
"hasMiniOptions",
"calls",
"puts"
})
public class Option {
#JsonProperty("expirationDate")
private Integer expirationDate;
#JsonProperty("hasMiniOptions")
private Boolean hasMiniOptions;
#JsonProperty("calls")
private List<Call> calls = null;
#JsonProperty("puts")
private List<Put> puts = null;
So once you'll have the response as :
ResponseEntity<MyPOJO> response = restTemplate.exchange(resourceURL, HttpMethod.GET,entity, MyPOJO.class);
Then response.getBody will give the content inside optionChain node which is what you're looking for. You can then normally drill down to whatever node you want as now you have everything in plain java objects and you can ignore whatever you want or use whatever is needed.
Using objectMapper also you can then achieve the same :
ObjectMapper mapper = new ObjectMapper();
MyPojo myPojo= mapper.readValue(rawJson, MyPojo.class);
Quick (performant) and working.
final ObjectMapper objectMapper = new ObjectMapper();
final JsonNode jsonNode = objectMapper.readTree(rawJson);
final JsonNode result = jsonNode.get("optionChain")
.get("result");
final JsonNode firstResult = result.get(0);
final YourResultClass resultObject = objectMapper.treeToValue(firstResult, YourResultClass.class);
If you need to ignore unknown fields
final ObjectMapper objectMapper =
new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

Convert Json string to Java object gives null (null)

Hello i got this Json string
{"NexusResource":{"resourceURI":"http://nexus.ad.hrm.se/nexus/service/local/repositories/snapshots/content/se/hrmsoftware/hrm/hrm-release/16.1-SNAPSHOT/","relativePath":"/se/hrmsoftware/hrm/hrm-release/16.1-SNAPSHOT/","text":"16.1-SNAPSHOT","leaf":false,"lastModified":"2018-04-09 12:23:59.0 UTC","sizeOnDisk":-1}}
I want to convert this to an object of a class named NexusResource that looks like this
public class NexusResource {
#JsonProperty("resourceURI") private String resourceURI;
#JsonProperty("relativePath") private String relativePath;
#JsonProperty("text") private String text;
#JsonProperty("leaf") private Boolean leaf;
#JsonProperty("lastModified") private String lastModified;
#JsonProperty("sizeOnDisk") private Integer sizeOnDisk;
#JsonIgnore private Map<String, Object> additionalProperties = new HashMap<>();
}
i try to convert it with an ObjectMapper
ObjectMapper mapper = new ObjectMapper();
NexusResource resource = mapper.readValue(version, NexusResource.class);
were version is the Json string but when i log resource all i get is null (null) even though version got all the data.
You can configure your ObjectMapper to unwrap the root value, in order to de-serialize into your POJO.
E.g.:
mapper.configure(DeserializationFeature.UNWRAP_ROOT_VALUE, true);
See API.
You could also work around that by modifying your POJO (see Karol's answer).
Failure to choose either should result in a com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException being thrown, with message: Unrecognized field "NexusResource".
NexusResource is not a root of your JSON but a key. To make your Java mapping work you should define a wrapping type:
public class NexusResources {
#JsonProperty("NexusResource") private NexusResource root;
...
}
and then use it to map:
ObjectMapper mapper = new ObjectMapper();
NexusResources root = mapper.readValue(version, NexusResources.class);
NexusResource resource = root.getRoot();
The problem is that the JSON does not match the class you are trying to parse. Please notice that the JSON has a field called "NexusResource" that has all the other fields. Whereas the class NexusResource.class just has the fields. Two things you can do. Change the JSON to match NexusResource.class, or create a new class that matches the JSON.
1) Change the json to the following.
{"resourceURI":"http://nexus.ad.hrm.se/nexus/service/local/repositories/snapshots/content/se/hrmsoftware/hrm/hrm-release/16.1-SNAPSHOT/","relativePath":"/se/hrmsoftware/hrm/hrm-release/16.1-SNAPSHOT/","text":"16.1-SNAPSHOT","leaf":false,"lastModified":"2018-04-09 12:23:59.0 UTC","sizeOnDisk":-1}
2) Create new class that actually matches your Json.
class NexusResourceJson {
#JsonProperty("NexusResource ")
NexusResource resource;
public NexusResource getResource() {return resource;}
}
ObjectMapper mapper = new ObjectMapper();
NexusResource resource = mapper.readValue(version, NexusResourceJson.class).getResource();

Wrong POST body JSON serialization when using postForEntity in Spring

I'm trying to send an instance of the object EGiftCreationRequest as JSON via POST body in Spring:
final BigDecimal amount = new BigDecimal(100.00);
final String configurationId = "test_configuration_id";
final String referenceNumber = "12345";
EGiftCreationRequest giftCreationRequest = new EGiftCreationRequest() {{
giftAmount(amount);
productConfigurationId(configurationId);
retrievalReferenceNumber(referenceNumber);
}};
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<EGiftCreationRequest> httpEntity = new HttpEntity<EGiftCreationRequest>(giftCreationRequest, headers);
ResponseEntity<EGift> entity = new TestRestTemplate().postForEntity(
"http://localhost:" + this.port + "/eGiftProcessing/v1/generateEGift",
httpEntity,
EGift.class
);
However, for some reason the object is being serialized into the following String:
{"headerParams":{}}
Obviously this has nothing to do with my EGiftCreationRequest, which is actually:
public class EGiftCreationRequest extends RequestBase<EGiftCreationRequest> {
private BigDecimal giftAmount;
private String productConfigurationId;
private String retrievalReferenceNumber;
public BigDecimal giftAmount() {
return this.giftAmount;
}
public String productConfigurationId() {
return this.productConfigurationId;
}
public String retrievalReferenceNumber() {
return this.retrievalReferenceNumber;
}
public EGiftCreationRequest giftAmount(final BigDecimal giftAmount) {
this.giftAmount = giftAmount;
return this;
}
public EGiftCreationRequest productConfigurationId(final String productConfigurationId) {
this.productConfigurationId = productConfigurationId;
return this;
}
public EGiftCreationRequest retrievalReferenceNumber(final String retrievalReferenceNumber) {
this.retrievalReferenceNumber = retrievalReferenceNumber;
return this;
}
}
What can possibly be going on?
This is caused by a misconfigured Jackson mapper. By default, Jackson is looking for accessors named in JavaBeans fashion (get*(), set*()) to retrieve and set values. Since the model uses a different naming convention (the field names themselves), Jackson fails to serialize the object.
The following mapper configuration makes everything work correctly:
ObjectMapper mapper = new ObjectMapper();
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
mapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
mapper.setVisibility(PropertyAccessor.GETTER, JsonAutoDetect.Visibility.NONE);
mapper.setVisibility(PropertyAccessor.SETTER, JsonAutoDetect.Visibility.NONE);
mapper.setVisibility(PropertyAccessor.CREATOR, JsonAutoDetect.Visibility.NONE);
TestRestTemplate testRestTemplate = new TestRestTemplate();
List<HttpMessageConverter<?>> messageConverters = new ArrayList<HttpMessageConverter<?>>();
messageConverters.add(new MappingJackson2HttpMessageConverter(mapper));
testRestTemplate.setMessageConverters(messageConverters);

Do we have to have to post json object with exactly same fields as in pojo object in controller?

I am new to spring rest and am having problem to map JSON object from jquery to controller. My jquery JSON object have some field absent which are present in java object on controller. Do I have to create new class to map such object or is there any way to map these objects without creating new class?
Here are the code
Controller:
#RequestMapping(value = "/createTest", method = RequestMethod.POST,consumes="application/json")
#ResponseBody
public String createTest(#RequestBody TestJsonDTO testJson)
throws JsonProcessingException, IOException {
//....
TestJsonDTO:
public class TestJsonDTO {
private TestSet testSet;
private List<MainQuestion> questionsInTest;
//gettters and setters
TestSet:
public class TestSet implements Serializable {
public TestSet() {
}
#Id
#GeneratedValue
private int id;
private String name;
private int fullmark;
private int passmark;
String duration;
Date createDate = new Date();
Date testDate;
boolean isNegativeMarking;
boolean negativeMarkingValue;
MainQuestion:
public class MainQuestion implements Serializable {
private static final long serialVersionUID = 1L;
public MainQuestion() {
}
#Id
#GeneratedValue
private int id;
private String name;
and my jquery post method
function createTest() {
$.ajax({
type : 'POST',
url : "http://localhost:8085/annotationBased/admin/createTest",
dataType : "json",
contentType : "application/json",
data : testToJSON(),
success : function() {
alert("success")
},
error : function(msg) {
alert("error while saving test");
}
});
}
function testToJSON() {
listOfQuestionForTest = questionToAdd;//array of ids of questions
return JSON.stringify({
"testSet.name" : $('#testname').val(),
"testSet.fullmark" : parseInt($('#fullmark').val()),
"testSet.passmark" : parseInt($('#passmark').val()),
"questionsInTest" : listOfQuestionForTest
// "testDate":$('#testDate').value()
})
}
In JSON.stringify I am not sending all the fields in TestJsonDto. How can I map this?
You should configure Spring this way:
#Configuration
public class ServiceContext
extends WebMvcConfigurationSupport {
#Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
MappingJackson2HttpMessageConverter converter = this.getMappingJackson2HttpMessageConverter();
converters.add(converter);
}
#Bean
public MappingJackson2HttpMessageConverter getMappingJackson2HttpMessageConverter() {
MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter();
ObjectMapper objectMapper = this.getObjectMapper();
mappingJackson2HttpMessageConverter.setObjectMapper(objectMapper);
return mappingJackson2HttpMessageConverter;
}
#Bean
public ObjectMapper getObjectMapper() {
JsonFactory jsonFactory = new JsonFactory();
ObjectMapper objectMapper = new ObjectMapper(jsonFactory);
objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); // this is what you need
objectMapper.setSerializationInclusion(Include.NON_NULL); // this is to not serialize unset properties
return objectMapper;
}
}
Here Spring is configured with an ObjectMapper that doesn't serialize properties whose value is null and that doesn't fail on deserialization if some property is missing.
EDIT: (Added some background and explanations)
Spring converts what comes in HTTP request's body into a POJO (that's what #RequestBody actually tells Spring to do). This conversion is performed by a HttpMessageConverter, which is an abstraction. Spring provides default specific message converters for common media types, such as Strings, JSON, form fields, etc.
In your case, you need to tell Spring how to deserialize the incoming JSON, i.e. how to read the JSON that you're sending from jQuery and how to convert this JSON into the POJO you're expecting to receive in your #Controller (TestJsonDTO in your question).
Jackson 2 is a JSON serialization/deserialization library that is widely used. It's most important class is ObjectMapper, which is used to perform the actual serialization and deserialization. Spring has a specific HttpMessageConverter that uses Jackson in order to serialize and deserialize JSON. This is MappingJackson2HttpMessageConverter, which can receive a Jackson's ObjectMapper instance that you can configure if you want to override default behavior.
This ObjectMapper is configured to not serialize properties that are null in your POJO (i.e. your JSON won't contain these properties as fields), and more important, when deserializing, it is configured to not fail with an exception if there is a missing property in either your JSON or your POJO. This is what objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); actually does.

Jackson object mapper includes escape sequence in responses

When I use object mapper, it inluces \r\n in the responses.Help me how to resolve it.
I am having train POJO and it has String name and String Value.
I set name as "Sydney" and Value as "SYD".It reruns
{\ \ \"name \" : \"Sydney\",\ \ \"Value \" : \"SYD\",\ \ \"isEnable\" : false,\ \ \"isCurrent\" : false\ \ }"
raw value in browser
"{\r\n \"name\" : \"Sydney\",\r\n \"name\" : \"SYD\",\r\n \"isEnable\" : false,\r\n \"isCurrent\" : false\r\n}"
below is my code
Train
public class Train {
public Train() {
}
private String name;
private String value;
private String Code;
private String countryName;
private String state;
private String stateName;
private boolean isEnable;
private boolean isCurrent;
//*getters and setters/*/
}
Controller calss
public ResponseEntity<String> getDetails( )
throws IOException {
ResponseEntity<String> responseEntity = null;
try(StringWriter writer = new StringWriter()) {
ObjectMapper mapper = new ObjectMapper();
Train train = new Train();
// set name and value to the train object//
if(train != null)
{
mapper.setSerializationInclusion(Inclusion.NON_NULL);
mapper.setSerializationInclusion(Inclusion.NON_EMPTY);
mapper.writerWithDefaultPrettyPrinter().writeValue(writer,
train);
responseEntity = new ResponseEntity<>(writer.toString(),
HttpStatus.OK);
}
}
catch()
{}
return responseEntity;
}
Configuration:
#Override
public void configureMessageConverters(
List<HttpMessageConverter<?>> converters) {
converters.add(extendedJsonConvertor());
super.configureMessageConverters(converters);
}
#Bean
public MappingJackson2HttpMessageConverter extendedJsonConvertor() {
MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter();
mappingJackson2HttpMessageConverter
.setObjectMapper(getNullAndEmptyFilteredObjectMapper());
return mappingJackson2HttpMessageConverter;
}
#Bean
public ObjectMapper getNullAndEmptyFilteredObjectMapper() {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
objectMapper.configure(
DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
return objectMapper;
}
When I debug the above code I came to know mapper include those \r\n in the response.Help me how to remove those slashes.
The problem is the line below.
mapper.writerWithDefaultPrettyPrinter().writeValue(writer,train);
Try replacing it with
mapper.writeValue(writer,train);
Why do you create a new object mapper when you are configuring, MappingJackson2HttpMessageConverter?
You can autowire the object mapper or return the actual object and let spring convert it to json
That's a "simple" double encoding issue i believe. You set a string in the response entity which is again writen as a json response.
If you want to rely on the spring view rendering (mappingjackson2httpmessageconverter) you have to create a response entity for "Train". (Or return a train instance directly from your controller method)
Or you use the way you implemented it and you have to ensure that rendering a string for a json response will not use the jackson message converter, but is left untouched by spring.

Categories

Resources