Gson how to get serialized name - java

When we define a class with following format
public class Field {
#SerializedName("name")
public String name;
#SerializedName("category")
public String category;
}
for the JsonObject content
{
"name" : "string",
"category" : "string",
}
and using Gson to parse the content
Field field = new GsonBuilder().create().fromJson(
content, Field.class);
So,my question is can we use Gson to get the #Serialized name. For in this instance I want to know what #Serialized name is used for field.name,which is name and for field.category which is category.
As per suggested by #Sotirios Delimanolis, using Reflection we can get the Serialized name
java.lang.reflect.Field fields = Field.class.getDeclaredField("name");
SerializedName sName =fields.getAnnotation(SerializedName.class);
System.out.println(sName.value());

Use reflection to retrieve the Field object you want. You can then use Field#getAnnotation(Class) to get a SerializedName instance on which you can call value() to get the name.

Instead of parsing with Field.class, can't you parse it into a JsonObject.class instead? Then use JsonObject.get():
import com.google.gson.JsonObject;
Gson gson = new GsonBuilder().create();
JsonObject jsonObject = gson.fromJson(content, JsonObject.class);
String serializedName = jsonObject.get("name").getAsString();
Note that .getAsString() will return it as a String without embedded double quotes, compare this to when you call toString().
One thing I was trying to do was serialize an enum field, which is not an object. In that case, you can serialize using JsonElement.class, since it's just a primitive:
import com.google.gson.JsonElement;
Gson gson = new GsonBuilder().create();
JsonElement jsonElement = gson.fromJson("\"a\"", JsonElement.class);
String serializedName = jsonElement.getAsString();

Thats a way with alternate for example for a more complex example
Enum class
public enum SomeStatusCd {
#SerializedName(
value = "status_1",
alternate = {"an alternate 1", "an alternate 2"}
)
STATUS_1("status_1")
....
}
get the enum from alternate
public static SomeStatusCd getFromAlternate(String alternateFieldName){
SomeStatusCd result = null;
Field[] statusDeclaredFields = SomeStatusCd.class.getDeclaredFields();
String foundEnumName = null;
for (Field statusDeclaredField : statusDeclaredFields) {
SerializedName annotation = statusDeclaredField.getAnnotation(SerializedName.class);
if (annotation != null){
String[] declaredFieldAlternates = annotation.alternate();
for (String declaredFieldAlternate : declaredFieldAlternates) {
if (declaredFieldAlternate.equals(alternateFieldName)){
foundEnumName = statusDeclaredField.getName();
}
}
}
}
if (foundEnumName != null){
for (SomeStatusCd enumConstant : SomeStatusCd.class.getEnumConstants()) {
if (enumConstant.name().equals(foundEnumName)){
result = enumConstant;
}
}
}
return result;
}
Test it
SomeStatusCd fromAlternate = getFromAlternate("an alternate 1");
assertSame(fromAlternate, SomeStatusCd.STATUS_1);

Related

How to convert JSON to Java object if I do not know all json fields before parsing?

