Deserialize json array and object to strings with default GSON configuration - java

I have to deserialize json like this:
{
"key1" : [
{
"hash1" : "value1_1",
"hash2" : "value1_2",
...
"hashN" : "value1_3",
"date" : "dateValue1"
},
{
"hash1" : "value2_1",
"hash2" : "value2_2",
...
"hashN" : "value2_3",
"date" : "dateValue2"
},
...
],
"key2": {
"description" : {
"hash1" : {
"description1" : "some text",
"description2" : "some text",
},
...
"hashN" : {
"description1" : "some text",
"description2" : "some text",
}
}
}
}
That json have set of unknow keys: hash1, hash2, ... hash2, and set of know keys: key1, key2, description, date, description1, description2.
I work with some custom rest client which use default GSON configuration to deserialize jsons to objects. And I can't change that configuration.
Using this rest client looks like this:
restClient.makeRequest(requestData, DataResponse.class, new RestResponseListener<DataResponse>()
{
#Override
public void onSuccessfulResponse(DataResponse responseData)
{
}
});
DataResponse class have to inherit from Response class from rest client package.
That rest client can't deserialize jsons like above so I decide to try deserializing to String or JsonObject and next in onSuccessfulResponse use custom deserializer.
I try to create below class to hold response:
public class DataResponse extends Response
{
private String key1;
private String key2;
public DataResponse()
{
}
}
Unfortunately I get exception:
com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected a string but was BEGIN_ARRAY at line 1 column 14 path
The question is, how to deserialize array from key1 and object from key2 to strings.
Or maybe is another solution.

Follow Lyubomyr Shaydariv advice I found two solutions.
Using JsonElement class
JsonElement is of course abstract so I have to use subclasses as below
public class DataResponse extends Response
{
private JsonArray key1;
private JsonObject key2;
public DataResponse()
{
}
//getters
}
In rest client callback I handled this data like this:
restClient.makeRequest(requestData, DataResponse.class, new RestResponseListener<DataResponse>()
{
#Override
public void onSuccessfulResponse(DataResponse responseData)
{
Type mapType = new TypeToken<Map<String, String>>(){}.getType();
Gson gson = new Gson();
for(JsonElement element : responseData.getKey1())
{
Map<String, String> map = gson.fromJson(element, mapType);
//do things
}
}
});
Match DataResponse class to json structure
I don't know why it doesn't work previously, but now does:
public class DataResponse extends Response
{
private List<Map<String, String>> key1;
private Key2SchemaClass key2;
public DataResponse()
{
}
public static class Key2SchemaClass
{
private List<Map<String, Description>> description;
}
public static class Description
{
private String description1;
private String description2;
}
//getters
}

Related

How to deserialize a JSON file ( using Google JSON) consisting of same key name but uses different type?

Consider the following JSON File:
{
"version": "1.0",
"firstData": {
"meta": "this is string",
"version": "1"
},
"SecondData": {
"meta": ["string1", "string2", "string3"],
"version": "1"
},
"ThirdData": {
"meta": true,
"version": "1"
},
"FourthData": {
"meta": [true, false, false, true],
"version": "1"
},
"FifthData": {
"meta": [{
"meta": "string",
"version": "2"
},
{
"meta": ["string1","string2"],
"version": "2"
}]
"version": "1"
}
}
As seen, The "meta" attribute has different data type, sometimes it is String, sometimes it is ArrayOfString, sometimes Boolean etc.
Since my JSON file has several data,
I want it to follow the following Structure :
class information
{
String version;
HashMap<String,Data> details;
}
class Data
{
variable meta;
String version;
}
How do I create a corresponding POJO and deserialize it using Google GSON?
Just define your meta as JsonElement. Then you will have sort methods like: getAsString, getAsBoolean, getAsJsonObject, getAsJsonArray, ..., and also you are able to deserialize it again after you find out what is the type.
So your class could look like:
public class SomeClass {
private int version;
private JsonElement meta;
//getters and setters and other stuff
}
Edit: More elaboration and implementation
Define two classes: GeneralItem and GeneralData
class GeneralItem
{
public final int version;
public final JsonElement meta;
}
class GeneralData
{
public final String version;
public final Map<String, GeneralItem> items;
public GeneralData(String version, Map<String, GeneralItem> items)
{
this.version = version;
this.items = items;
}
}
And then we define a custom deserializer for our GeneralData:
class GeneralDataDeserializer implements JsonDeserializer<GeneralData>
{
#Override
public GeneralData deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException
{
final JsonObject object = json.getAsJsonObject();
final String version = object.get("version").getAsString();
object.remove("version");
HashMap<String, GeneralItem> items = new HashMap<>(object.size());
for (Map.Entry<String, JsonElement> item : object.entrySet())
items.put(item.getKey(), context.deserialize(item.getValue(), GeneralItem.class));
return new GeneralData(version, items);
}
}
Finally registering the deserializer to our gson instance and getting the data:
final Gson gson = new GsonBuilder()
.registerTypeAdapter(GeneralData.class, new GeneralDataDeserializer())
.create();
final String json = "your json here";
final GeneralData data = gson.fromJson(json, GeneralData.class);
System.out.println(data.items.get("firstData").meta.getAsString());
//other parts you want
(Note that constructors, getter and setters, error checking, etc. are removed for the sake of brevity)

