json serialization with a variable field as a string - java

I have a pojo that I am unmarshalling a REST response to. One of the fields ("variable value") is just a Json variable element (can be any form).
Is there a way to tell it to treat the field as a plain string for all cases instead of trying to deserialize to an object?
Here's a json obiect ("variable value" can be any form):
{"id":1, "variable value": {"name":"one", "age": 22, "data":{"key":"value"}}}
I would like to save this json as a class object using gson
public class SomeCommand {
private Long id;
private String data;
}

It sounds that you would like to parse the given JSON string to transform variable value into String object. You can achieve this by creating 2 classes - SomeCommandOriginal and SomeCommand as follows:
First, convert the JSON string to SomeCommandOriginal to map the value of variable value to JsonNode.
class SomeCommandOriginal {
private Long id;
#JsonProperty("variable value")
private JsonNode variableValue;
//general getters and setters
}
class SomeCommand {
private Long id;
private String data;
public SomeCommand(SomeCommandOriginal someCommandOriginal) {
super();
this.id = someCommandOriginal.id;
this.data = someCommandOriginal.variableValue.toString();
}
//general getters and setters
}
Second, initialize an instance of SomeCommand and pass someCommandOriginal as the argument of customized constructor:
ObjectMapper mapper = new ObjectMapper();
SomeCommandOriginal someCommandOriginal = mapper.readValue(jsonStr, SomeCommandOriginal.class);
SomeCommand someCommand = new SomeCommand(someCommandOriginal);
System.out.println(someCommand.getData());
Console output:
{"name":"one", "age": 22, "data":{"key":"value"}}
UPDATED
If you are using Gson, just modify the datatype of variableValue to be JsonObject and switch to #SerializedName annotation as follows:
class SomeCommandOriginal {
private Long id;
#SerializedName("variable value")
private JsonObject variableValue;
//general getters and setters
}
And then you can get the same result as well:
Gson gson = new Gson();
SomeCommandOriginal someCommandOriginal = gson.fromJson(jsonStr, SomeCommandOriginal.class);
SomeCommand someCommand = new SomeCommand(someCommandOriginal);
System.out.println(someCommand.getData());

Related

Parse json using ObjectMapper where json key contains json as a value

I have a class with such structure:
class SomeClass {
private String stringValue;
private Collection<String> collectionValue = new ArrayList<>();
private String jsonStringValue;
private boolean booleanValue;
}
And then I use
objectMapper.readValue(jsonString, SomeClass.class);
to parse this object from JSON.
The main problem is that jsonStringValue is a json inside of json:
{"stringValue" : "someString",
"collectionValue" : ["123456", "234567", "hello"],
"jsonStringValue" : "{
"someKey" : 1,
"anotherKey" : {
"againKey" : "value"
}
},
"booleanValue" : true
}
And trying to parse jsonStringValue it throws
com.fasterxml.jackson.core.JsonParseException: Unexpected character ('a' (code 97)): was expecting comma to separate Object entries
Exactly "a" character from my example (json modified on security purposes)
I believe there should be some escaping rule for parsing json as a String.
How do I parse json value as a string?
First, your JSON string is not valid because there is a redundant double quote before the left bracket in jsonStringValue. The valid one looks like this:
{
"stringValue" : "someString",
"collectionValue" : ["123456", "234567", "hello"],
"jsonStringValue" : {
"someKey" : 1,
"anotherKey" : {
"againKey" : "value"
}
},
"booleanValue" : true
}
Second, jsonStringValue is not a simple String object, it is a nested JSON objects. Therefore, you are supposed to create corresponding classes for it as follows:
Class SomeClass {
private String stringValue;
private List<String> collectionValue = new ArrayList<>();
private JsonStringValue jsonStringValue;
private boolean booleanValue;
//general getters and setters
}
Class JsonStringValue {
private int someKey;
private AnotherKey anotherKey;
//general getters and setters
}
Class AnotherKey {
private String againKey;
//general getters and setters
}
At last, the given JSON string can be transformed into SomeClass POJO with ObjectMapper.
ObjectMapper mapper = new ObjectMapper();
SomeClass someClass = mapper.readValue(jsonStr, SomeClass.class);
System.out.println(someClass.getjsonStringValue().getAnotherKey().getAgainKey());
Console output:
value
UPDATED
If you still want to transform the jsonStringValue object into String, an alternative way is shown as follows:
Create 2 classes - SomeClassOriginal and SomeClass, the only difference between them is the data type of jsonStringValue. The former one is JsonNode and later one is String.
Class SomeClassOriginal {
private String stringValue;
private List<String> collectionValue = new ArrayList<>();
private JsonNode jsonStringValue;
private boolean booleanValue;
//general getters and setters
}
Class SomeClass {
private String stringValue;
private List<String> collectionValue = new ArrayList<>();
private String jsonStringValue;
private boolean booleanValue;
public SomeClass(SomeClassOriginal someClassOriginal) {
super();
this.stringValue = someClassOriginal.stringValue;
this.collectionValue = someClassOriginal.collectionValue ;
this.jsonStringValue= someClassOriginal.jsonStringValue.toString();
this.booleanValue= someClassOriginal.booleanValue;
}
//general getters and setters
}
Then you can get the jsonStringValue as String like this:
ObjectMapper mapper = new ObjectMapper();
SomeClassOriginal someClassOriginal = mapper.readValue(jsonStr, SomeClassOriginal.class);
SomeClass someClass = new SomeClass(SomeClassOriginal);
System.out.println(someClass.getjsonStringValue());
Console output:
{"someKey":1,"anotherKey":{"againKey":"value"}}

