Following is how JSON string looks
{
"employee": {
"id": "c1654935-2602-4a0d-ad0f-ca1d514a8a5d",
"name": "smith"
...
}
}
Now i am using ObjectMapper#readValue(jsonAsStr,Employee.class) to convert it to JSON.
My Employee class is as follows...
#XmlRootElement(name="employee")
public class Employee implements Serializable {
private String id;
private String name;
...
public Employee() {
}
#XmlElement(name="id")
public String getId() {
return id;
}
public void setId(String id) {
this.id= id;
}
#XmlElement(name="name")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
...
}
The exception I am getting is
com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException:
Unrecognized field "employee" (class com.abc.Employee), not marked as
ignorable (12 known properties: , "id", "name", ... [truncated]])
I am not able to understand why "employee" is considered as a property. Am i wrong in assuming that only class members are considered as properties?
The problem is that a JSON Object { } maps to a Java class, and the properties in the JSON map to the Java properties. The first { } in your JSON (which you are trying to unmarshal to Employee), has a property employee, which Employee class does not have a property for. That's why you are getting the error. If you were to try and unmarshal only the enclosed { }
{
"id": "c1654935-2602-4a0d-ad0f-ca1d514a8a5d",
"name": "smith"
}
it would work as Employee has those properties. If you don't have control over the JSON, then you can configure the ObjectMapper to unwrap the root value
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.UNWRAP_ROOT_VALUE, true);
But the you might have another problem. The unwrapping is based on the annotation on the Employee class, either #JsonRootName("employee") or #XmlRootElement(name = "employee"). With the latter though, you need to make sure you have JAXB annotation support. For that, you need to have the jackson-module-jaxb-annotations, then register the module
mapper.registerModule(new JaxbAnnotationModule());
This applies for all your JAXB annotations you're using. Without this module, they won't work.
#peeskillet is right.
I was looking for a long time about how to use jax annotation to deserialize the json returned from server since I was getting UnrecognizedPropertyException as well.
Adding the following code fixed my problem:
mapper.registerModule(new JaxbAnnotationModule());
Follow below the entire code i used:
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JaxbAnnotationModule());
List<PojoTO>response = mapper.readValue(result.readEntity(String.class), mapper.getTypeFactory().constructCollectionType(List.class, PojoTO.class));
Related
I have a Json response that looks like this:
[
{ "name":"A" },
{ "name":"B" }
]
I have Java classes representing a single ResponseDto and contains a List of Person:
public class GetPersonsResponseDto {
public List<Person> persons;
}
public class Person {
public String name;
}
I would like to deserialize the by JSON using ObjectMapper but without use of a custom Deserializer and without collection type (no Persons[].class or TypeReference<List<Person>>(){}). What I really want is
ObjectMapper mapper = new ObjectMapper();
mapper.readValue(in, GetPersonsResponseDto.class);
But I get:
jackson.map.JsonMappingException:
Can not deserialize instance of com.project.my.GetPersonsResponseDto out of START_ARRAY token
I tried several Annotations but without success.
Actually it is quite simple to serialize your models to the target json, but might be tricky to deserialize.
So, the solution for deserialization in this case could be using #JsonCreator annotation from com.fasterxml.jackson.annotation package above constructor:
#Data
public class GetPersonsReponseDto {
public List<Person> persons;
#JsonCreator // use this annotation for deserialization on constructor
public GetPersonsReponseDto(List<Person> persons) {
this.persons = persons;
}
public GetPersonsReponseDto() {
}
}
However, it might not work with some versions of jackson.
I'm using the objectMapper to first serialise and deserialise an object.
I'm serialising the object here:
byte[] data = objectMapper.writeValueAsBytes(service.getServiceInfo());
client.create().withMode(CreateMode.EPHEMERAL).forPath(service.getLeaderPath(), data);
The getServiceInfo is of type: ServiceInfo.class
Here is how I'm trying to deserialise the data:
byte[] data = client.getData().forPath(service.getLeaderPath());
T serviceInfo = objectMapper.readValue(data, typeServiceInfo);
Here T is of type ServiceInfo.class and typeServiceInfo is it's class variable Class<T>
This is the ServiceInfo.class:
#Data
public class ServiceInfo {
private String name;
public ServiceInfo(String name) {
this.name = name;
}
}
Now when I run my code, I obtain a MismatchedInputException
This is the error trace I obtained:
com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of `com.nutanix.categories.beans.curator.ServiceInfo` (although at least one Creator exists): cannot deserialize from Object value (no delegate- or property-based Creator)
at [Source: (byte[])"{"name":"2816c308-5277-4b23-bdd6-64d6f3513e16"}"; line: 1, column: 2]
at com.fasterxml.jackson.databind.exc.MismatchedInputException.from(MismatchedInputException.java:63)
at com.fasterxml.jackson.databind.DeserializationContext.reportInputMismatch(DeserializationContext.java:1429)
at com.fasterxml.jackson.databind.DeserializationContext.handleMissingInstantiator(DeserializationContext.java:1059)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1297)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:326)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:159)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4202)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3266)
at com.nutanix.categories.curators.ServiceLeaderLatch.start(ServiceLeaderLatch.java:74)
What am I doing wrong here? Any help is deeply appreciated.
PS: Please mention if I have to submit additional information regarding my query in the comments
There are two ways to solve it:
Modify the ServiceInfo bean itself and remove the constructor. Although, it will require you to update all it's declarations.
#Data
public class ServiceInfo {
private String name;
}
Or, add #JsonCreator annotation to the bean
#Data
public class ServiceInfo {
private String name;
#JsonCreator
public ServiceInfo(#JsonProperty("name") String name) {
this.name = name;
}
}
If you don't like #JsonProperty annotation, you can customize ObjectMapper
<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-paranamer</artifactId>
<version>${some-version}</version>
</dependency>
And then register the module:
ObjectMapper mapper = new ObjectMapper();
mapper.registerModules(new ParanamerModule());
Another option is leave everything as it is and add a default constructor
#Data
public class ServiceInfo {
private String name;
public ServiceInfo() {
}
public ServiceInfo(String name) {
this.name = name;
}
}
I am using jackson-annotations 2.4 and related jars to covert from JSON to POJO. Let's say I have a structure as follows in my json:
person
{
name
{
firstName,
lastName
}
}
I have POJO for the person defined as:
#JsonIgnoreProperties(ignoreUnknown = true)
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonPropertyOrder({"name"})
class Person
{
private Name name;
#JsonProperty("name")
public Name getName()
{
return name;
}
#JsonProperty("name")
public void setName(Name name)
{
this.name = name;
}
}
Assume I've a similar POJO defined for Name. Now my question is can the getter for Name in Person ever return a null value or it gets instantiated behind the scenes?
I tried searching on google but it seemed like jackson returned default values for the non-nullable fields but there was no mention about what happens to the structure?
It will depend on the json you use to parse, i.e:
{
"name": {
"firstname": "abc",
"lastname": "xyz"
}
}
or
{
"name": {
}
}
Both JSONs above will never return null for person.getName(), even if the fields inside the node are missing. But on the other hand if you don't pass the node name on your json, then person.getName() will always return null. For instance, this JSON will always cause person.getName() to be null:
{
"name": "abc"
}
Try this . This will definitely work out. I was facing same got the solution by this.
#JsonInclude(JsonSerialize.Inclusion.NON_NULL)
or
#JsonInclude( JsonSerialize.Inclusion.NON_EMPTY)
you may also try by Remove this
#JsonPropertyOrder({"name"}) //remove this
I'm trying to build a JPA CriteriaQuery from a client-provided JSON filter; that is, to query this Person POJO:
#Entity
public class Person {
#Id
public Long id;
public String name;
public Date dateOfBirth;
}
a client would provide a JSON like this
{
"$or": [
{ "name": { "$beginsWith": "Jo" } },
{ "dateOfBirth": { "$lessThan": "1983-01-01T00:00:00Z" } }
]
}
When parsing this filter, I need to obtain the right Java type from the provided JSON values, e.g. a Date for dateOfBirth. Given that I can easily reach the JsonNode for "1983-01-01T00:00:00Z" and that Jackson's ObjectMapper knows somewhere what type to deserialize for the dateOfBirth field of Person.class, how can I get it? Ideally it would be something in the lines of:
// jsonNode is the JsonNode for "1983-01-01T00:00:00Z"
ObjectMapper mapper = new ObjectMapper();
ObjectReader reader = mapper.readerFor(Person.class);
Date date = (Date) reader.asField("dateOfBirth").readValue(jsonNode);
That asField() method would do the magic to return a reader which will read a JSON string as Java Date (or more generally the type that the ObjectMapper would resolve applying [de]serializers annotated for that field).
Note: I'm not asking how to parse dates with Jackson, but how to read a value and get the object Jackson would deserialize normally, but for a nested field.
My REST service returns following JSON
{
"name": "John",
"id" : 10
}
Can I use Jersey to marshall it into following Bean:
public class User{
private String name;
//getter & setter
}
I wanted to do this with following code but it doesn't work
WebResource webResource = client.resource(url);
webResource.accept(MediaType.APPLICATION_JSON_TYPE);
User user = webResource.get(User.class);
Is this even possible or I have to implement full JSON structure in Java Beans to get it work?
I know that I can parse this JSON with Jackson and any other methods.
With Jackson, easiest way is to configure ObjectMapper like so:
objectMapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES,
false);
Check this sample provider
package com.company.rest.jersey;
#Provider
#Component
#Produces({MediaType.APPLICATION_JSON})
public class JacksonMapperProvider implements ContextResolver<ObjectMapper> {
ObjectMapper mapper;
public JacksonMapperProvider(){
mapper = new ObjectMapper();
mapper.configure(Feature.INDENT_OUTPUT, true);
// Serialize dates using ISO8601 format
// Jackson uses timestamps by default, so use StdDateFormat to get ISO8601
mapper.getSerializationConfig().setDateFormat(new StdDateFormat());
// Deserialize dates using ISO8601 format
// MilliDateFormat simply adds milliseconds to string if missing so it will parse
mapper.getDeserializationConfig().setDateFormat(new MilliDateFormat());
// Prevent exceptions from being thrown for unknown properties
mapper.configure(
DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES,false);
}
#Override
public ObjectMapper getContext(Class<?> aClass) {
return mapper;
}
}
With Jackson :
You have two options:
Jackson works on setters-getters of fields. So, you can just remove getter of field which you want to omit in JSON. ( If you don't need getter at other place.)
Or, you can use the #JsonIgnore annotation of Jackson on getter method of that field and you see there in no such key-value pair in resulted JSON.
#JsonIgnore
public int getSecurityCode(){
return securityCode;
}
In your bean, add the annotation #JsonIgnoreProperties(ignoreUnknown = true) at the class level and it should skip the id property in the JSON since it's not present in the bean.
#JsonIgnoreProperties(ignoreUnknown = true)
public class User{
private String name;
//getter & setter
}
(See http://wiki.fasterxml.com/JacksonAnnotations for details)