JSON array to List of objects: UnrecognizedPropertyException - java

I couldn't find where I was wrong for the following array json string. I am not sure whether I am mapping right. I hope a friend will help me.
Thanks...
JSON string value is like below;
[
{
"PaymentRequest": {
"RequestGuid": 123
...
}
},{
"PaymentRequest": {
"RequestGuid": 456
...
}
}
]
Object definition is like below;
#JsonRootName(value = "PaymentRequest")
#JsonIgnoreProperties(ignoreUnknown = true)
public class PaymentRequest{
#JsonProperty("RequestGuid")
String requestGuid;
...
}
My wrapper class is like below;
public class MyWrapper{
PaymentRequest paymentRequest;
//setter getter
}
My implementation is like below.
ObjectMapper mapper = new ObjectMapper();
List<MyWrapper> users = mapper.readValue(jsonString, new TypeReference<List<MyWrapper>>() {});
Result:
com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "PaymentRequest" (class vpos.dto.MyWrapper), not marked as ignorable (one known property: "paymentRequest"])
at [Source: (StringReader); line: 3, column: 24] (through reference chain: java.util.ArrayList[0]->vpos.dto.MyWrapper["PaymentRequest"])

Problem is that property in json is called PaymentRequest and your field is paymentRequest with lower p at the begining. You can add annotation #JsonProperty("PaymentRequest") to your field or change property naming strategy like this:
ObjectMapper mapper = new ObjectMapper();
mapper.setPropertyNamingStrategy(PropertyNamingStrategy.UPPER_CAMEL_CASE);

Related

Unrecognized field during deserialization despite #SerializedName annotation

I am fetching some data via a REST service, but I am getting this error when deserializing the response :
com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "ResultSet Output" (class com.HolderCollectionWrapper), not marked as ignorable (one known property: "holders"]) at [Source: java.io.ByteArrayInputStream#74efa7bd; line: 1, column: 22] (through reference chain: com.HolderCollectionWrapper["ResultSet Output"])
This is my code :
response = restTemplate.exchange(requestUrl, HttpMethod.GET, request, HolderCollectionWrapper.class);
public class HolderCollectionWrapper {
#SerializedName("ResultSet Output")
private List<Holder> holders;
public List<Holder> getHolders() {
return holders;
}
public void setHolders(List<Holder> holders) {
this.holders = holders;
}
}
This is the JSON I am getting :
{
"ResultSet Output": [
{...}, {...}, {...}
]
}
Despite the #SerializedName("ResultSet Output"), it's not working, why ?
#SerializedName is a gson annotation and you are using jackson library for serialization.
The jackson annotation for field name is #JsonProperty
Try:
#JsonProperty("ResultSet Output")
private List<Holder> holders;
This happens because the SerializedName("ResultSet Output") gson annotation indicates that the holders will be serialized with the ResultSet Output name like the json example you post; to deserialize it with jackson you have to use the JsonProperty annotation, specifying the ResultSet Output name applied on the setter to avoid possible conflicts with the gson library used for serialization:
public class HolderCollectionWrapper {
#SerializedName("ResultSet Output")
private List<Holder> holders;
public List<Holder> getHolders() {
return holders;
}
#JsonProperty("ResultSet Output")
public void setHolders(List<Holder> holders) {
this.holders = holders;
}
}

Default value in POJO field incase of data type mismatch during JSON deserialization

When we deserialize JSON into POJO, JACKSON throws a Mismatch Input exception in case of data type mismatch, which is expected.
So my question is, "Is there any feature flag available in Jackson or Gson, to set the default value for mismatched field during deserialization?"
I understand that we can implement the custom deserializer for such fields, where random input value can be expected.
But is this already supported using some flag in any serialization deserialization java library?
Sample Code:
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Data;
import java.io.IOException;
public class JsonSample {
#Data
static class Address {
String houseAddress;
}
#Data
static class InnerJsonClass {
Integer integerField;
Address address;
}
public static void main(String[] args) {
String jsonInput = "{\"integerField\": 1,\"address\":\"hello\"}";
try {
ObjectMapper objectMapper = new ObjectMapper();
InnerJsonClass object = objectMapper.readValue(jsonInput, InnerJsonClass.class);
System.out.println(object.toString());
} catch (IOException e) {
e.printStackTrace();
}
}}
Exception:
com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of com.paytm.logistics.JsonSample$Address (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('hello')
at [Source: (String)"{"integerField": 1,"address":"hello"}"; line: 1, column: 30] (through reference chain: com.paytm.logistics.JsonSample$InnerJsonClass["address"])
at com.fasterxml.jackson.databind.exc.MismatchedInputException.from(MismatchedInputException.java:63)
at com.fasterxml.jackson.databind.DeserializationContext.reportInputMismatch(DeserializationContext.java:1342)
at com.fasterxml.jackson.databind.DeserializationContext.handleMissingInstantiator(DeserializationContext.java:1031)
at com.fasterxml.jackson.databind.deser.ValueInstantiator._createFromStringFallbacks(ValueInstantiator.java:371)
at com.fasterxml.jackson.databind.deser.std.StdValueInstantiator.createFromString(StdValueInstantiator.java:323)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromString(BeanDeserializerBase.java:1366)
at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeOther(BeanDeserializer.java:171)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:161)
at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:127)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:288)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:151)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4001)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2992)
at com.paytm.logistics.JsonSample.main(JsonSample.java:25)
Address is a object, not a String.
String jsonInput = "{\"integerField\": 1,\"address\":{\"houseAddress\": \"hello\"}}";
Try this
Your jsoninput is not in correct format it should be like below:
objectMapper will only convert value in specified object when json and pojo declaration mapping are same.
String jsonInput = "{\"integerField\": 1,\"address\":{\"houseAddress\": \"hello\"}}";
or if you don't want to change string json then you have to use code like below
#Data
static class InnerJsonClass {
Integer integerField;
String address;
}

