i define this class
public class PostServerActionsRequest {
private ChangePassword changePassword;
private Reboot reboot;
private Rebuild rebuild;
private Resize resize;
private String confirmResize;
private String revertResize;
private CreateImage createImage;
//constructor + getter & setter
}
that i used to parse multiple json requests using jackson json processor. The situation is the following: i receive a json with this structure:
//Json A
{
"reboot": {
"type": "SOFT"
}
}
where i define class Reboot with a private String attribute whose name is type. Obviously the attributes that haven't the relative equivalent in json are set to null by jackson during deserialization. So serializing i obtain this json:
//Json B
{
"changePassword": null,
"reboot": {
"type": "SOFT"
},
"rebuild": null,
"resize": null,
"confirmResize": null,
"revertResize": null,
"createImage": null
}
Now i know how tell jackson to ignore null or empty values during serialization, for example with the annotation #JsonSerialize(include=JsonSerialize.Inclusion.NON_DEFAULT) above the class PostServerActionsRequest, but my question is, it's possible to tell jackson to don't set to null values that are not in json request (json A) during deserialization? This because i want to obtain a class has only the values present in the json request.
I hope i was clear to explain my issue and thanks you in advance for your help.
it's possible to tell jackson to don't set to null values that are not in json request (json A) during deserialization?
No, it is not possible.
Indeed, what you are asking doesn't make any sense. When you create a PostServerActionsRequest, by deserializing from JSON, or by any other means, each of the fields in the PostServerActionsRequest instance has to have a value.
It is simply meaningless to talk about a field of a Java object as having "no value" ... in the sense you are talking about. For fields that are reference typed, the value has to be either a reference to some object ... or null. There are simply no alternatives.
Related
In Java, using Jackson, I want to deserialize JSON that looks something like this:
{
"123_ABC": {
"XYZ": 768,
"123_DATA": {
"123_DEF": "",
"123_ACT": "ZAC",
"123_PAG": {
"123_PAG_A": 1,
"123_PAG_B": 1
}
}
}
}
You all know that identifiers starting with a number are invalid in Java (and every programming language I ever heard of.)
I already know how to use #JsonProperty to translate field names, but handling class names is outside my knowledge.
If I define classes corresponding to the structure of the JSON, but with valid class names, is there a way to use Jackson annotations to map the invalid class id in the JSON to my valid class names?
I think #JsonProperty should be good to deserialize this.
Let's create a wrapper class that will have 123_ABC as a property of class ValidClass.
class Wrapper {
#JsonProperty("123_ABC")
private ValidClass validName;
}
Now, when you serialize, it will create JSON like this (or can be deserialized using that)
{ "123_ABC":{ //PROPERTIES OF ValidClass HERE } }
Similarly, you can have different properties in further inner classes.
In case if you to support 123_ABC only for deserialization and serialize with correct field names, you can do like this
#JsonAlias("123_ABC")
private ValidClass validName;
it will serialize to following.
{"validName": {//properties}}
but deserialization can be done using both
{"validName": {//properties}}
{"123_ABC": {//properties}}
In case, if keys keep changing, I would suggest to deserialize them in Map.
I want to deserialize an object which is annotated with #JsonRootName. However the JSON in which the object is transported contains another extra property. As a result Jackson is complaining with:
com.fasterxml.jackson.databind.exc.MismatchedInputException: Unexpected token (FIELD_NAME), expected END_OBJECT: Current token not END_OBJECT (to match wrapper object with root name 'account'), but FIELD_NAME at [Source: (ByteArrayInputStream); line: 1, column: 26].
Apparently deserialization of #JsonRootName annotated objects works ONLY if that object is the sole property in JSON file - since it's not expecting the "lastTransactionID" to be there.
Here's my Account class:
#JsonRootName("account")
public class Account {
private String id;
}
This is the JSON I need to deserialise:
{
"account": {
"id": "1234"
},
"lastTransactionID": "1"
}
Since I'm using spring I have this setup also spring.jackson.deserialization.unwrap_root_value=true.
Is there any way to solve this without:
having to write a custom deserializer?
OR
intercepting the response and stripping it of the extra property before deserialization takes place?
It looks like simplest way to solve this issue is create wrapper for Account class and deserialise json as usual with disabled DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES feature.
public static class Wrapper {
public Account account;
}
In this case other fields will be ignored.
It's not a nice solution, I know, but it solve a problem.
We can use ObjectMapper to Map json to java Objects.
public Account jsonToObject(Map<String, Object> map){
ObjectMapper objectMapper = new ObjectMapper();
Account account = objectMapper.convertvalue(map.get("account"),Account.class);
return account;
}
You can use JsonIgnoreProperties(ignoreUnknown=true) annotation on your Account class. Please refer below link for more details.
https://www.thetechnojournals.com/2019/10/entity-object-conversion-to-dto-object.html
I am having troubles when JSON is being deserialized using Jackson.
The problem is when the JSON is deserialized and whatever JSON property is changed by DEV, I still need to get it deserialized into an object.
Here is the part of variables in the object
#JsonProperty("accountingFiscalYear")
public String accountingFiscalYear;
#JsonProperty("amount")
public Float amount;
#JsonProperty("debitFlag")
public Boolean debitFlag;
and here is the JSON part
"accountingFiscalYear": "2017",
"amount": 1632.0000,
"debitFlag": true,
When it runs it is deserialized without any problems. But if there is any change in the JSON response it fails during the deserialization like:
For example if I change the debitFlag data type from Boolean to Integer
com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of int out of VALUE_TRUE token
I know it is right, but I would like to continue with deserialization and simply ignore types that could not be deserialized and keep them null.
Thanks for hints.
I have a large nested object. I want to serialise this object in the JSON string, however I need only certain fields to be included. Problem here is that fields could change very frequently and I want to build it in a way that could help me easy include or exclude fields for serialisation.
I know that I can write a lot of code to extract certain fields and build JSON "manually". But I wonder if there are any other elegant way to achieve similar outcome but specifying a list of required fields?
For example having following object structure I want include only id and name in the response:
class Building {
private List<Flat> flats;
}
class Flat {
private Integer id;
private Person owner;
}
class Person {
private String name;
private String surname;
}
Json:
{
"flats" : [
{
"flat":
{
"id" : "1",
"person" : {
"name" : "John"
}
}
}
]
}
You can use gson for serializing/deserializing JSON.
Then you can include the #Expose annotation to use only the fields you require.
Be sure to also configure your Gson object to only serialize "exposed" fields.
Gson gson = GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
Alternative:
You can actually do it the inverse way, marking fields which will not be exposed. You can do this with the transient keyword.
So whatever you want to ignore just add transient to it. Here's how it works on gson.
PS: This works on most Java JSON serializers too.
Using com.fasterxml.jackson.annotation.JsonIgnore is another way to achieve this.
import com.fasterxml.jackson.annotation.JsonIgnore;
class Person {
private String name;
#JsonIgnore
private String surname;
}
It will ignore the surname when the parser converts the bean to json.
Similar annotation will be available in other json processing libraries.
If using Gson, study how to use ExclusionStrategy & JsonSerializer.
Using those is a more flexible way to control serialization since it allows to decide per serialization what to serialize.
Using annotations requires later to add / remove those annotations from fields if there is a need to change what to serialize.
In the case of your example the latter might be more appropriate.
This question might be good startpoint
serialize-java-object-with-gson
I'm having problems mapping an object using Jackson.
The issue happens when I map a JSON object that sometimes is missing an item from the class.
I'm trying to find out how to set up the configurations in order to not crash when the JSON does not have all the fields of the class.
I've already tried with:
MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
#JsonIgnoreProperties(ignoreUnknown = true)
This is the error:
com.fasterxml.jackson.databind.JsonMappingException: Instantiation of [simple type, class com.non.real.package.Like] value failed: null (through reference chain: com.non.real.package.CardFeed["likes"]->com.non.real.package.CardLikes["likes"]->java.util.ArrayList[0])
"likes": {
"count": 0,
"likes": []
}
Trying different solutions I've found out that the Like object is extending the class Model of ActiveAndroid. Removing that "extension" and it works fine. I think the Model class does not work fine when it has a NULL or EMPTY.
For Jackson you could try changing the mapper's configuration directly:
mapper.setSerializationInclusion(Include.NON_NULL);
But may I suggest you look at another library to map JSON to POJO? Both GSON and Genson (my personal favorite) do the same, but much faster, and much easier. Take a look at the benchmarks here, where they compare the (de)serialization of Jackson, GSON and Genson.
With Genson, it's very easy to skip null values:
private static final Genson gensonSkipNulls = new Genson.Builder().setSkipNull(true).create();
/**
* Deserializes JSON into a Java object.
*
* #param json The JSON to deserialize.
* #param superclass The model to deserialize the JSON into.
* #return An object that is an instanceof superclass.
*/
public Object deserialize(final String json, final Class superclass) {
return genson.deserialize(json, superclass);
}