My service can receive several different jsons, such as:
{
"event":"conversation_started",
"context":"context information",
"user":{
"id":"01234567890A=",
"name":"John McClane",
"avatar":"http://avatar.example.com",
"country":"UK",
"language":"en",
"api_version":1
},
"subscribed":false
}
or
{
"event":"message",
"message":{
"type":"text",
"text":"a message to the service",
"location":{
"lat":12.34,
"lon":12.34
}
}
}
or several else jsons. The only field that is the same for all jsons is "event". All other fields can be different (depends on "event" value).
So the question is: how to convert those jsons to java objects (without making messy code)? The only way I know is to manually check "event" value (like json.startsWith("{\n\"event\":\"message\"") but I'm sure that there is any simple decision for doing this.
There are three ways I've done this. The first is to do what you're suggesting - parse the JSON, check the type, and create the object. Be very careful with using a String parser as you may or may not have things like new lines. Instead, do something like:
ObjectMapper objectMapper = new ObjectMapper();
JsonNode jsonNode = objectMapper.readTree(eventString);
String eventType = jsonNode.get("event").asText();
if( eventType.equalsIgnoreCase("conversation_started")) {
// create ConversationStarted object using something like:
ConversationStarted conversationStarted = objectMapper.readValue( eventString, ConversationStarted.class );
}
This, of course, requires all classes to have a concrete POJO to allow for deserialization.
Another way is to do what many other programming languages do and have a key/value map. There are a few ways to do this. One is with the Jackson libraries:
Map<String, Object> map = objectMapper.readValue(eventString, new TypeReference<Map<String,Object>>(){});
Map<String, Object> user = (Map<String, Object>) map.get("user");
System.out.println( "conversation started - avatar is " + user.get("avatar"));
That way you can pass around the Map and extract as needed. Note that you still need to understand the structure of the JSON but you don't need to have a POJO for it.
Lastly is a variation on the second solution. Using JSONPath you can pull out what you need directly. Again you will want to first check out which type of event you have. Something like:
if( JsonPath.read(eventString, "$.event").equals("conversation_started") ) {
String avatar = JsonPath.read(eventString, "$.user.avatar");
System.out.println("conversation started - avatar is " + avatar);
}
The last two methods require you to pull out values one at a time as shown. The first solution gives you a full object to work with. It is your call as to what works best in your environment.
UPD: If you don't want to convert JSON String to JAVA Object via declaring a POJO, you can parse it to JSONObject(com.alibaba.fastjson.JSONObject)
public class Event {
public static void main(String[] args) {
String jsonA = "{\"event\":\"conversation_started\",\"context\":\"context information\",\"user\":{\"id\":\"01234567890A=\",\"name\":\"John McClane\",\"avatar\":\"http://avatar.example.com\",\"country\":\"UK\",\"language\":\"en\",\"api_version\":1},\"subscribed\":false}";
String jsonB = "{\"event\":\"message\",\"message\":{\"type\":\"text\",\"text\":\"a message to the service\",\"location\":{\"lat\":12.34,\"lon\":12.34}}}";
JSONObject jsonObject = JSONObject.parseObject(jsonA);
String event = jsonObject.getString("event");
if (event.equals("message")) {
//do what you want to do
System.out.println("message event......");
} else if ("conversation_started".equals(event)) {
System.out.println("context information event......");
}
}
}
Declaring a class of Event as below, and then convert JSON String to a Event JAVA object.
#Data
public class Event {
private String event;
private String context;
private User user;
private boolean subscribed;
private Message message;
#Data
public static class User {
private String id;
private String name;
private String avatar;
private String country;
private String language;
private int api_version;
}
#Data
public static class Message {
private String type;
private String text;
private Location location;
#Data
public static class Location {
private double lat;
private double lon;
}
}
public static void main(String[] args) {
String jsonA = "{\"event\":\"conversation_started\",\"context\":\"context information\",\"user\":{\"id\":\"01234567890A=\",\"name\":\"John McClane\",\"avatar\":\"http://avatar.example.com\",\"country\":\"UK\",\"language\":\"en\",\"api_version\":1},\"subscribed\":false}";
String jsonB = "{\"event\":\"message\",\"message\":{\"type\":\"text\",\"text\":\"a message to the service\",\"location\":{\"lat\":12.34,\"lon\":12.34}}}";
ObjectMapper objectMapper = new ObjectMapper();
try {
Event eventA = objectMapper.readValue(jsonA, new TypeReference<Event>() {
});
System.out.println(objectMapper.writeValueAsString(eventA));
Event eventB = objectMapper.readValue(jsonB, new TypeReference<Event>() {
});
System.out.println(objectMapper.writeValueAsString(eventB));
} catch (IOException e) {
e.printStackTrace();
}
}
}
Use a JSON object. This is dynamic and can load any json. Then you can reference the event field consistently
Example 1
//import java.util.ArrayList;
//import org.bson.Document;
Document root = Document.parse("{ \"event\" : \"conversation_started\", \"context\" : \"context information\", \"user\" : { \"id\" : \"01234567890A=\", \"name\" : \"John McClane\", \"avatar\" : \"http://avatar.example.com\", \"country\" : \"UK\", \"language\" : \"en\", \"api_version\" : 1 }, \"subscribed\" : false }");
System.out.println(((String)root.get("event")));
Example 2
//import java.util.ArrayList;
//import org.bson.Document;
Document root = Document.parse("{ \"event\" : \"message\", \"message\" : { \"type\" : \"text\", \"text\" : \"a message to the service\", \"location\" : { \"lat\" : 12.34, \"lon\" : 12.34 } } }");
System.out.println(((String)root.get("event")));

Cannot cast from <Type> to Result by using Gson

I am using Gson library to convert my JSON array of Objects to String.
But i am getting this error of Cannot cast from DataIntent to Result!!
DataIntent is the name of POJO class.
data.json
`{
"dataIntents": [
{
"intent": "muster.policy.daily",
"expr": "Am I supposed to register my attendance daily?"
},
{
"intent": "leave.probation",
"expr": "An employee is eligible for how many leaves ??"
}
]
}`
POJO classes :
public class DataIntent {
private String intent;
private String expr;
//getters and setters
}'
Example class
public class Example {
private List<DataIntent> dataIntents = null;
public List<DataIntent> getDataIntents() {
return dataIntents;
}
public void setDataIntents(List<DataIntent> dataIntents) {
this.dataIntents = dataIntents;
}
}
Main class :
public class JSONMain {
public static void main(String[] args) {
Gson gson = new Gson();
BufferedReader br = null;
try {
br = new BufferedReader(new FileReader("data.json"));
org.junit.runner.Result result = (org.junit.runner.Result)
gson.fromJson(br, DataIntent.class);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
I dont know what i am doing wrong? As i am new to programming.
I have seen this over a video on youtube (This link)
I am getting problem on
org.junit.runner.Result result = (org.junit.runner.Result)gson.fromJson(br, DataIntent.class);
Is it the right Result i am using?? or else what is the other solutions so i can parse my JSONArray of objects to get key : value of 'expr'
Please help!!
gson.fromJson deserialize the json string into an object of the class you provided as parameter, DataIntent.class in your case.
In the video you linked, Result is the class he's going to deserialize json string to.
In fact the statement is:
Result result = gson.fromJson(br, Result.class)
There's no cast needed, you just have to define the variable you want to instance with the result of the desarialization of the same type you're passing as parameter to fromJson method:
DataIntent di = gson.fromJson(br, DataIntent.class);
Edit based on your comment:
You should deserialize to your Example class:
Example example = gson.fromJson(br, Example.class);
and then loop through the list of DataIntent of the Example class:
for(DataIntent di : example.getDataIntents())

Convert a JSON of different type of objects into java List object

I have a JSON object stored in db in the form of string. I am using it to create dynamic form in the UI. Now the problem is I want to change some values in it based on other changes happening on the application. So suppose I updated label for the field, then I have to get this JSON and change that here.
This would be easy If I have stored same type of objects in this json, but my JSON is like follows:
[{
"name": "someName",
"xtype": "keyvaluecombo",
"fieldLabel": "Some Title",
"refType": "YES_NO",
"multiSelect": false,
"helpText": ""
},
{
"name": "someName2",
"xtype": "keyvaluecombo",
"fieldLabel": "Some Title2",
"refType": "YES_NO",
"multiSelect": false,
"helpText": ""
},
{
"xtype": "datefield",
"fieldLabel": "Joining Date",
"name": "joiningDate",
"submitFormat": "Y-m-d"
},
{
"xtype": "userselectioncombo",
"fieldLabel": "Selection",
"name": "selections",
"filterBy": {
"functions": [
"select"
]
}
}]
Now this is stored as String in db, what is efficient way of changing fieldLabel based on name. I could have tried working on it as string only and use regular expression, but that didn't feel right.
You should write a bean class, which should be mapping to you Json object like,
public class abc {
private String name;
private String xtype;
private String fieldLabel;
........
}
Then you should use
import java.lang.reflect.Type;
GsonBuilder gsonBuilder = new GsonBuilder();
Gson gson = gsonBuilder.create();
Type type = new TypeToken<List<abc>>() {
}.getType();
List<abc> abcList = gson.fromJson(confTemplate,
type); // confTemplate is your Json object you get from DB
this will get the list of beans.
for (abc abcData : abcList ) {
// you can do your stuff
}
First of all the best way, changing your database design with a new one that suits your model. Not keeping json in your database as a column. But if you can't do that, because sometimes it's impossible to change old db designs you can trace the following way.
And of course you should read your json from db before start and save it again after the below process.
Create a custom object that suits your model.
public class MyObject{
private String name;
private String fieldLabel;
public String getFieldLabel(){
return fieldLabel;
}
public void setFieldLabel( String fieldLabel ){
this.fieldLabel = fieldLabel;
}
public String getName(){
return name;
}
public void setName( String name ){
this.name = name;
}
// bla bla other fields
Convert your json into your object, and vice versa see the code example below:
public static void main( String[] args ){
Gson gson = new Gson();
String yourJson = "[{'name':'someName','xtype':'keyvaluecombo','fieldLabel':'Some Title','refType':'YES_NO','multiSelect':false,'helpText':''},{'name':'someName2','xtype':'keyvaluecombo','fieldLabel':'Some Title2','refType':'YES_NO','multiSelect':false,'helpText':''},{'xtype':'datefield','fieldLabel':'Joining Date','name':'joiningDate','submitFormat':'Y-m-d'},{'xtype':'userselectioncombo','fieldLabel':'Selection','name':'selections','filterBy':{'functions':['select']}}]";
// changing single quotes with double ones.
yourJson = yourJson.replaceAll( "'", "\"" );
JsonArray jsonArray = new JsonParser().parse( yourJson ).getAsJsonArray();
List<MyObject> result = new ArrayList<MyObject>();
for( JsonElement jsonElement : jsonArray ){
MyObject myObject = gson.fromJson( jsonElement, MyObject.class );
// change fields as you wish
if( myObject.getName().equals( "someName" ) ){
myObject.setFieldLabel( "TEST" );
}
// add it to another list
result.add( myObject );
}
// convert into another json again..
System.out.println( gson.toJson( result ) );
}
Easy to realize that Object in your list have attributes below:
"name"
"xtype"
"fieldLabel"
"refType"
"multiSelect"
"helpText"
"submitFormat"
"filterBy"
So you can create an Object which has over attributes. Using ObjectMapper for deserialize the list:
ObjectMapper mapper = new ObjectMapper();
mapper.readValue(json, new TypeReference<ArrayList<T>>() {})
After have a list object you can loop for change any attribute or change attribute of an specific item you want.

Parsing nested JSON data using GSON

I'm trying to parse some JSON data using gson in Java that has the following structure but by looking at examples online, I cannot find anything that does the job.
Would anyone be able to assist?
{
"data":{
"id":[
{
"stuff":{
},
"values":[
[
123,
456
],
[
123,
456
],
[
123,
456
],
],
"otherStuff":"blah"
}
]
}
}
You just need to create a Java class structure that represents the data in your JSON. In order to do that, I suggest you to copy your JSON into this online JSON Viewer and you'll see the structure of your JSON much clearer...
Basically you need these classes (pseudo-code):
class Response
Data data
class Data
List<ID> id
class ID
Stuff stuff
List<List<Integer>> values
String otherStuff
Note that attribute names in your classes must match the names of your JSON fields! You may add more attributes and classes according to your actual JSON structure... Also note that you need getters and setters for all your attributes!
Finally, you just need to parse the JSON into your Java class structure with:
Gson gson = new Gson();
Response response = gson.fromJson(yourJsonString, Response.class);
And that's it! Now you can access all your data within the response object using the getters and setters...
For example, in order to access the first value 456, you'll need to do:
int value = response.getData().getId().get(0).getValues().get(0).get(1);
Depending on what you are trying to do. You could just setup a POJO heirarchy that matches your json as seen here (Preferred method). Or, you could provide a custom deserializer. I only dealt with the id data as I assumed it was the tricky implementation in question. Just step through the json using the gson types, and build up the data you are trying to represent. The Data and Id classes are just pojos composed of and reflecting the properties in the original json string.
public class MyDeserializer implements JsonDeserializer<Data>
{
#Override
public Data deserialize(JsonElement je, Type type, JsonDeserializationContext jdc) throws JsonParseException
{
final Gson gson = new Gson();
final JsonObject obj = je.getAsJsonObject(); //our original full json string
final JsonElement dataElement = obj.get("data");
final JsonElement idElement = dataElement.getAsJsonObject().get("id");
final JsonArray idArray = idElement.getAsJsonArray();
final List<Id> parsedData = new ArrayList<>();
for (Object object : idArray)
{
final JsonObject jsonObject = (JsonObject) object;
//can pass this into constructor of Id or through a setter
final JsonObject stuff = jsonObject.get("stuff").getAsJsonObject();
final JsonArray valuesArray = jsonObject.getAsJsonArray("values");
final Id id = new Id();
for (Object value : valuesArray)
{
final JsonArray nestedArray = (JsonArray)value;
final Integer[] nest = gson.fromJson(nestedArray, Integer[].class);
id.addNestedValues(nest);
}
parsedData.add(id);
}
return new Data(parsedData);
}
}
Test:
#Test
public void testMethod1()
{
final String values = "[[123, 456], [987, 654]]";
final String id = "[ {stuff: { }, values: " + values + ", otherstuff: 'stuff2' }]";
final String jsonString = "{data: {id:" + id + "}}";
System.out.println(jsonString);
final Gson gson = new GsonBuilder().registerTypeAdapter(Data.class, new MyDeserializer()).create();
System.out.println(gson.fromJson(jsonString, Data.class));
}
Result:
Data{ids=[Id {nestedList=[[123, 456], [987, 654]]}]}
POJO:
public class Data
{
private List<Id> ids;
public Data(List<Id> ids)
{
this.ids = ids;
}
#Override
public String toString()
{
return "Data{" + "ids=" + ids + '}';
}
}
public class Id
{
private List<Integer[]> nestedList;
public Id()
{
nestedList = new ArrayList<>();
}
public void addNestedValues(final Integer[] values)
{
nestedList.add(values);
}
#Override
public String toString()
{
final List<String> formattedOutput = new ArrayList();
for (Integer[] integers : nestedList)
{
formattedOutput.add(Arrays.asList(integers).toString());
}
return "Id {" + "nestedList=" + formattedOutput + '}';
}
}

Parsing JSON using Google GSON: reading values directly from child objects

I'm having trouble parsing the following JSON with Google's Gson:
{"Name":
{"object1":
{"field1":"17",
"field2":"360",
"field3":"19",
"field4":"sun",
"field5":"rain"
}
}
}
I have tried the following to get the value of field1 but it doesn't work
#SerializedName("Name/object1/field1")
public int fieldOne;
What am I doing wrong?
Your objects have to conserve the hierarchy of your json instructions. For your example, it would be something like this:
public class Object {
#SerializedName("field1")
public String fieldOne;
#SerializedName("field2")
public String fieldTwo;
#SerializedName("field3")
public String fieldThree;
#SerializedName("field4")
public String fieldFour;
}
public class Name {
#SerializedName("object1")
public Object obj;
}
public class GsonObj {
#SerializedName("Name")
public Name name;
}
Using the following call:
String json = "{\"Name\":{" +
"\"object1\":{" +
"\"field1\":\"17\",\"field2\":\"360\",\"field3\":\"19\",\"field4\":\"sun\",\"field5\":\"rain\"}}}";
Gson gson = new Gson();
GsonObj jsonResult = gson.fromJson(json, GsonObj.class);
Log.d("test", "field one: "+jsonResult.name.obj.fieldOne);
Log.d("test", "field two: "+jsonResult.name.obj.fieldTwo);
Log.d("test", "field three: "+jsonResult.name.obj.fieldThree);
Log.d("test", "field four: "+jsonResult.name.obj.fieldFour);
You have invalid JSON. JSON may either start with { or [ so you need to wrap your string with another pair of {}.
A good practice is to always check your data first. I often use this here:
http://jsonlint.com/
I don't think you can have "Name/object1/field" you have to specify key name directly without hierarchy.
refer How to parse dynamic JSON fields with GSON?

Categories

Resources