Mapping JSON response to Java POJO Class using GSON

I am trying to map below JSON to a POJO Class using Gson library. Below is the JSON response and POJO Class and mapping done
import java.util.Map;
import com.google.gson.JsonElement;
public class DataResponse {
private String $status;
private Map<String, JsonElement> $payload;
public String get$status() {
return $status;
}
public void set$status(String $status) {
this.$status = $status;
}
public Map<String, JsonElement> get$payload() {
return $payload;
}
public void set$payload(Map<String, JsonElement> $payload) {
this.$payload = $payload;
}
}
Here is the Sample JSON.
{
"$status": "OK",
"$payload": {
"$nextStart": "123",
"$results": [
{
"$key": "101",
"score": 3,
"to": "Test1"
},
{
"$key": "102",
"score": 4,
"to": "Test2"
},
]
}
}
Below is the mapping done. Is there some problem with POJO class definition. Since I cannot get all the elements of JSON response mapped to the innermost element from the response. Appreciate your support in providing useful suggestions.
Gson gson = new Gson();
DataResponse dataResponse = gson.fromJson(EntityUtils.toString(response.getEntity()),
DataResponse.class);
While working with marshalling and unmarshalling, it is always good to have a model defined as:
public class DataResponse {
private String $status;
private Payload $payload;
// getters and setters
}
class Payload {
private String $nextStart;
private List<Result> $results;
// getters and setters
}
class Result {
private String $key;
private String score;
private String to;
// getters and setters
}
Now when you convert json to POJO as:
Gson gson = new Gson();
DataResponse dataResponse = gson.fromJson(EntityUtils.toString(response.getEntity()), DataResponse.class);
it can easily convert it.
Also, believe me, it is good for processing in your further code!
Update: if you really want to convert json to Map, then you can do something like this:
import java.lang.reflect.Type;
import com.google.gson.reflect.TypeToken;
Type type = new TypeToken<Map<String, String>>(){}.getType();
Map<String, String> myMap = gson.fromJson("{'key':'value'}", type);
Substitute json string there.

Json Serialize and Deserialize complex content using Gson

I have a structure that I want to store using JSON in a file. None of the implementation classes will have more significant information than what is given.
public class ItemExample implements IItem{
private ModelMap map;
private String name;
}
public class ModelMap {
private HashMap<Coord, IPartType> map;
}
public class Coord {
private int x,y,z;
}
public class PartExample implements IPartType {
private String name;
private Purity purity;
}
public Enum Purity{
}
I am brand new to creating JSONs, I've been reading up on how Gson works but I am not really understanding how to translate the examples to my case. Most examples assume knowledge of certain aspects that I just don't know yet.
This is what I have started to do for IPartType:
public class PartDeserialize<T> implements JsonDeserializer<T>{
#Override
public T deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
JsonObject content = json.getAsJsonObject();
String name = content.get("name").getAsString();
Purity purity = Purity.valueOf(content.get("purity").getAsString());
return new Gson().fromJson(content, typeOfT);
}
}
I would appreciate any help.
Possible JSON Example per request:
{
"name" : "sword",
"map" :
{
"map" :
{
"1,1,1" : //string representation of Coord
{
"name" : "blade",
"purity" : "base" // string representation of Purity Enum
},
"0,0,0" :
{
"name" : "handle",
"purity" : "high"
}
}
}
}

jackson serialization for Java object with Map?

