Create a generic JSONPatch object - java

I want to create a DTO for Jackson to serialize my jsonPatch variables into a json patch variable.
I have this attributes to represent the class Person:
#JsonProperty("lastName")
private String lastName;
#JsonProperty("firstName")
private String firstName;
#JsonProperty("age")
private int age;
#JsonProperty("a")
private A classA;
And also the class A has:
#JsonProperty("colour")
private String colour;
#JsonProperty("quantity")
private BigDecimal quantity;
The DTO that I created was something like this:
#JsonProperty("path")
protected String path;
#JsonProperty("op")
protected String operation;
#JsonProperty("value")
protected Object values;
The json patch that I receive can have on the values class either a Person or the class A:
Patch for Person:
[
{
"value":
{
"lastName": "Doe",
"firsName": "John"
},
"path": /people",
"op": "replace"
}
]
Patch for A:
[
{
"value":
{
"quantity": 12.1,
},
"path": /A",
"op": "remove"
}
]
The value can be either a Person or a class A, as I told you, that's why the value is an Object class.
My problem is that when Jackson serializes the value from Person, it serializes to a Map, and when the value is from object A, it serializes to a double, which will lead to casting the values, which could be very dangerous.
Is there any way to tell Jackson that the values are from a Person object or from an A object, so it can serialize without any cast?

I would recommend creating a common class with all the properties and add JsonIgnoreProperties to the class so that Jackson will ignore unknown properties while deserializing
#JsonIgnoreProperties(ignoreUnknown = true)
class Common {
#JsonProperty("colour")
private String colour;
#JsonProperty("quantity")
private BigDecimal quantity;
#JsonProperty("lastName")
private String lastName;
#JsonProperty("firstName")
private String firstName;
#JsonProperty("age")
private int age;
#JsonProperty("a")
private A classA;
}
And then after deserializing the JSON to Common object just do null check to identify deserialized JSON is Person or A class
if(common.getFirstName()!=null && common.getLastName()!=null)
// Person class
if(common.getQuantity()!=null)
// A class

Related

Convert Java object with embedded objects to a JSON with list of attributes and list of values and vice versa

In my Spring project I have several objects that should be serialized to a specific JSON format.
public class Person {
private Integer id;
private String name;
private String height;
private Address address;
}
and
public class Address {
private String street;
private String city;
private String phone;
}
Let assume that Person.height and Address.phone should not appear in the JSON.
The resulting JSON should look like
{
"attributes": ["id", "name", "street", "city"],
"values": [12345, "Mr. Smith", "Main street", "Chicago"]
}
I can create create a standard JSON with an ObjectMapper and some annotations like #JsonProperty and #JsonUnwrapped where I disable some SerializationFeatures. But at the moment I'm not able to create such a JSON.
Is there an easy way to create this JSON? And how would the way back (deserialization) look like?
There are good reasons Jackson doesn't serializes maps in this format. It's less readable and also harder to deserialize properly.
But if you just create another POJO it's very easy to achieve what you want to do:
public class AttributeList {
public static AttributeList from(Object o) {
return from(new ObjectMapper().convertValue(o, new TypeReference<Map<String, Object>>() {}));
}
public static AttributeList from(Map<String, Object> attributes) {
return new AttributeList(attributes);
}
private final List<String> attributes;
private final List<Object> values;
private AttributeList(Map<String, Object> o) {
attributes = new ArrayList<>(o.keySet());
values = new ArrayList<>(o.values());
}
}

How to use #JsonUnwrapped in list of objects

I'm trying to deserialize a JSON object using Jackson annotation, but I can't deserialize it:
Is an array of a type "Deposito"
{
"depositos": [
{
"deposito": {
"id": "13168775373",
"nome": "Geral",
"saldo": "100000.0000000000",
"desconsiderar": "N",
"saldoVirtual": "100000.0000000000"
}
}
]
}
my java class:
#JsonUnwrapped
#JsonProperty(value ="depositos")
private List<Deposito> depositos;
my deposito class:
#JsonRootName(value = "deposito")
public class Deposito {
private String id;
private String nome;
private Double saldo;
private String desconsiderar;
private Double saldoVirtual;
}
You would need to add an additional class to your model:
public class DepositoMetadata {
private Deposito deposito;
}
Now you need to adjust your main java class (as you called it):
private List<DepositoMetadata> depositos;
Finally, you can remove #JsonRootName(value = "deposito") from your Deposito class.

How to deserialize complex JSON to java object

