How to convert similar looking JSON structure into different POJO with Gson? - java

I am having below 2 JSON, one for login and another one for order
{
"head": {
"requestCode": "code"
},
"body": {
"reqId": "xyz",
"userName": "xyz",
"passwd": "xyz",
}
}
{
"head": {
"requestCode": "code"
},
"body": {
"reqId": "xyz",
"orderId": "xyz"
}
}
I am trying to write java pojo where the head and refId of body are common for each json but other content of body.
something like the below pojo. Now problem is GSon cannot parse and build objects based on nested parameterized types. Is there any better way to implement it? Not JSON structure will not change.
POJO
public class Base<T extends Body> {
#SerializedName("head")
#Expose
public Head head;
#SerializedName("body")
#Expose
private T body;
}
public class Body {
#SerializedName("clientCode")
#Expose
private String clientCode;
}
public class Head {
#SerializedName("requestCode")
#Expose
public String requestCode;
}
public class Login extends Body {
#SerializedName("userName")
#Expose
public String userName;
#SerializedName("passwd")
#Expose
public String passed;
}
public class Order extends Body {
#SerializedName("orderId")
#Expose
String orderId;
}

You could either introduce two new subclasses of Base which you use for deserialization, for example:
class LoginRequest extends Base<Login> { }
class OrderRequest extends Base<Order> { }
Or you can use Gson's TypeToken class to deserialize a parameterized Base type. See also the corresponding section in the user guide. For example:
Type loginType = new TypeToken<Base<Login>>() {}.getType();
Base<Login> loginRequest = gson.fromJson(..., loginType);

Related

Unable to map API response to pojo