change field name to lowercase while deserializing POJO to JSON using GSON?

I have a POJO class like this. I am deserializing my JSON to below POJO first..
public class Segment implements Serializable {
#SerializedName("Segment_ID")
#Expose
private String segmentID;
#SerializedName("Status")
#Expose
private String status;
#SerializedName("DateTime")
#Expose
private String dateTime;
private final static long serialVersionUID = -1607283459113364249L;
...
...
...
// constructors
// setters
// getters
// toString method
}
Now I am serializing my POJO to a JSON like this using Gson and it works fine:
Gson gson = new GsonBuilder().create();
String json = gson.toJson(user.getSegments());
System.out.println(json);
I get my json printed like this which is good:
[{"Segment_ID":"543211","Status":"1","DateTime":"TueDec2618:47:09UTC2017"},{"Segment_ID":"9998877","Status":"1","DateTime":"TueDec2618:47:09UTC2017"},{"Segment_ID":"121332121","Status":"1","DateTime":"TueDec2618:47:09UTC2017"}]
Now is there any way I can convert "Segment_ID" to all lowercase while deserializing? I mean "Segment_ID" should be "segment_id" and "Status" should be "status". Is this possible to do using gson? So it should print like this instead.
[{"segment_id":"543211","status":"1","datetime":"TueDec2618:47:09UTC2017"},{"segment_id":"9998877","status":"1","datetime":"TueDec2618:47:09UTC2017"},{"segment_id":"121332121","status":"1","datetime":"TueDec2618:47:09UTC2017"}]
if I change the "SerializedName" then while deserializing my JSON to POJO, it doesn't work so not sure if there is any other way.
You need to provide alternative names for deserialisation process and primary (value property) for serialisation.
class Segment {
#SerializedName(value = "segment_id", alternate = {"Segment_ID"})
#Expose
private String segmentID;
#SerializedName(value = "status", alternate = {"Status"})
#Expose
private String status;
#SerializedName(value = "datetime", alternate = {"DateTime"})
#Expose
private String dateTime;
}
Now, you can deserialise fields: Segment_ID, DateTime, Status and still be able to serialise as desired.

How to generate complete json string of a java instance