I need to deserialize JSON to java class.
I have JSON like the following:
{
"data": {
"text": "John"
},
"fields":[
{
"id": "testId",
"name": "fieldName",
"options": {
"color": "#000000",
"required": true
}
},
{
"id": "testId",
"name": "fieldName1",
"options": {
"color": "#000000",
"required": false
}
}
]
}
and I need to deserialize this JSON (only "fields" section) to java class like the following:
public class Field {
public final String id;
public final String name;
public final String color;
public final boolean required;
}
and I need to get something like the following:
// The key is the id from field object (it can be the same in the multiple objects.)
Map<String, List<Field>> fields = objectMapper.readValue(json, Map<String, List<Field>>);
How can I do it using Jackson?
As long as jackson doesn't support #JsonWrapped, you have to use the following work around.
First you need to create a custom class which contains the fields:
public class Fields {
public List<Field> fields;
}
Depending on your ObjectMapper configuration you have to add #JsonIgnoreProperties(ignoreUnknown = true) to the Fields class, to ignore any other properties.
Next is that you have to define the nested Options class which is solely used temporarily:
public class Options {
public String color;
public boolean required;
}
And at last add this constructor to your Field class:
#JsonCreator
public Field(#JsonProperty("id") String id, #JsonProperty("name") String name, #JsonProperty("options") Options options){
this.id = id;
this.name = name;
this.color = options.color;
this.required = options.required;
}
The #JsonCreator annotation indicates to jackson that this constructor needs to be used for the deserialization. Also the #JsonProperty annotations are required as arguments to constructors and methods are not preserved in the bytecode
Then you can deserialize your json just like this:
List<Field> fields = objectMapper.readValue(json, Fields.class).fields;

Get map from retrofit query

I have JSON that I get using retrofit
[{
"id":"1",
"name":"name",
"fields_json":{
"f1":"value1",
"f2":"value2",
"f3":"value3"
}
},{
"id":"2",
"name":"name2",
"fields_json":{
"f1":"value1",
"f2":"value2",
"f3":"value3"
}
}]
I want get List of Person(long id, String name, Map fields)
How I may get fields_json as Map in this class?
If you change your json a bit, so you can use special response classes
{"persons":[{id":"1","name":"name", ...} ] }
public class Response {
#SerializedName("persons")
#Expose
public ArrayList<Person> persones;
}
public class Person {
#SerializedName("id")
#Expose
public String id;
#SerializedName("name")
#Expose
public String name;
#SerializedName("fields_json")
#Expose
public FieldsJson fieldsJson;
}
public class FieldsJson {
#SerializedName("f1")
#Expose
public String f1;
#SerializedName("f2")
#Expose
public String f2;
#SerializedName("f3")
#Expose
public String f3;
}
and set this class as response
#POST("/url")
Call<Response> getPersones(
....
);
So, if you wish You can describe public fieldsJson as Map
Map<String, Object> fieldsJson
It cannot be added as a Map object.
Instead you need to create another java class that contains the f1-f3 variables.
Then add this new class as a variable with the name of fields_json to your current class.

Gson to POJO, how to read the inner JSON Objects as part of the same POJO?

I have a JSON like below and would like to convert it using Gson to one POJO.
I am trying to figure out how to basically cut down the inner nested objects like desc to be treated as part of the same Java object, instead of creating a new POJO named Desc.
Is there a way to do this with Serialized Names to look into nested JSON objects?
Thanks in advance!
JSON to be converted to POJO
{
'name': name,
'desc': {
'country': country,
'city': city,
'postal': postal,
'street': street,
'substreet': substreet,
'year': year,
'sqm': sqm
},
'owner': [owner],
'manager': [manager],
'lease': {
'leasee': [
{
'userId': leaseeId,
'start': leaseeStart,
'end': leaseeeEnd
}
],
'expire': leaseExpire,
'percentIncrease': leasePercentIncrease,
'dueDate': dueDate
},
'deposit': {
'bank': 'Sample Bank',
'description': 'This is a bank'
}
}
Custom POJO
public class Asset {
private String mId;
#SerializedName("name")
private String mName;
private String mCountry;
private String mCity;
private String mPostal;
private String mStreet;
private String mSubstreet;
private int mYear;
private int mSqm;
#SerializedName("owner")
private List<String> mOwners;
#SerializedName("manager")
private List<String> mManagers;
private List<Leasee> mLeasees;
private DateTime mLeaseExpiration;
private int mPercentIncrease;
private int mDueDate;
private String mDepositBank;
private String mDepositDescription;
}

Categories

Resources