I have a Java class like this and want to convert to JSON using Jackson. Thanks for your help.
Java Class
public class myClass {
String Id;
Map<String, Object> optionalData = new LinkedHashMap<String, Object>();
}
How to serialization it to JSON using Jackson ObjectMapper ?
For example, suppose the optionalData is a Map saving two entries <"type", "book"> and <"year", "2014">
I want the output to be as follow. Please note that the key/value of optionalData could be changed on the fly (so, I cannot create a "static" Java object for this without using Map)
[
{
id: "book-id1",
type: "book",
year: "2014"
},
{
id: "book-id2",
type: "book",
year: "2013"
}
]
You can use the #JsonAnyGetter annotation on a getter method that returns the map of optional values. Please refer to this blog plost that explains that in details.
Here is an example:
public class JacksonAnyGetter {
public static class myClass {
final String Id;
private final Map<String, Object> optionalData = new LinkedHashMap<>();
public myClass(String id, String key1, Object value1, String key2, Object value2) {
Id = id;
optionalData.put(key1, value1);
optionalData.put(key2, value2);
}
public String getid() {
return Id;
}
#JsonAnyGetter
public Map<String, Object> getOptionalData() {
return optionalData;
}
}
public static void main(String[] args) throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
List<myClass> objects = Arrays.asList(
new myClass("book-id1", "type", "book", "year", 2013),
new myClass("book-id2", "type", "book", "year", 2014)
);
System.out.println(mapper.writerWithDefaultPrettyPrinter().writeValueAsString(objects));
}
}
Output:
[ {
"id" : "book-id1",
"type" : "book",
"year" : 2013
}, {
"id" : "book-id2",
"type" : "book",
"year" : 2014
} ]
You need to write your own Jackson JsonSerializer to create custom JSON string from Java object as per the need.
Here are the nice posts along with example
JSON Serializer & DeserializerHow do I use a custom Serializer with Jackson?
How Do I Write a Jackson JSON Serializer & Deserializer?
The same thing you can achieve using GSON JsonSerializer
Here are some examples
Serialize java object with GSON
GSON Serialiser Example - javacreed
Here is the code using GSON Serialiser
List<MyClass> list = new ArrayList<MyClass>();
MyClass myClass1 = new MyClass();
myClass1.setId("book-id1");
myClass1.getOptionalData().put("type", "book");
myClass1.getOptionalData().put("year", "2014");
list.add(myClass1);
MyClass myClass2 = new MyClass();
myClass2.setId("book-id2");
myClass2.getOptionalData().put("type", "book");
myClass2.getOptionalData().put("year", "2013");
list.add(myClass2);
class MyClassSerialiser implements JsonSerializer<MyClass> {
#Override
public JsonElement serialize(final MyClass obj, final Type typeOfSrc,
final JsonSerializationContext context) {
final JsonObject jsonObject = new JsonObject();
jsonObject.addProperty("id", obj.getId());
Map<String, String> optioanlData = obj.getOptionalData();
if (optioanlData.size() > 0) {
for (Map.Entry<String, String> entry : optioanlData.entrySet()) {
jsonObject.addProperty(entry.getKey(), entry.getValue());
}
}
return jsonObject;
}
}
String jsonString = new GsonBuilder().setPrettyPrinting().
.registerTypeAdapter(MyClass.class, new MyClassSerialiser()).create()
.toJson(list);
System.out.println(jsonString);
output:
[
{
"id": "book-id1",
"type": "book",
"year": "2014"
},
{
"id": "book-id2",
"type": "book",
"year": "2013"
}
]

NullPointerException : JSON Parsing in JAVA using GSON

