Gson-> Json to deserialize List of custom objects - java

I am trying to serialize and de-serialize an ArrayList of Java POJOs using Gson on Json objects
I have an object MyClass as
public class MyClass{
private int type
private int pos;
private Object value;
}
I have an ArrayList of these objects, which I serialize as
List<MyClass> values= null;
String json = new Gson().toJson(retValues);
The json string is
[{"type":4,"pos":1,"value":15}]
I try to deserialize it as
Type myType = new TypeToken<ArrayList<MyClass>>() {}.getType();
List<MyClass> test=new Gson().fromJson(json, myType);
I get an error
The JsonDeserializer com.google.gson.DefaultTypeAdapters$CollectionTypeAdapter#1141ddf failed to deserialized json object [{"type":4,"pos":1,"value":18}] given the type java.util.ArrayList<abc.MyClass>
Any input much appreciated!

I figured it out. I added 2 things, I don't know which one made it work.
- I added a no-arguments constructor to MyClass
- I made MyClass implement serializable.
And it works!
Thanks for your help.

Related

How to convert List<?> to List<Object> in java?

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);

GSON not de-serializing properly nested map with generic key/value

I'm using GSON to deserialise a JSON string to a JAVA object containing a nested Map with generic key/value.
From my debugging I see GSON converts the first generic type to the correct object. But the second is not converted and therefore acts as a string.
class A {
public B<C_Enum> b = new B<C_Enum>();
}
class B<T> {
private Map<T, T> map = new HashMap<T, T>();
}
enum C_Enum {
VAL1, VAL2;
}
main() {
String json = "{\"b\": {\"map\": {\"NOT_VALID\": \"NOT_VALID\"}}}";
GsonBuilder builder = new GsonBuilder();
Gson customDeserializer = builder.create();
A a = customDeserializer.fromJson(json, A.class);
}
In this example the map is populated with a null key because NOT_VALID is not a valid C_Enum value, and the value of the map is populated with NOT_VALID.
Note: my real code is a bit different but the problem is the same
I meet the same issue
Map<SOME_ENUM, T>map;
// gson will not use #SerializedName in the SOME_ENUM
String badJson = new Gson().toJson(map)
change it to
Map<SOME_ENUM, T>map;
// gson is good
String goodJson = new GsonBuilder().enableComplexMapKeySerialization().create().toJson(map)
link to gson/issue

How to Deserialize JSON object with dynamic variable names to a Java POJO?

I am trying to parse the following nested JSON object using RestTemplate's getForObject method:
"rates":{
"USD":1.075489,
"AUD":1.818178,
"CAD":1.530576,
"PLN":4.536389,
"MXN":25.720674
}
The number of currency rates varies depending on user input (it can be one or more).
How can I map such list of objects or a HashMap to a Java POJO class?
I tried with composition in the rates object:
public class Rates implements Serializable {
private List<ExternalApiQuoteCurrencyRate> list;
// getter and no-args constructor
}
public class ExternalApiQuoteCurrencyRate implements Serializable {
private String currency;
private BigDecimal rate;
// getters and no-args constructor
}
But the rates object gets deserialized as null.
Could somebody please help? Thanks a lot in advance!
Thanks to #Simon and #bhspencer I solved the issue by exporting the JSON object to a HashMap using JsonNode.
Here is the solution:
ResponseEntity<JsonNode> e = restTemplate.getForEntity(API_URL, JsonNode.class);
JsonNode map = e.getBody(); // this is a key-value list of all properties for this object
// but I wish to convert only the "rates" property into a HashMap, which I do below:
ObjectMapper mapper = new ObjectMapper();
Map<String, BigDecimal> exchangeRates = mapper.convertValue(map.get("rates"), new TypeReference<Map<String, BigDecimal>>() {});

Gson to json string conversion

Hello all I am setting value to an object and then running gson.tojson(myObject)
This works fine and the output looks like:
{"val1":22,"val2":4,"val3":34,"val4":1046.0,"val5":"hello","val6":true}
However I now need my json string to look like
{"myJson": {"val1":22,"val2":4,"val3":34,"val4":1046.0,"val5":"hello","val6":true}}
is there a built in way to do this or should I just do sting concat?
Yes, you just need to get the JsonTree and add an inner object to it
JsonElement innerObject = gson.toJsonTree(myObject);
JsonObject outerObject = new JsonObject();
outerObject.add("myJson",innerObject);
Now, outerObject has innerObject so you can take it from there, convert it to String if you want.
String json = outerObject.toString();
I don't know if there is a option for that with Gson but you can create a wrapper class for your object :
class ObjectWrapper {
Object myJsonObject;
}
And use gson.toJson() on the wrapped object.
You can create a wrapper class which has your object set in its property "myJson".
public class Wrapper {
<Yourclass> myJson;
public Wrapper(<Yourclass> obj){
myJson = obj;
}
}
Afterwards create the JSON based on the Wrapper.

Serialize an object which has a json-format-string to json

I have an object like:
public class Foo{
public String f1="[{\"jsonField\":\"something\"},{\"jsonField\":\"something\"}]";
}
Gson would serialize it to:
{"f1":"[{\"jsonField\":\"something\"},{\"jsonField\":\"something\"}]"}
The f1 field was serialized to a string. Apparently, the field is a well formed json-format string. How can I do to serialized the field to an jso array, like below:
{"f1":[{"jsonField":"something"},{"jsonField":"something"}]}
PS. For performance consideration, I can't deserialize then serialize the field.
Gson is serializing your string field to a string. That's normal. If your field, however, was a List<String>, Gson would give you:
{"f1":["jsonField:something","jsonField:something"]}
And if it was a List where something has a field called jsonField you'd get what you actually want.
This is the implicit way that Gson serializes your objects. If you don't like it, you need to implement your own TypeAdapter and register it with Gson at the builder.
GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapter(MyObject.class, new SomethingGsonAdapter());
Gson gson = builder.create()
And you need to define:
public class SomethingGsonAdapter implements JsonDeserializer<DataItem>, JsonSerializer<DataItem>;

Categories