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
Related
How to convert List<?> to List in java?
For example I have this class
#Data
public class Example {
private List<?> data;
}
and I used in this function
#PostMapping("/getResult")
#ResponseBody
public Result getResult(#RequestBody String json) {
Gson gson = new Gson();
Example xmpl = gson.fromJson(json, Example.class);
List<MyObject> source = (List<MyObject>)xmpl.getData(); //==> error
// get Result
return result;
}
It will give this error
class com.google.gson.internal.LinkedTreeMap cannot be cast to class com.myproject.MyObject
EDITED:
The real problem is not from converting ? to object, but from converting LinkedTreeMap to the object
WORKAROUND :
String jsonData = gson.toJson(xmpl.getData());
MyObjectBean[] objs = gson.fromJson(jsonData,MyObjectBean[].class);
You could go with two solutions, to start with:
You can change the Generic type, this way You don't say data is any collection, but it's a collection of type <T>. Now You can create classes with given type anywhere You need it.
Generic value <?> means in general that you don't care what is inside, and probably You won't read it anyway. When You are interested only if collection is null or what it's size.
When You need to do something with it, then use Generic types.
Example:
public class Example<T> {
private List<T> data;
}
Now inside of your controller, create a private class, to deserialize your payload.
static class MyObjectExample extends Example<MyObject>{
}
Now you can use it do decode JSON:
MyObjectExample xmpl = gson.fromJson(json, MyObjectExample.class);
List<MyObject> source = xmpl.getData();
Now if your code can be serialized to MyObject it will work.
Spring supports deserialization also.
If you have a #RestController annotation added to your Controller class
Example:
#PostMapping("/getResult")
public Result getResult(#RequestBody MyObjectExample xmpl) {
// get Result
return result;
}
Or you can add
consumes = MediaType.APPLICATION_JSON_VALUE
to your REST method.
Try using Spring to convert your value for you.
You can find more
GetMapping and PostMapping
tutotrial
The real issue is not when converting ? to MyObject, but the LinkedTreeMap to MyObject, from
this explanation
by #harsh
so I did this workaround
String jsonData = gson.toJson(xmpl.getData());
MyObjectBean[] objs = gson.fromJson(jsonData,MyObjectBean[].class);
I want to extract json object with restassured, and response is generic like:
#Data
public class ExtractBase<T> {
private Class<T> result; // here I can expect different classes
private String targetUrl;
private Boolean success;
private String error;
private Boolean unAuthorizedRequest;
private Boolean __abp;
}
and I want extract it and get result each time with different class:
.extract().body().as(ExtractBase.class).getResult(); // and here I want to have possibility to choose class which should be exctracted depends on my request
I have tried to use TypeToken but with no result :(
any tips for extracting generic classes from JSON responses?
Use ObjectMapper to map from Objects response to custom type.
Example
objectMapper.readValue(json.getBoody(), YourType.class)
Remember, that objectMaper mustbe register module on methot objectMaper
private final ObjectMapper mapper = new ObjectMapper().findAndRegisterModules();
and your response shouldby
private T result; - witout "class"
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.
Iam currently trying to create a distinct List<Class> classList which contains all Classes of an object for example
DemoObject.java
public class DemoObject {
private Integer id;
private String name;
private BigDecimal price;
private Boolean isActive;
private List<NestedDemoObject> nested;
}
NestedDemoObject.java
public class NestedDemoObject {
private Integer id;
private String nameNest;
private Boolean isActive;
}
What i want to create is a method public List<Class> getDistinctClasses(Class cl); which you give as input for example DemoObject.class and returns a list with
[DemoObject.class, Integer.class, String.class, BigDecimal.class, Boolean.class, List.class, NestedDemoObject.class]
Another example for NestedDemoObject.class would be
[NestedDemoObject.class, Integer.class, String.class, Boolean.class]
I tried to use the .getDeclaredClasses() from Class without any luck.
There is any way to get all nested classes from an object with Reflection API?
Any help or direction appreciated.
The solution provided by Mark is partially correct. You're on the right way trying to retrieve the classes from declared fields. However getType() method does not reveal the generic types.
In order to access the generic types you should use Field.getGenericType() instead. It returns the classes as Type objects. The Field objects DO KNOW their own types (they are not erased as one may believe mistakenly).
This is a java 1.8+ example printing the types with generics:
Arrays.stream(DemoObject.class.getDeclaredFields())
.map(Field::getGenericType)
.map(Type::getTypeName)
.distinct()
.forEach(System.out::println);
It will print the following result:
java.lang.Integer
java.lang.String
java.math.BigDecimal
java.lang.Boolean
java.util.List<com.eto.sandbox.NestedDemoObject>
If you want to play with generic types or parse them for any reason then you could use this example:
Arrays.stream(DemoObject.class.getDeclaredFields())
.map(Field::getGenericType)
.distinct()
.forEach(type -> {
if (type instanceof Class) {
// This is a simple class
} else if (type instanceof ParameterizedType) {
// This is a generic type. You can parse its parameters recursively.
}
});
Maybe this points you in the right direction:
for (Field f : DemoObject.class.getDeclaredFields()) {
System.out.println(f.getType().getName());
}
This prints:
java.lang.Integer
java.lang.String
java.math.BigDecimal
java.lang.Boolean
java.util.List
You can get a class instance through something like Class.forName.
I find it odd that getDeclaredClasses is not working for me either, and I will look into that. I'll update the answer when I know more.
UPDATE
getDeclaredClasses prints classes defined inside a class like so:
class DemoObject {
private Integer id;
private String name;
private BigDecimal price;
private Boolean isActive;
private List<NestedDemoObject> nested;
public class InnerClass {
}
}
Then executing getDeclaredClasses:
for (Class<?> f : DemoObject.class.getDeclaredClasses()) {
System.out.println(f.getName());
}
prints the value:
DemoObject$InnerClass
I have a server that returns a json string:
{"pId": "ChIJ2Vn0h5wOlR4RsOSteUYYM6g"}
Now, I can use jackson to deserialize it into an object with the variable called pId, but I don't want the variable to be called pId, I would rather deserialize it to placeId.
Current object in android java:
public class Place {
private String pId;
}
What I want the object to look like:
public class Place {
private String placeId;
}
If I change the object's variable to placeId, jackson will not be able to deserialize the JSON as the property names no longer matches.
Is there a jackson annotation I can used to map the "placeId" variable in the java object to the JSON string variable "pId" returned back from the server?
Use #JsonProperty annotation:
public class Place {
#JsonProperty("pId")
private String placeId;
}
For more information you can see the related javadoc.