I'm using Gson to cast my class to Json, I have a field called payload
which must to be my class itself.
My class is as follow:
public class MyClass {
private Long id;
private String name;
private Object payload;
}
But when I use it as follow:
MyClass myClassObj = MyClass()
myClassObj.setId(1L);
myClassObj.setName("Example");
myClassObj.setPayload(myClassObj);
And I see the result of:
String result = new Gson().toJson(myClassObj);
The result does not contain payload data object.
{"id":1, "name":"Example"}
I need something like:
{"id":1, "name":"Example", "payload": {"id":1, "name":"Example"}}
Thanks in advance.
Any help will be useful.
You will need to change it to be defined as such
public class MyClass {
private Long id;
private String name;
private MyClass payload = null;
}
Gson serialized parameters that are not transient. Object does not have the "id" and "name" parameters you are wanting to serialize. MyClass does. Ensure that payload's default value is null otherwise you may have an infinite loop on your hands when serializing to json.
I found a solution, Object can be anything, so before to set payload of my class I made the follow:
myClassObj.setPayload(new Gson.fromJson(myClassObj.toString(), myClassObj.class);
Note:
In MyClass I have override toString method as follow:
#Override
public String toString() {
return new Gson().toJson(this);
}
If someone has a better solution, feel free to post it.
Related
I am getting a response, which I converted to Pojo class with one field of type Object. Now when I am trying to cast the Object type to another Pojo class its throwing the error :
java.lang.ClassCastException: com.google.gson.internal.LinkedTreeMap cannot be cast to SecondClass
Code :
FirstClassResponse firstClassResponse = (FirstClassResponse) convertJSONToObject(firstClassResponseJson, FirstClassResponse.class);
//jsonToObject method
public static Object convertJSONToObject(String jsonRequest, Class objectClassType) throws Exception {
Object object = gson.fromJson(jsonRequest, objectClassType);
return object;
}
Here, firsClass object when printed gives following result :
FirstClassResponse [modifiedResponse=null, response={id=123, username=abc, balance=0.0, currencycode=EUR, created=2021-03-30 16:31:54, agent_balance=0.0, sessionid=123}]
Now, the error happens in the following line :
SecondClassResponse modifiedResponse = (SecondClassResponse) firstClassResponse.getResponse();
java.lang.ClassCastException: com.google.gson.internal.LinkedTreeMap cannot be cast to SecondClassResponse
I am sharing the POJO for FirstClassResponse and SecondClassResponse :
public class FirstClassResponse{
private SecondClassResponse modifiedResponse;
private Object response;
//getter, setter
}
public class SecondClassResponse{
private String id;
private String username;
private double balance;
private String currencycode;
private String created;
private double agent_balance;
private String sessionid;
//getter, setter
}
private Object response;
Make this a SecondClassResponse, not an Object. With it being an Object, GSON doesn't know that this should be a SecondClassResponse, so it just shoves the map in there as a Map, which obviously can't be cast.
The entire point of using GSON is to turn everything into specific objects so you can use it in a more Java like way. If you store something as an Object when converting from GSON, you're almost always doing it wrong.
That FirstClassResponse is completely superfluous; use SecondClassResponse instead.
Just look at the JSON ...and then explain to me how to map as FirstClassResponse?
And you've not even object-relational mapping (as the GSON converter does), but you're parsing.
Perhaps gson.fromJson cannot convert the attribute class of the class before. You can try to take out firtClassResponse.getResponse() and do the conversion separately
I am trying to deserializer and then serialize a java object.
I got an object like this one-
public class Blas{
private Integer blasRootId;
private List<Bla> blaList = new ArrayList<>();
public Blas() {}
/region g & s
getter and setters ..
//endregion
}
And the object -
public class Bla{
private String fileName;
private String description;
private Integer id;
public Bla() {}
//region g & s
getter and setters ..
//endregion
}
I deserialize the object with
ObjectMapper mapper = new ObjectMapper();
mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
String jsonString = mapper.writeValueAsString(Blas);
And the created json is like
{
"Blas": {
"blasRootId": 2840,
"blaList": [
"java.util.ArrayList",
[
{
"fileName": "RegularPayload",
"description": "",
"id": 2260
}
]
]
}
}
So when I try to serialize the created json the following error accord -
Can not instantiate value of type [simple type, class Bla] from String value ('java.util.ArrayList'); no single-String constructor/factory method
Who can i make the deserializer to write the list as it is ,without the addition "java.util.ArrayList" list, or how can i read it right?
Update :
It was my mistake, I added in the "mapper.configure" a parameter (That i don't recall which) that caused the serializer to add the "java.util.ArrayList".
My code example should work fine.
As prsmax asked, it depends how the code were you try to deserialize blas looks like, it seems like you are trying to take the string of blas and deserialize like this:
mapper.readValue(blasStr, Bla.class)
If you want only to deserialize a list of Bla you can do this:
JavaType javaType = mapper.getTypeFactory().constructCollectionType(ArrayList.class, ValueType.class);
List<ValueType> list = mapper.readValue(str, javaType);
If you actually need the wrapper object Blas, then you should have a constructor marked with #JsonCreator accepting the a List<Bla> marked with #JsonProperty (There are other ways, but this is a fail safe way and makes the code readable)
I'm trying to make a call to the iTunes REST service that returns information about the genres defined in iTunes via a RESTeasy client. The JSON object returned by this call looks something like this:
{
"35":{
"name":"iPod Games",
"id":"35",
"url":"https://itunes.apple.com/us/genre/ipod-games/id35"
},
"36":{
"name":"App Store",
"id":"36",
"url":"https://itunes.apple.com/us/genre/ios/id36?mt=8"
}
}
I've defined my response object model like this:
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
#JsonIgnoreProperties(ignoreUnknown = true)
public class ITunesGenre implements Serializable {
private static final long serialVersionUID = 4330727214147295490L;
#XmlElement
private String name = null;
#XmlElement
private String id = null;
...
}
However, when I make the call via my RESTeasy client, however, I get serialization errors. I believe it is due to the fact that this is not a true List or array of objects. Instead, it seems like each entry has an "identifier" on it (in the example above, the "35" or "36").
Given a JSON object like this, how do I map this so that the RESTeasy client can deserialize it? I've not encountered objects of this format before. I obviously can't hard-code each identifier, since there will be several and they could potentially change.
You can see the full JSON object returned by this call (it's sizable) by clicking here. You'll see that this object structure is found throughout this object, rather than using simple Lists or Arrays of objects.
Any ideas? I'd really appreciate any help you can give.
The response is a Map so root element is not your ITunesGenre class but the Map.I suppose that it is clear how to modify response object.
I suppose it could look something like this (though i haven't tested it)
#XmlRootElement
public class Response implements Serializable
{
public Response(){
}
private java.util.Map<String, Genre> genres = new java.util.HashMap<String, Genre> ();
}
public class Genre implements Serializable {
private static final long serialVersionUID = 4330727214147295490L;
public Genre(){
}
#XmlElement
private String name = null;
#XmlElement
private String id = null;
...
}
I can't find a simple way to add a custom field during serialization in Gson and I was hoping someone else may be able to help.
Here is a sample class to show my issue:
public class A {
String id;
String name;
...
}
When I serialize class A I would like to return something like:
{ "id":"123", "name":"John Doe", "url_to_user":"http://www.example.com/123" }
where url_to_user is not stored in my instance of class A, but can be generated with data in the instance of class A.
Is there a simple way of doing this? I would prefer to avoid writing an entire serializer just to add one field.
Use Gson.toJsonTree to get a JsonElement, with which you can interact dynamically.
A a = getYourAInstanceHere();
Gson gson = new Gson();
JsonElement jsonElement = gson.toJsonTree(a);
jsonElement.getAsJsonObject().addProperty("url_to_user", url);
return gson.toJson(jsonElement);
Well, the top rated answer is quite a quick one and not essentially bad when you are lacking much time but here is the problem: There is no proper separation of concern
You are modifying the serialized JSON at the same place where you are writing your business logic. You should be doing all the serialization inside of a TypeAdapter or a JsonSerializer.
How can we maintain a proper separation of concern?
The answer wraps around a bit of additional complexity but the architecture demands it. Here we go(taken from my other answer):
First, we would be using a custom serializer for the type. Second, we would have to create a copy constructor inside the base class and a wrapper subclass as follows:
Note: The custom serializer might seem like an overkill but trust me, it pays off in long run for maintainability.
.
// Lets say the base class is named Cat
public class Cat {
public String name;
public Cat(String name) {
super();
this.name = name;
}
// COPY CONSTRUCTOR
public Cat(Cat cat) {
this.name = cat.name;
}
#Override
public String sound() {
return name + " : \"meaow\"";
};
}
// The wrapper subclass for serialization
public class CatWrapper extends Cat{
public CatWrapper(String name) {
super(name);
}
public CatWrapper(Cat cat) {
super(cat);
}
}
And the serializer for the type Cat:
public class CatSerializer implements JsonSerializer<Cat> {
#Override
public JsonElement serialize(Cat src, Type typeOfSrc, JsonSerializationContext context) {
// Essentially the same as the type Cat
JsonElement catWrapped = context.serialize(new CatWrapper(src));
// Here, we can customize the generated JSON from the wrapper as we want.
// We can add a field, remove a field, etc.
// The main logic from the top rated answer now here instead of *spilling* around(Kindly ignore the cat having a url for the sake of example)
return catWrapped.getAsJsonObject().addProperty("url_to_user", url);
}
}
So, why a copy constructor?
Well, once you define the copy constructor, no matter how much the base class changes, your wrapper will continue with the same role. Secondly, if we don't define a copy constructor and simply subclass the base class then we would have to "talk" in terms of the extended class, i.e, CatWrapper. It is quite possible that your components talk in terms of the base class and not the wrapper type.
I am trying to deserialise a JSON-RPC object with Jackson. The format of JSON-RPC is :
{ "result": "something", "error": null, "id": 1}
In my case the result property is an generic Object.
I have a class for deserilising the response:
public class JsonRpcResponse {
private Object result;
private JsonRpcError error;
private int id;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public JsonRpcError getError() {
return error;
}
public void setError(JsonRpcError error) {
this.error = error;
}
public Object getResult() {
return result;
}
public void setResult(Object result) {
this.result = result;
}
}
I can get the response object with:
JsonRpcResponse jsonResp = mapper.readValue(response, JsonRpcResponse.class);
I want to have a generic method that deserializes this result object by passing to the method the type of the object (or the class if you want) that is going to be deserialized to. This way I can pass any type of object depending of the response I expect.
For example, I have this class with two properties:
public class JsonEventProperties {
private String conditon;
private String usage;
public JsonEventProperties(String condition, String usage) {
this.conditon = condition;
this.usage = usage;
}
public JsonEventProperties() {
throw new UnsupportedOperationException("Not yet implemented");
}
public String getConditon() {
return conditon;
}
public void setConditon(String conditon) {
this.conditon = conditon;
}
public String getUsage() {
return usage;
}
public void setUsage(String usage) {
this.usage = usage;
}
}
The result object inside the response for the above case will be:
"result": {"condition":"test","usage":"optional"}
I tried:
mapper.readValue(result,objectClass)
where result is a JsonNode intance of the result (Which for some reason is a LinkedHashMap) and objectClass the class I want it to deserialize to. But this is not working.
I busted my head all day with different ways of doing this but I probably do not understand who Jackson works.
Can anyone help me with this?
Thank you in advance.
I understand the original question to be asking about polymorphic deserialization of the "result" object.
Jackson now has a built-in mechanism available for this, using the #JsonTypeInfo and #JsonSubTypes annotations. (ObjectMapper has methods available as alternatives to using the annotations.) Further information is available in the official docs at http://wiki.fasterxml.com/JacksonPolymorphicDeserialization. Also, I posted a few use examples of this at http://programmerbruce.blogspot.com/2011/05/deserialize-json-with-jackson-into.html.
However, if you're stuck deserializing JSON that, in the target object, does not have an element that identifies the type by some name, then you're stuck with custom deserialization, where you'll have to determine based on some object content what the type should be. One of the last examples in the same blog posted I linked above demonstrates this approach, using the existence of particular JSON elements in the target object to determine the type.
Check out jsonrpc4j on github:
https://github.com/briandilley/jsonrpc4j
I had the same issue, this was my solution.
I added one more field to the object, so when building the object, i am setting the field value with class name, when deserializing it i am using
mapper.convertvalue(object, Class.forName(field value)
In your case
private Object result;
In the result object add one more field "className", while serializing the class set the value "className" with the name of the class you are treating as result object.
while deserializing the object
JsonRpcResponse jsonResp = mapper.readValue(response, JsonRpcResponse.class);
in jsonResp you will have Object result, String className, here the object is of type linkedhashmap
Now to convert to your object
objectmapper.convertValue(result, Class.forName(className))
The above code will get you the generic object which you want .
Hope this helps