I have a class like this:
#JsonInclude(Include.NON_NULL)
#JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class)
public class VPC
{
#NotNull()
private String id;
#NotNull()
#DynamoDBMarshalling(marshallerClass = SubnetTypeMarshaller.class)
private Map<SubnetType, List<String>> subnetTypeToId;
}
Here, SubnetType is a enum like this:
public enum SubnetType
{
AppSubnet,
DBSubnet,
DMZSubnet;
}
Now, I want to store the above in AWS DynamoDB. For this, I need to convert enum to a string and I have written the following.
public class SubnetTypeMarshaller implements DynamoDBMarshaller<Map<SubnetType, List<String>>>
{
private Gson gson = new GsonBuilder().create();
#Override
public String marshall(final Map<SubnetType, List<String>> securityGroupTypeListMap)
{
return gson.toJson(securityGroupTypeListMap);
}
#Override
public Map<SubnetType, List<String>> unmarshall(final Class<Map<SubnetType, List<String>>> aClass,
final String s)
{
return gson.fromJson(s, aClass);
}
}
But this doesn't work. While getting values from DB, I get the following error:
java.lang.String cannot be cast to java.lang.Enum (through reference chain: java.util.ArrayList[0]->["security_group_type_to_id"])
Am I missing something in this? I searched on other posts how to convert enums to string using #SerializedName annotation. But that didn't work either. I have also tried the solution mentioned in the other post, but it doesn't work. Maybe because my enum is in itself a part of map and I can't really annotate the enum attribute inside the map.
Gson provides default serialization for enums, if you want to change it you have to build your own adapter.
Check gson docs for registerTypeAdapter.
Related
I have an issue regarding serialization/deserialization with jackson.
I have a class with a Map (occupations) like this:
public class RoomType implements Comparable<RoomType>, Serializable {
private static final long serialVersionUID = 2310443507411437907L;
// Key: idUseOccupation, Value: Occupation
private Map<Long, Occupation> occupations = new LinkedHashMap<>();
...
and the Getter of this field instead of returning a Map, it's returning a Collection
public Collection<Occupation> getOccupations() {
return occupations.values();
}
Setter:
public void setOccupations(Map<Long, Occupation> occupations) {
this.occupations = occupations;
}
So, I have no problem with the serialization, but when I try to deserialize with jackson to a roomType object, I get an error:
Can not deserialize instance of java.util.LinkedHashMap out of START_ARRAY token. Just for testing I have changed the getter from Collection to Map and I checked that it works fine, but I cannot make this change because it will imply multiple changes in lots of classes and it might provoke such a big issues in several applications.
How can I solve this problem?
Thanks in advance.
We ingest an external API (we cannot change the JSON we receive) which produces JSON with flattened keys. For example:
{
"composite.key": "value",
"normal": "another value",
"composite.key2": "back here again..."
}
which we would ideally like to deserialize into:
public class SomeObject {
public String normal;
public Composite composite;
}
public class Composite {
public String key;
public String key2;
}
while we know we can write a custom deserializer, I would first like to check if there is support for this in GSON using annotations or by some other means.
You can use GSON's #SerializedName annotation on the Java fields.
Something like this
public class Composite {
#SerializedName("composite.key")
public String key;
#SerializedName("composite.key2")
public String key2;
}
I think the long and short of this is to just use Jackson which provides built-in support by annotating the wrapping object with #JsonUnwrapped(prefix="composite.").
I am trying to create a POJO for the following JSON.
{
"key1":"value1",
"key2":"value2",
"hashmap":
{
"1":"val"
"2":"val"
...
"n":"val"
}
}
Now the POJO I tried was
public class MyPOJO{
#SerializedName{"key1"}
#Expose
private String key1;
#SerializedName{"key2"}
#Expose
private String key2;
#SerializedName{"hashmap"}
#Expose
private HashMap<String,String> hMap;
}
The problem is that the hashmap is not getting serialized. It is just ignored when the class gets serialized.
This is how I use the class in Retrofit.
#POST("/endpoint/")
void foo(#Body MyPojo, Callback<Response> callback);
One suggestion I came across is to use an inner class instead of the Hashmap. But my keys are dynamic, I cannot define variables for each key. I need to get the Hashmap serialized.
http://www.jsonschema2pojo.org/ use this website to generate pojo from json
Maybe you should have a look at retrofit converters and use a converter which supports maps.
Or use a custom converter.
Somary for below: I need to deserilize A<B<C>> from json with Java Gson library
I have an api that response in this templete (Json):
{code:string, message:string, data:(any json type/object/array)}
In Java I define a class to read results:
public class ApiResult <DATA> {
public String code;
public String message;
public DATA data;
}
And I have another Data Class:
public class Ball {
public String color;
public String weight;
}
One of my api methods returns list of ball in top template.
I use GSON.fromJson(reader, new TypeToken<ApiResult<List<Ball>>>() {}.getType());
But Gson read data in List<com.google.gson.internal.LinkedTreeMap> not List
How can I fix this?
Finally I solve my question but not for all A<B<C>> problems
I redefine my ApiResult class to:
public class ApiResult {
public String code;
public String message;
public JsonElement data;
}
Using result = GSON.fromJson(reader, ApiResult.class); I extract global response (All api responses return this part).
and check code and message that I need
then I extract real data I want with final List<Ball> data = GSON.fromJson(result.data, new TypeToken<List<Ball>>() {}.getType()); and return it
I think the main bug/limit in Gson is it only check Generic Type only once for parent type and doesn't check it for generic Type[s]
and I think it's better that they (its Developers) add it to next versions
I have a complex object and for some of the nested objects I need to serialize them into JSON fields instead of JSON objects.
Eg.
public class Outer {
private String someField;
private AnotherClass anotherField;
}
public class AnotherClass {
#XmlElement(name = "useThisName")
private String someField;
private String anotherField;
}
How can I make a custom serializer that will be for the nested object and obey the annotations so the fields are named properly?
My use case for this is to use the ObjectMapper.convertValue() method to create a Map so that I can loop through it and create NameValuePairs for a rest url.
In the end I am hoping to end up with a
Map<String, String>
That I can loop over and create apache BasicNameValuePairs from.
Below is some code I want to use for the end result if I can get everything to serialize properly.
Map<String, String> parameters
= DefaultJacksonMapper.getDefaultJacksonMapper().convertValue(obj, LinkedHashMap.class);
return parameters
.entrySet()
.stream()
.map(entry -> new BasicNameValuePair(entry.getKey(), entry.getValue()))
.collect(Collectors.toList());
If I convert this to a map now my output is like:
"someField" -> "data"
"anotherField" -> "size = 2"
I am trying to get the Map to have the following output which I feel like I need a custom serializer.
"someField" -> "data"
"useThisName" -> "data"
"anotherField" -> "data"
Ok I figured this out.
I ended up creating a new Module that inherited off of SimpleModule. Then I created a new Abstract class like
public abstract class OuterMixin {
#JsonUnwrapped
private AnotherClass anotherField;
}
I also had to annotate the AnotherClass with JsonProperty Like:
public class AnotherClass {
#XmlElement(name = "useThisName")
#JsonProperty("useThisName")
private String someField;
private String anotherField;
}
The when I got my Object Mapper I just registered my module with it and did the conversion and it all worked out.
As a side note I have another property that I had to write a custom serializer for and the #JsonUnwrapped did not work with that.