I have a class which has below fields
class MyEvent {
private long eventId;
private EventType eventType;
private EventCategory category;
private List<String> params;
private Boolean exists;
private long time;
private MyLocation location;
private boolean eventFlag;
private EventCriticality criticality;
private EventStatus eventStatus;
}
As you can see this class has primitive fields, fields with wrapper of primitive types (like Boolean exists), enums (EventStatus, EventCategory etc) and fields of other reference (like MyLocation location), collections
I want to generate complete json string, that has all the fields.
When i use
Gson gson = new GsonBuilder().setPrettyPrinting().create();
String json = gson.toJson(myevent);
I get json generated only for primitive fields that is
{
"eventid": 0,
"time": 0,
"eventFlag": false
}
Here myevent is instance of MyEvent which i get by using reflection i.e. i have class and then call clazz.newInstance()
How can i generate a json string that has all the fields i.e. complete json string.
If you have a flexibility to change api, you can use Jackson API http://wiki.fasterxml.com/JacksonHome.
With jackson you can write a code like this
MyEvent myEvent = new MyEvent();
//Your code to set myEvent
ObjectMapper mapper = new ObjectMapper();
String str1 = mapper.writeValueAsString(myEvent);
You will get the desired output. It will loop through all the objects withing myEvent and generate a json.

How to extract property from JSON embedded within JSON?

This is the JSON String I am getting back from a URL and I would like to extract highDepth value from the below JSON String.
{
"description": "",
"bean": "com.hello.world",
"stats": {
"highDepth": 0,
"lowDepth": 0
}
}
I am using GSON here as I am new to GSON. How do I extract highDepth from the above JSON Strirng using GSON?
String jsonResponse = restTemplate.getForObject(url, String.class);
// parse jsonResponse to extract highDepth
You create a pair of POJOs
public class ResponsePojo {
private String description;
private String bean;
private Stats stats;
//getters and setters
}
public class Stats {
private int highDepth;
private int lowDepth;
//getters and setters
}
You then use that in the RestTemplate#getForObject(..) call
ResponsePojo pojo = restTemplate.getForObject(url, ResponsePojo.class);
int highDepth = pojo.getStats().getHighDepth();
No need for Gson.
Without POJOs, since RestTemplate by default uses Jackson, you can retrieve the JSON tree as an ObjectNode.
ObjectNode objectNode = restTemplate.getForObject(url, ObjectNode.class);
JsonNode highDepth = objectNode.get("stats").get("highDepth");
System.out.println(highDepth.asInt()); // if you're certain of the JSON you're getting.
Refering to JSON parsing using Gson for Java, I would write something like
JsonElement element = new JsonParser().parse(jsonResponse);
JsonObject rootObject = element.getAsJsonObject();
JsonObject statsObject = rootObject.getAsJsonObject("stats");
Integer highDepth = Integer.valueOf(statsObject.get("highDepth").toString());

Format of POJO for nested JSON?

So lets say the JSON response is:
[{ "data" : { "item1": value1, "item2:" value2 }}]
How do you get the values 'value1' and 'value2' when you must first access data?
If the fields were at the root then I could just have the method return a POJO with those field names.
I basically want the below to work.
#GET("/path/to/data/")
Pojo getData();
class Pojo
{
public String item1;
public String item2;
}
You can try below code to convert your json string to Pojo object with required fields using Gson library.
Gson gson = new Gson();
JsonArray jsonArray = gson.fromJson (jsonString, JsonElement.class).getAsJsonArray(); // Convert the Json string to JsonArray
JsonObject jsonObj = jsonArray.get(0).getAsJsonObject(); //Get the first element of array and convert it to Json object
Pojo pojo = gson.fromJson(jsonObj.get("data").toString(), Pojo.class); //Get the data property from json object and convert it to Pojo object
or you can define your nested Pojo class to parse it.
class Pojo
{
private String item1;
private String item2;
//Setters and Getters
}
class Data
{
private Pojo data;
//Setters and Getters
}
ArrayList<Data> yourArray = new Gson().fromJson(jsonString, new TypeToken<List<Data>>(){}.getType());
EDIT : Try below code to get value1 and value2 using Retrofit.
class Pojo
{
private String item1;
private String item2;
//Setters and Getters
}
class Data
{
private Pojo data;
//Setters and Getters
}
class MyData
{
private ArrayList<Data> dataList;
//Setters and Getters
}
IService service = restAdapter.create(IService.class);
MyData data = service.getData();
ArrayList<Data> list = data.getDataList(); // Retrive arraylist from MyData
Data obj = list.get(0); // Get first element from arraylist
Pojo pojo = obj.getData(); // Get pojo from Data
Log.e("pojo", pojo.item1 + ", " + pojo.item2);

Categories