How to ignore "handler": {}, "hibernateLazyInitializer": {} in json jackson in Spring hibernate project?

I am using fasterxml json with object mapper and below is my code:
ObjectMapper mapper = new ObjectMapper();
mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
try {
String jsonInString = mapper.writeValueAsString(myClassObjectHere);
return new ResponseEntity<String>(jsonInString, HttpStatus.OK);
} catch (JsonProcessingException e) {
e.printStackTrace();
return new ResponseEntity<String>(HttpStatus.INTERNAL_SERVER_ERROR);
}
The way I have implemented and am using the code, i get desired output but json has 2 random strange values in certain json objects as follows:
{
"listing": {
"listingId": 1,
"name": "Business",
"handler": {},
"hibernateLazyInitializer": {}
},
"handler": {},
"hibernateLazyInitializer": {}
},
How to configure objectmappper to ignore "handler": {}, "hibernateLazyInitializer": {} values from outputted json ?
I tried solutions below:
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
But its not working and the output is still the same as i posted above.
Also, I know I can ignore these handler and hibernateLazyInitializer in json by annotating classes with #JsonIgnoreProperties({"hibernateLazyInitializer", "handler"}) but is there any way to globally configure json jackson object mapper so that it never adds these values in my outputted json?
You could try adding a mixin to Object.class:
public ObjectMapper getObjectMapper() {
ObjectMapper mapper = new ObjectMapper();
mapper.addMixIn(Object.class, IgnoreHibernatePropertiesInJackson.class);
return mapper;
}
#JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
private abstract class IgnoreHibernatePropertiesInJackson{ }
I just ran into the same problem and found a way to globally get hibernate entities mapped correctly by adding the Hibernate4Module to the mapper:
objectMapper.registerModule(
new Hibernate4Module().configure(
Hibernate4Module.Feature.FORCE_LAZY_LOADING, true));
Seems like "handler": {}, "hibernateLazyInitializer": {} properties seems to be empty or null. You can use the following configuration to ignore empty or null properties.
mapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
Or if you have access to the Class annotate handler and hibernateLazyInitializer with #JsonIgnore this will prevent it from being Serialized globally.
Adding Annotation over the class #JsonIgnoreProperties(value = {"hibernateLazyInitializer", "handler"}) worked for me.

