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.
Related
I have the following JSON structure:
{
"sets": [
{...},
{
"id": "id",
"html": "<html></html>",
"javascript": "{onError: function (event) {}}",
"css": ".someclass {}",
"translations": {
"en": { "LABEL_1": "Some label text", "HEADER_1": "Some header text" },
"fr": { "LABEL_1": "Some label text", "HEADER_1": "Some header text" }
}
}
]
}
I have an object that represents this JSON for deserialization purpose
#Data //Lombok
#NoArgsConstructor //Lombok
public class Set {
#JsonProperty("screenSetID")
private String screenSetID;
#JsonProperty("html")
private String html;
#JsonProperty("css")
private String css;
#JsonProperty("javascript")
private String javascript;
#JsonProperty("translations")
private String translations;
}
I have the following piece of code to deserialize JSON
private List<Set> parseSetsData(String json) {
ObjectMapper mapper = new ObjectMapper();
try {
return mapper.readValue(json, TypeReference<List<Set>(){});
} catch (IOException e) {
throw new RuntimeException(e);
}
}
How I can parse translations JSON object as it is?
Any Jason object could be mapped to Map<String, Object> and any Json List could be mapped to List<Object>. So you could parse your JSON as follows:
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModules(new JavaTimeModule());
objectReader = objectMapper.reader();
Map<String, Object> parsedJson = (Map<String, Object>)objectReader.forType(Map.class).readValue(jsonString)
Note that your JSON is a JSON object and not JSON list, so this example parses it to Map
I'm sure you understand that the that you want is part of on array hats why I had to use a for loop:
ObjectMapper mapper = new ObjectMapper();
JsonNode treeNode = mapper.readTree(json);
treeNode=treeNode.findValue("sets");
for (Iterator<JsonNode> it = treeNode.elements(); it.hasNext(); ) {
JsonNode node = it.next();
String theValueYouWant=node.findValue("translations").textValue();
}
Json I found that when you deserialize your item it should look like the following;
public class En
{
#JsonProperty("LABEL_1")
public String lABEL_1;
#JsonProperty("HEADER_1")
public String hEADER_1;
}
public class Fr
{
#JsonProperty("LABEL_1")
public String lABEL_1;
#JsonProperty("HEADER_1")
public String hEADER_1;
}
public class Translations
{
public En en;
public Fr fr;
}
public class Set
{
public String id;
public String html;
public String javascript;
public String css;
public Translations translations;
}
However, in your class, "translations" is a string, but in a JSON structure, it points to an object.
I am trying to write a wrapper around JSON for sending websocket messages. I've created this class which allows you to construct with an event name, and then pass an associative array of event data.
How can I parse JSON in the getString method like this, here is an example of the JSON:
{
"event_name": "some event name",
"event_data": {
"some data": "some data value",
"some more dat": "some more data value"
}
}
Class:
package com.eu.websockets.events.server;
import java.util.HashMap;
import java.util.Map;
public abstract class ServerWebSocketEvent {
private String eventName;
private Map<String, String> eventData;
public ServerWebSocketEvent(String eventName) {
this.eventName = eventName;
this.eventData = new HashMap<>();
}
public void addEventData(String key, String value) {
eventData.put(key, value);
}
public String getString() {
}
}
To have field names different as in the JSON you present you need either to instruct that with #SerializedName or in this case you can also set FieldNamingPolicy to your Gson.
So with #SerializedName:
#SerializedName("event_name")
private String eventName;
#SerializedName("event_data")
private Map<String, String> eventData;
...
public String getString() {
return new Gson().toJson(this)
}
or with FieldNamingPolicy like:
public String getString()
return new GsonBuilder()
.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
.setPrettyPrinting() // This one is not needed use if you want to
.create().toJson(this);
}
I have a JSON feed with multiple nested JSON objects. I have written my POJO classes and have looked on here for how to deserialize nested JSON objects to access the data I needed. However I am still receiving NullPointerExceptions on my nested JSON objects:
JSON feed example
{
"data": [
{
"relationships": {
"dismissals": {
"meta": {
"count": {
"home": 0,
"away": 0
}
},
"data": []
},
"home": {
"data": {
"type": "teams",
"id": "2"
}
}
}
}
]
}
Pojo Mappings
Relationships:
public class Relationships implements Serializable
#SerializedName("region")
#Expose
private Region region;
#SerializedName("competition")
#Expose
private Competition competition;
getters and setters
}
Region:
public class Region implements Serializable
{
#SerializedName("data")
#Expose
private Data data;
}
Data
public class Data implements Serializable, Parcelable
{
#SerializedName("type")
#Expose
private String type;
#SerializedName("id")
#Expose
private String id;
}
My TypeAdapter
public class ItemTypeDataFactory implements TypeAdapterFactory {
public <T> TypeAdapter<T> create(Gson gson, final TypeToken<T> type) {
final TypeAdapter<T> delegate = gson.getDelegateAdapter(this, type);
final TypeAdapter<JsonElement> elementAdapter = gson.getAdapter(JsonElement.class);
return new TypeAdapter<T>() {
public void write(JsonWriter out, T value) throws IOException {
delegate.write(out, value);
}
public T read(JsonReader in) throws IOException {
JsonElement jsonElement = elementAdapter.read(in);
if (jsonElement.isJsonObject()) {
JsonObject jsonObject = jsonElement.getAsJsonObject();
}
return delegate.fromJsonTree(jsonElement);
}
}.nullSafe();
}}
Retrofit builder:
Gson gson = new GsonBuilder()
.registerTypeAdapterFactory(new ItemTypeDataFactory()) // This is the important line ;)
.setDateFormat("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'SSS'Z'")
.create();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
RequestInterface request = retrofit.create(RequestInterface.class);
For example I want to get:
getRelationships().getDissmissals().Meta().Count().Home();
When I run my app I get NullPointerException for that.
Is there something I need to add to my type adapter to deserialize the classes so I can get the data in multiple nested JSON objects? I have tried looking on here already and nothing has helped.
Some times it's difficult to generate the POJO class for a JSON response.
You can generate your POJO easily here http://www.jsonschema2pojo.org/
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
}
I have a JSON array like as shown below which I need to serialize it to my class. I am using Jackson in my project.
[
{
"clientId": "111",
"clientName": "mask",
"clientKey": "abc1",
"clientValue": {}
},
{
"clientId": "111",
"clientName": "mask",
"clientKey": "abc2",
"clientValue": {}
}
]
In above JSON array, clientValue will have another JSON object in it. How can I serialize my above JSON array into my java class using Jackson?
public class DataRequest {
#JsonProperty("clientId")
private String clientId;
#JsonProperty("clientName")
private int clientName;
#JsonProperty("clientKey")
private String clientKey;
#JsonProperty("clientValue")
private Map<String, Object> clientValue;
//getters and setters
}
I have not used jackson before so I am not sure how can I use it to serialize my JSON array into Java objects? I am using jackson annotation here to serialize stuff but not sure what will be my next step?
You can create a utility function shown below. You may want to change the Deserialization feature based on your business needs. In my case, I did not want to fail on unknown properties => (FAIL_ON_UNKNOWN_PROPERTIES, false)
static <T> T mapJson(String body,
com.fasterxml.jackson.core.type.TypeReference<T> reference) {
T model = null;
if(body == null) {
return model;
}
com.fasterxml.jackson.databind.ObjectMapper mapper =
new com.fasterxml.jackson.databind.ObjectMapper();
mapper.configure(com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,
false);
try {
model = mapper.readValue(body, reference);
} catch (IOException e) {
//TODO: log error and handle accordingly
}
return model;
}
You can call it using similar approach as shown below:
mapJson(clientValueJsonString,
new com.fasterxml.jackson.core.type.TypeReference<List<DataRequest>>(){});
You can try #JsonAnyGetter and #JsonAnySetter annotations with an inner class object. Also clientName should have type String, not int.
public class DataRequest {
private String clientId;
private String clientName;
private String clientKey;
private ClientValue clientValue;
//getters and setters
}
public class ClientValue {
private Map<String, String> properties;
#JsonAnySetter
public void add(String key, String value) {
properties.put(key, value);
}
#JsonAnyGetter
public Map<String,String> getProperties() {
return properties;
}
}