I want to parse a JSON File through java using the Api GSON to get the last fields of the JSON file :
descriptor.json :
{
"Teleservice_1" : {
"Record_1" : {
"method_name" : "mehdi",
"method_params": ["param1",2,"param3"]
},
"Record_2" : {
"method_name" : "mkyong",
"method_params": [3,"param2"]
},
"Record_3" : {
"method_name" : "amine",
"method_params": [3,"param1","param2"]
}
},
"Teleservice_2" : {
"Record_11" : {
"method_name" : "mehdi1",
"method_params": ["param11",22,"param33"]
},
"Record_22" : {
"method_name" : "mkyong1",
"method_params": [33,"param22"]
},
"Record_33" : {
"method_name" : "amine1",
"method_params": [33,"param11","param22"]
}
},
"Teleservice_3" : {
"Record_111" : {
"method_name" : "mehdi2",
"method_params": ["param111",222,"param333"]
},
"Record_222" : {
"method_name" : "mkyong2",
"method_params": [333,"param222"]
},
"Record_333" : {
"method_name" : "amine2",
"method_params": [333,"param111","param222"]
}
}
}
ListTeleServices.java :
import java.util.HashMap;
public class ListTeleServices {
private HashMap<String, TeleService> listTeleServices;
public ListTeleServices() {
}
public TeleService getTeleService(String teleserviceName) {
if(this.listTeleServices.get(teleserviceName) != null)
return this.listTeleServices.get(teleserviceName);
else
return null;
}
}
TeleService.java :
import java.util.HashMap;
public class TeleService {
private HashMap<String, Record> listRecords;
public TeleService() {
}
public Record getRecord(String recordName) {
if(this.listRecords.get(recordName) != null)
return this.listRecords.get(recordName);
else
return null;
}
}
Record.java :
public class Record {
private String method_name;
private Object[] method_parameters;
public Record(String methodName, Object[] methodParameters) {
this.method_name = new String(methodName);
this.method_parameters = methodParameters;
}
public String getMethodName() {
return this.method_name;
}
public Object[] getMethodParameters() {
return this.method_parameters;
}
public void setMethodName(String methodName) {
this.method_name = methodName;
}
public void setMethodParameters(Object[] methodParameters) {
this.method_parameters = methodParameters;
}
}
And finally my parser class, JSONMainParse.java :
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import com.google.gson.Gson;
public class JSONMainParse {
public static void main(String[] args) throws FileNotFoundException {
BufferedReader br = new BufferedReader(new FileReader("/Users/Mehdi/Desktop/descriptor.json"));
Gson gson = new Gson();
ListTeleServices teleservices = gson.fromJson(br, ListTeleServices.class);
String methodName = teleservices.getTeleService("Teleservice_2").getRecord("Record_33").getMethodName();
System.out.println(methodName);
}
}
It seems correct to me, and it should display : "amine1" but it gives me a nullPointerException at :
ListTeleServices.getTeleService(ListTeleServices.java:12) which is :
if(this.listTeleServices.get(teleserviceName) != null)
and at JSONMainParse.main(JSONMainParse.java:15) which is :
String methodName = teleservices.getTeleService("Teleservice_2").getRecord("Record_33").getMethodName();
Do you have any idea about this ? Thank you :)
SOLUTION:
You are using more classes than necessary to parse the JSON response! You can delete your classes ListTeleServices and TeleService and keep only your Record class.
Gson gson = new Gson();
Type mapOfMapsType = new TypeToken<Map<String, Map<String, Record>>>() {}.getType();
Map<String, Map<String, Record>> map = gson.fromJson(br, mapOfMapsType);
Finally, in order to get the method name, you have to use:
String methodName = map.get("Teleservice_2").get("Record_33").getMethodName();
EXPLANATION:
When you use your class ListTeleServices to parse the JSON here:
ListTeleServices teleservices = gson.fromJson(br, ListTeleServices.class);
What Gson does is to analise the class ListTeleServices and compare it with the JSON response, so it says:
You passed a class ListTeleServices.class, and the JSON response starts with an object {}... so far everything is OK!
Then it continues parse the JSON, and:
In the class ListTeleServices it finds an attribute listTeleServices which is some object (doesn't mind the type for the moment).
However, in the JSON response it finds three elements "Teleservice_1", "Teleservice_2" and "Teleservice_3", but none of them has the same name listTeleServices, so Gson skip all these values and assigns null to the attribute listTeleServices...
Remember that Gson needs the names in the JSON response to be the same that those in the class you are using to parse the response.
On the other hand, if you use directly a Map<String, Map<String, Record>>, Gson see:
You passed the type of Map<String, Map<String, Record>>, and the JSON response starts with an object {}... so far everything is OK! (Remember a Map is just an object)
Then it continues parse the JSON, and:
In Map<String, Map<String, Record>> it see that there must be some pairs of key (string) and value (some object).
And in the JSON response it finds exactly that, some pairs of strings "Teleservice_1", "Teleservice_2" and "Teleservice_3", and some objects {}, so it can keep parsing happily...
P.S: To go further, note that you could have in your class ListTeleServices these attributes:
private HashMap<String, Record> Teleservice_1;
private HashMap<String, Record> Teleservice_2;
private HashMap<String, Record> Teleservice_3;
And it would work well, but this way you can't have an arbitrary number of teleservice ojects...
And by the way, I've also realised other error: in your Response class, the attribute name method_parameters doesn't match the name of the field in the JSON response, which is method_params. You can either change the attribute name or use the annotation:
#SerializedName("method_params")
private Object[] method_parameters;
change this:
private HashMap<String, TeleService> listTeleServices;
to this
private HashMap<String, TeleService> listTeleServices = new HashMap<String,TeleService>();
Initialize the
private HashMap<String, TeleService> listTeleServices;
as
private HashMap<String, TeleService> listTeleServices = new HashMap<>();
In your current code , you are trying to invoke get() on the null object reference, which throws NullPointerException , as you are trying to invoke instance method on a null object.

Categories

Resources