UnrecognizedPropertyException from jackson when reading data produced by jersey-json

I have this JAXB-annotated class:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement
public class SomeClass {
#XmlAttribute
public String value;
}
Based on this class, a JSON document was produced using jersey-json (via com.sun.jersey.api.json.JSONJAXBContext):
{
"#value":"someValue"
}
Note that jersey decided to use #value as tag name (and not simply value), probably in order to honour the #XmlAttribute annotation.
Now the task is to read this json document using jackson-json and produce an instance of the JAXB annotated class:
ObjectMapper mapper = new ObjectMapper();
JaxbAnnotationIntrospector introspector = new JaxbAnnotationIntrospector(mapper.getTypeFactory());
DeserializationConfig deserConfig = mapper.getDeserializationConfig().with(introspector);
mapper.setConfig(deserConfig);
SerializationConfig serConfig = mapper.getSerializationConfig().with(introspector);
mapper.setConfig(serConfig);
mapper.readValue(jsonFile, SomeClass.class);
This fails with the following exception:
Caused by: com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "#value" (class test.jersey.vs.jackson.SomeClass), not marked as ignorable (one known property: "value"])
at [Source: C:\Users\AppData\Local\Temp\junit5080915042527904512\json.txt; line: 1, column: 12] (through reference chain: test.jersey.vs.jackson.SomeClass["#value"])
at com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException.from(UnrecognizedPropertyException.java:62)
at com.fasterxml.jackson.databind.DeserializationContext.handleUnknownProperty(DeserializationContext.java:834)
at com.fasterxml.jackson.databind.deser.std.StdDeserializer.handleUnknownProperty(StdDeserializer.java:1093)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.handleUnknownProperty(BeanDeserializerBase.java:1477)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.handleUnknownVanilla(BeanDeserializerBase.java:1455)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:282)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:140)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3798)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2740)
My question now is whether there is a way to tell jackson to associate the #value tag from the JSON document with the value field of the class.
I tried specifying a PropertyNamingStrategy, but that was never called during deserialization.
PropertyNamingStrategy pns = new PropertyNamingStrategy() {
#Override
public String nameForField(MapperConfig<?> config, AnnotatedField field, String defaultName) {
if (field.hasAnnotation(XmlAttribute.class)) {
if (defaultName.startsWith("#")) {
return defaultName.substring(1);
}
}
return super.nameForField(config, field, defaultName);
}
};
DeserializationConfig deserConfig = mapper.getDeserializationConfig().with(introspector).with(pns);
mapper.setConfig(deserConfig);

can't deserialize an Object to its original Type using jackson #JsonTypeInfo annotation

im Trying to serialize an object ( from an Enum ) in the client-side of my application and deserialize it in the other side ( server-side ) to the same Object using jackson . i have this enum in my client-side :
#JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "#type")
public enum Request{
Signup,
Login
}
which using the #jsonTypeInfo annotaion of jackson .
and on the server-side im doing this to deserialize the object :
ObjectMapper mapper = new ObjectMapper();
final JsonNode jsonNode;
jsonNode = mapper.readTree(json); //json is the return String from the convertObjectToJson(Request.Signup);
//i get the error on this line
String type = jsonNode.get("#type").asText();
as i've commented in the code above im getting the NullException on the jsonNode.get("#type").asText() while the json is : [ "Request", "Signup" ]
and this is the function that serialize the objects :
public static String convertObjectToJson(Object object) throws IOException {
ObjectWriter objectWriter = new ObjectMapper().writer().withDefaultPrettyPrinter();
String json = objectWriter.writeValueAsString(object);
return json;
}
where is the problem ?
Jackson by default will represent java enums as simple strings and for that reason you are unable to deserialize the object
Take a look here, it could help: http://www.baeldung.com/jackson-serialize-enums

Categories