Been trying to map a certain JSON string that I'm receiving from an REST API call, but so far I only got the following message.
Unrecognized field "my_first_field" (class MyClass), not marked as ignorable
I've been parsing the contents with IOUtils class, the following way (maybe the encoding is the root cause).
String json = IOUtils.toString(responseEntity.getContent(), UTF_8);
Once this has been done, I try to map the payload String to my POJO class using ObjectMapper.
new ObjectMapper().readValue(json, new TypeReference<MyClass>(){ })
However, while performing that step the exception mentioned in the beginning is prompt. The POJO class is the following.
public static class MyClass {
#JsonProperty("my_first_field")
private List<Map<String, String>> myFirstField;
#JsonProperty("my_second_field")
private String mySecondField;
public MyClass() { }
public MyClass(List<Map<String, String>> myFirstField, String mySecondField) {
this.myFirstField = myFirstField;
this.mySecondField = mySecondField;
}
(...)
}
Ignoring those unknown fields result in all POJO fields being null. What could be the problem in here?
EDIT: Sample JSON
{"my_second_field":"samplevalue", "my_first_field":[{"inner":"value"}]}
Make sure you import #JsonProperty annotation from fasterxml package, not from anywhere else.
Related
I have a simple POJO:
#Data
#Builder
#NoArgsConstructor
#AllArgsConstructor
public class StatusPojo {
private String status;
}
When I de-serialize simple string "asd" (without quotes) like this:
StatusPojo pojo = new ObjectMapper().readValue("asd", StatusPojo.class)
I am getting a StatusPojo object created successfully, with status field's value as "asd", though it is not valid JSON and nowhere has the field name "status" mentioned along.
Why is it behaving like this and how to disable this behavior and have object mapper throw an exception?
Your POJO has #AllArgsConstructor (maybe because of the #Builder) that then generates something like this:
public StatusPojo(String status) {
this.status = status;
}
When ObjectMapper then de-serializes plain string it uses that constructor to create object.
If you added some other property to your pojo, like just:
private String noAsdPlease;
there would be an exception, because ObjectMapper could not find creator, there would not be that above mentioned constructor but with two String params.
At quick glace DeserializationFeature does not have such a feature that disables using one string arg constructor for plain string.
Playing with more fields, removing #Builder & #AllArgsConstructor might resolve your problem but if you cannot change those ther might not be other options.
I have such JSON
{"body":{"result":[{"crossStateId":1,"raceId":181564,"withOfficer":1,"documents":[{"indexed":0,"documentNumber":"zzz","isMain":1,"documentTypeId":6,"serverId":16,"countryId":327,"useDate":"2017-02-07T19:31:51.000+0000","documentSubTypeId":6,"crossId":5018177,"documentId":44973231,"personId":222,"infinity":0,"documentValid":"2023-08-25T20:00:00.000+0000"}],"directionId":2,"documentNumber":"sss","operatorUsername":"AIRPORT_84","crossDate":"2017-02-07T19:31:51.000+0000","serverId":16,"crossTypeId":1,"crossRegisterDate":"2017-02-07T19:31:52.818+0000","officerNote":"","children":[],"personNote":"","crossId":5018177,"workplaceId":82,"divisionId":2,"race":{"carriageContainer":0,"raceId":181564,"raceStateId":1,"directionId":2,"creatorId":415,"countryId":327,"transportIdByType":605,"raceDateTime":"2017-02-07T19:20:58.000+0000","raceNumber":"841 sss sss","creatorUsername":"AIRPORT_8","divisionId":2,"transportTypeId":3,"createDate":"2017-02-07T19:20:58.000+0000"},"syncState":0,"autos":[],"userId":491,"raceNumber":"841 sss sss","operatorNote":"","person":{"firstNameEn":"JUMBERI","indexed":1,"lastNameGe":"ჩოხელი","genderId":2,"personId":6027803,"personalNumber":"222","countryNameGe":"sss","birthDate":"1963-06-14T20:00:00.000+0000","lastNameEn":"sss","countryId":327,"firstNameGe":"sss"},"airplane":{"raceNumber":"841 sss sss","airCompanyId":1,"airplaneId":605,"airportId":5657,"bortNumber":"01","transportSubTypeId":78,"countryId":360},"underAge":0,"personId":6027803,"decisionId":22}],"total":8264},"errorCode":0}
I would like to deserialize it to Java class but I am interested in only some JSON fields. Anyway here are the model classes:
public class Response implements Serializable {
private Body body;
private long errorCode;
}
public class Body implements Serializable {
Result result[];
}
public class Result implements Serializable {
private long crossStateId;
private long raceId;
private Person person;
private Child children [];
private Auto autos[];
}
etc.
But for some reason I get following exception:
org.codehaus.jackson.map.exc.UnrecognizedPropertyException:
Unrecognized field "body" (Class com.demo.Response), not marked as
ignorable at [Source: java.io.StringReader#6483f5ae; line: 1, column:
10] (through reference chain: com.demo.Response["body"])
Here is code(the JSON string is correctly received and has same format as I initially mentioned in the beginning):
String res = MainProgram.sendGet("someURL");
ObjectMapper objectMapper = new ObjectMapper();
Response ob = objectMapper.readValue(res, Response.class);
I would appreciate some help.
You need to create getters and setters for the fields, and you should add annotations to your fields.
Annotation:
#JsonProperty(value = "body")
private Body body;
Doing one of above will make it work.
Sidenote:
You can create your pojos from json automatically with http://www.jsonschema2pojo.org/. Just paste it in and download it, or use one of their plugins.
As mentioned by others, private fields are not auto-detect by default, so either:
Annotating fields with #JsonProperty OR
Adding setter
is needed for deserialization.
However, there is another possibility: you can use annotations #JsonAutoDetect to change minimum visibility needed, and here enable discovery of ALL fields.
Or you can even change the defaults used via ObjectMapper method (something like setVisibility(...)).
I have been searching all day for something that answers this, but I have not had a lot of luck thus far.
My question is straightforward: how do I deserialize an anonymous object correctly using Jackson.
private interface Interface1
{
int getValue();
}
public static void testAnonymousObject() throws IOException
{
ObjectMapper mapper = new ObjectMapper();
mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
mapper.setVisibility(PropertyAccessor.ALL, Visibility.NONE);
mapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);
mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
Interface1 testObject = new Interface1()
{
private final int value = 5;
#Override
public int getValue()
{
return value;
}
};
String json = mapper.writeValueAsString(testObject);
System.out.println("JSON = " + json);
Interface1 received = (Interface1) mapper.readValue(json, Object.class);
System.out.println(received);
}
The output of this is: JSON = ["com.foo.test.JacksonTest$1",{"value":5}] before I get an exception:
Exception in thread "main" com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize Class com.foo.test.JacksonTest$1 (of type local/anonymous) as a Bean.
EDIT Just to clarify, both Jackson and XStream are able to serialize the object. But only XStream seems to be able to deserialize the object back. So this scenario can be made to work.
As of the time I am writing this, it seems that Jackson does not serialize inner classes or anonymous classes correctly. Other packages such as XStream and Kryo, do however.
Because inner classes do not have a default zero argument constructor (they have a hidden reference to the outer/parent class) Jackson cannot instantiate them.
you can check this link
Problem is not just about it being an inner class (which may or may not be problematic, depending on whether implementation is static or non-static), but also in that no type information is included -- all Jackson sees is type Interface1. To enable reading it back it is necessary to either include type information ("polymorphic type handling"), or to specify mapping between abstract type and implementation class.
Given that you are using an anonymous inner class, you would be able to support this usage by enabled so-called "default typing" (see ObjectMapper javadocs for enableDefaultTyping() or such).
But you may also need to implement specific strategy, if you do not want to enable type inclusion for all non-final types.
To see whether type id is included you can enable default typing with one of default options and have a look at JSON being produced: there should be an additional type id ("#class" property when class name is used as id).
A ready-to-use code-snippet for a generic JSON-deserialization to a Java POJO with Jackson using nested classes:
static class MyJSON {
private Map<String, Object> content = new HashMap<>();
#JsonAnySetter
public void setContent(String key, Object value) {
content.put(key, value);
}
}
String json = "{\"City\":\"Prague\"}";
try {
MyPOJO myPOJO = objectMapper.readValue(json, MyPOJO.class);
String jsonAttVal = myPOJO.content.get("City").toString();
System.out.println(jsonAttVal);
} catch (IOException e) {
e.printStackTrace();
}
#JsonAnySetter ensures a generic JSON-parsing and population.
Jersey by default convert single element returned to object . But the client side is expecting the data in json to be arraylist
Model class is LocationDetails
public class LocationDetails {
private String locationAccount;
private String locationName;
private String locationStreet;
private String locationPostcode;
}
other class LocationData which has arraylist of LocationDetails as
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class LocationData {
private ArrayList<LocationDetails> Locations;
}
and the controller class is using the following code to convert to JSON:
//Getting location and item along with barcodes
#POST
#Path("/getLocationAndItemData")
#Produces(MediaType.APPLICATION_JSON)
public LocationResponse getAlllocations(){
ArrayList<LocationDetails> locationDetailList = new ArrayList<LocationDetails>();
LocationDetails details = new LocationDetails();
//setting location account
details.setLocationAccount("10125");
locationDetailList.add(details);
}
The following code is returning json as LocationData : {LocationDetails : {"LocationAccount","10125"}}
whereas i want it to be like :
LocationData : {LocationDetails : [{"LocationAccount","10125"}]}
as the client side would expect the data to be inside list.
How to convert the type without changing the whole logic.I am using jersey.
Add #XmlElementWrapper annotation to your List, that should do the trick. If you have further problems with Jersey, try first XML output to see what is being produced. If XML is ok, JSON will be too.
#XmlElement(name="locationDetail")
#XmlElementWrapper(name="locationDetails")
private List<LocationDetail> locationDetails;
Also name your class properties with first lowercase letter, please.
I too had the same issue, after so many research i found that the problem is due to the jar files imported in the MyEclipse (Persisted container). I have removed that. The same code works for me.
The json format will be [{single element}].
I have this specific problem with JSON deserialization. Let's have this JSON structure:
{
"header":{
"objects":[
{"field":"value1"},
{"field":"value2"}
]
}
}
The JSON structure can't be altered as it comes from a 3rd party system.
Now let's have this simple POJO:
#JsonDeserialize(using=PojoDeserializer.class)
public class Pojo {
private string field;
//...getter, setter
}
The mentioned PojoDeserializer takes {"field": "value"} json string and deserializes it to the Pojo instance. So I can simply do the deserialization like this
Pojo instance = new
ObjectMapper().readValue("{\"field\":
\"value\"}", Pojo.class);
And here's my problem. Let's have another deserializer PojosCollectionDeserializer which takes the mentioned structure and deserializes it to a Collection of Pojo instances. I'd like to use it in a similar fashion as in the previous example:
Collection<Pojo> pojos = new ObjectMapper().readValue("{...}", Collection.class);
But this doesn't work as there is not defined that Collection should be created using the PojosCollectionDeserializer. Is there any way to achieve it?
I am not sure why are trying to explicitly specify deserializers, as it would all work just fine with something like:
public class Message {
public Header header; // or, if you prefer, getter and setter
}
public class Header {
public List<Pojo> objects;
}
public class Pojo {
public String field;
}
Message msg = objectMapper.readValue(json, Message.class);
without any additional configuration or annotations. There is no need to construct custom serializers or deserializers for simple cases like this.