I have a json response
"data": {
"students": [
{
"id": 100,
"name": "ABC"
},
{
"id": 101,
"name": "XYZ"
}
I need to map it to my pojo, something like -
public class TempClass {
List<Temp> list_students;
}
class Temp {
Long id;
String name;
}
Direct reading API response into my pojo gives me a class cast exception. I've tried converting response to a list of map and the collect as Temp class but that also doesn't work.
Exception -
java.util.LinkedHashMap cannot be cast to java object
Any suggestions please?
Code snippet for conversion -
new TempClass(((LinkedHashMap<String, Object>) response.getData()).entrySet())
.stream().map(map -> mapper.convertValue(map, Temp.class))
.collect(Collectors.toList()))
public class Data{
public ArrayList<Student> students;
}
public class Root{
public Data data;
}
public class Student{
public int id;
public String name;
}
Your POJO class will look like this

Apache Camel - GSON JsonSerializer use on routes

I have a endpoint with Camel that returns properties as JSON but are not with the proper order. The return class has a superclass that returns some control data which is necessarily to be present in every return.
public class Respuesta implements Serializable {
#SerializedName("subject")
#Expose
private String subject;
#SerializedName("action")
#Expose
private String action;
#SerializedName("status")
#Expose
private Integer status;
#SerializedName("description")
#Expose
private String description;
...getter/setter
And the final return class inherits that piece.
public class FacturadoresListarResponse extends Respuesta implements Serializable {
#SerializedName("lst")
#Expose
private List<Facturador> listaProveedores;
public FacturadoresListarResponse(List<Facturador> listaProveedores) {
super();
this.listaProveedores = listaProveedores;
}
public FacturadoresListarResponse() {
}
public void setRespuesta(Respuesta rsp) {
super.setAction(rsp.getAction());
super.setDescription(rsp.getDescription());
super.setStatus(rsp.getStatus());
super.setSubject(rsp.getSubject());
}
getter/setter...
}
So, the Gson's Marshaller takes first the inherited class property (lst), and then the parent class properties (subject, status, etc.), giving this kind of result on the wire.
{
"lst": [
{
"rut": "XXXX-X",
"rzsoc": "XXXXXXx",
"res": 1,
"ema": "a#a.cl"
}
],
"subject": "facturadores",
"action": "listar",
"status": 0,
"description": "OK"
}
I wrote a GSON custom JsonSerializer that builds data in order, but I can't use in a Camel DSL syntax. I tried, but without results:
.marshal().json(JsonLibrary.Gson,FacturadoresListarRspSerializer.class, true)
.convertBodyTo(String.class, "UTF-8")
Is there supported by Camel to use these kind of serializers to achieve proper order without migrating to Jackson?
Note: The code of the serializer (FacturadoresListarRspSerializer.class).
public class FacturadoresListarRspSerializer implements JsonSerializer<FacturadoresListarResponse> {
#Override
public JsonElement serialize(FacturadoresListarResponse src, Type typeOfSrc, JsonSerializationContext context) {
final JsonObject jsonObject = new JsonObject();
jsonObject.addProperty("subject", src.getSubject());
jsonObject.addProperty("action", src.getAction());
jsonObject.addProperty("status", src.getStatus());
jsonObject.addProperty("description", src.getDescription());
final JsonArray jsarrFacturadores = new JsonArray();
for (final Facturador fact : src.getListaProveedores()) {
JsonObject jsobFacturadores = new JsonObject();
jsobFacturadores.addProperty("rut", fact.getRutCompleto());
jsobFacturadores.addProperty("rzsoc", fact.getRazonSocial());
jsobFacturadores.addProperty("res", fact.getResolucion());
jsobFacturadores.addProperty("ema", fact.getCorreoEnvio());
jsarrFacturadores.add(jsobFacturadores);
}
jsonObject.add("lst", jsarrFacturadores);
return jsonObject;
}
}
Create a new GSON instance:
Gson gson = new GsonBuilder().registerTypeAdapter(FacturadoresListarResponse.class,
new FacturadoresListarRspSerializer()).create();
Create a new GsonDataFormat by specifying the previously created Gson instance:
GsonDataFormat gsonDataFormat = new GsonDataFormat(gson, FacturadoresListarResponse.class);
Specify the previous data format in your RouteBuilder's marshal(DataFormat dataFormat) method:
.marshal(gsonDataFormat)

How to write a TypeAdapter for multiple JSON objects with Gson?

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/

Gson.fromJson() always returns null

I'm trying to deserialize some JSON to a generic class. The structure is roughly as follows:
public abstract class AbstractRequest implements Constants
{
public abstract Class<?> getClazz();
}
public class GetTransaction extends AbstractTransactionRequest
{
#Override
public Class<Transaction> getClazz()
{
return Transaction.class;
}
}
And the Transaction class is as follows:
public class Transaction implements Serializable
{
#SerializedName("_id")
private String id;
private int amount;
#SerializedName("details")
private Map<String, String> transactionDetails;
private class Details {
private String issuer;
#SerializedName("redirect_url")
private String redirectUrl;
#SerializedName("approval_url")
private String approvalUrl;
}
}
All classes are slightly more complicated but I removed irrelevant variables.
Here's a JSON sample:
{
"_id": "2740096e-58a0-4677-8947-84fcc54cfaad",
"amount": 456,
"details": {
"issuer": "MYBANK",
"redirect_url": "https://example.com/redirect/MYBANK",
"approval_url": "https://example.com/v1/transaction/2740096e-58a0-4677-8947-84fcc54cfaad/MYBANK/authorize"
}
}
Now, I deserialize this code by doing
response.setData(Gson.fromJson(this.getResponse(), this.request.getClazz()));
Where setData accepts a Object, and getResponse returns the JSON as a String. I then do (Transaction) response.getData() which casts data to a Transaction. However, this is always null. Can anyone tell my why?
Sorry for the potentially confusing code!

Deserializing inner class with gson returns null

I want to use Gson to Deserialize my JSON into objects.
I've defined the appropriate classes, and some of those class' objects are included in other objects.
When trying to deserialize the whole JSON, I got null values, so I started breaking it apart.
I reached the point where all lower classes stand by them selves, but when trying to deserialize into an object that holds an instance of that smaller object - every thing returns as null.
My partial JSON:
{
"user_profile": {
"pk": 1,
"model": "vcb.userprofile",
"fields": {
"photo": "images/users/Screen_Shot_2013-03-18_at_5.24.13_PM.png",
"facebook_url": "https://google.com/facebook",
"site_name": "simple food",
"user": {
"pk": 1,
"model": "auth.user",
"fields": {
"first_name": "blue",
"last_name": "bla"
}
},
"site_url": "https://google.com/"
}
}
}
UserProfile Class:
public class UserProfile {
private int pk;
private String model;
private UPfields fields = new UPfields();//i tried with and without the "new"
}
UPfields Class:
public class UPfields {
private String photo;
private String facebook_url;
private String site_name;
private User user;
private String site_url;
}
User Class:
public class User {
private int pk;
private String model;
private Ufields fields;
}
Ufields Class:
public class Ufields {
private String first_name;
private String last_name;
}
In my main I call:
Gson gson = new Gson();
UserProfile temp = gson.fromJson(json, UserProfile.class);
So my temp object contain only null values.
I've tried changing the classes to static, and it doesn't work.
The UPfields object and all lower one work fine.
Any suggestions?
when I remove the
"{
"user_profile":"
and it's closing bracket, the deserialize to a user_profile object works.
In order to parse this json example you have to create auxiliary class, which will contain field named user_profile of type UserProfile:
public class UserProfileWrapper {
private UserProfile user_profile;
}
and parse this json string with this class:
UserProfileWrapper temp = gson.fromJson(json, UserProfileWrapper.class);
Gson starts by parsing the outermost object, which in your case has a single field, user_profile. Your UserProfile class doesn't have a user_profile field, so it can't deserialize it as an instance of that class. You should try to deserialize the value of the user_profile field instead.

Categories

Resources