Generalizing field names with Gson - java

I have a JSON objext that looks like this:
{
"isDefault": false,
"someIndex":
[
0
],
"label": "Hello",
"valueKindName": "someId",
"value": 3,
"conditions":
{
"salesType":
[
1,
2
],
"productType":
[
1,
5
]
}
}
Now my Conditions class looks like this:
public class Conditions {
private List<Integer> salesType = new ArrayList<Integer>();
private List<Integer> productType = new ArrayList<Integer>();
}
This works.
What I want to do is to generalize my class so that I could any new type to the conditions like:
"exampleType":
[
6,
9
]
without having to add
private List<Integer> exampleType = new ArrayList<Integer>();
to my Conditions.class.
I have thought of the following:
public class Conditions {
private ArrayList<Condition> conditions = new ArrayList<Condition>();
}
and
public class Condition {
private String key;
private ArrayList<Integer> values;
}
but Gson of course doesn't know how to convert the JSON to that type of data structure.
Any help would be highly apprectiated :)

You can register your own converter. It would look a little like this:
public class ConditionConverter implements JsonSerializer<Condition>, JsonDeserializer<Condition>
{
#Override
public JsonElement serialize(Condition src, Type typeOfSrc, JsonSerializationContext context)
{
final JsonObject cond = new JsonObject()
cond.add(src.key, context.serialise(src.values);
return cond;
}
public Condition deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException
{
// pick apart and make a condition again
}
}
You then register the type adapter with your GsonBuilder:
builder.registerTypeAdapter(Condition.class, new ConditionConverter());
To pick apart your object, you'll need to use JsonObject.entrySet(), as you don't know the key name beforehand. Your job would be slightly easier if you adopted JSON like this:
{
key: "exampleType",
values: [ 42, 43 ]
}

Related

GSON serialization fails with custom Objects

I have the following class
public class Strassennetz {
private ObservableMap<Position, Strassenabschnitt> abschnitte;
private Map<Position, List<Auto>> autos;
private SimpleListProperty<Auto> autoList;
private BooleanProperty simuliert;
private String name;
public static Strassennetz instance;
...
}
which I want to serialize and deserialize with GSON/FxGson:
Gson gsonBuilder = FxGson.coreBuilder()
.registerTypeAdapter(Strassenabschnitt.class, StrassenAdapter.getInstance())
.enableComplexMapKeySerialization()
.setPrettyPrinting()
.create();
String jsonResult = gsonBuilder.toJson(instance);
The StrassenAdapter was necessary to (de-)serialize the abstract class Strassenabschnitt correctly.
That serialization works as expected when I set the fields "autos" and "autoList" transient.
As soon as I want to include those fields in my serialization (which is very important), I get the following exception:
Exception in thread "JavaFX Application Thread"
java.lang.IllegalArgumentException: class
com.sun.javafx.util.WeakReferenceQueue$ListEntry declares multiple
JSON fields named next
The class Auto looks like that:
public class Auto {
public enum AutoModell {ROT, POLIZEI, BLAU}
private int geschwindigkeit;
private static final int MAXGESCHWINDIGKEIT = 8;
private SimpleObjectProperty<Himmelsrichtung> richtung = new SimpleObjectProperty<>();
private Queue<Wendepunkt> wendepunkte;
private SimpleIntegerProperty positionX;
private SimpleIntegerProperty positionY;
private int breite;
private int laenge;
private AutoModell autoModell;
private final transient Strassennetz strassennetz;
private Rectangle rectangle;
...
}
I went through three google search result pages looking for an answer, but I do not get it to work.
GSON really does not play nicely with JavaFX properties, because it fails to properly respect encapsulation. The default way GSON serializes and object is to use reflection to recursively get the values of fields, rather than getting values of properties (as defined by get/set methods).
In a JavaFX application, JavaFX properties are typically used in the data model to implement "enhanced java beans" (where the enhancement is the ability to register listeners with the properties, etc.)
Consider a typical JavaFX bean-type class:
public class Item {
private final StringProperty name = new SimpleStringProperty();
private final IntegerProperty value = new SimpleIntegerProperty();
public StringProperty nameProperty() {
return name ;
}
public final String getName() {
return nameProperty().get();
}
public final void setName(String name) {
nameProperty().set(name);
}
public IntegerProperty valueProperty() {
return value ;
}
public final int getValue() {
return valueProperty().get() ;
}
public final void setValue(int value) {
valueProperty().set(value);
}
}
If you imagine serializing instances of this class "by hand", you would not be interested in the internal implementation of the name and value properties, or any listeners registered on those properties; you would be only interested in serializing the values represented by the properties (i.e. the values returned by getName() and getValue()). To deserialize an Item instance, you would simply instantiate an Item, and call setName() and setValue() with the serialized values.
If you try using GSON "as-is" to serialize, say, a list of such Item instances:
public class App {
public static void main(String[] args) throws Exception {
Random rng = new Random();
rng.setSeed(42);
List<Item> items = new ArrayList<>();
for (int i = 1 ; i <= 5 ; i++) {
Item item = new Item();
item.setName("Item "+i);
item.setValue(rng.nextInt(100));
item.valueProperty().addListener((obs, oldValue, newValue) -> System.out.println(newValue));
items.add(item);
}
Gson gson = new GsonBuilder().setPrettyPrinting().create();
String gsonJson = gson.toJson(items);
System.out.println(gsonJson);
}
}
You get the following:
[
{
"name": {
"name": "",
"value": "Item 1",
"valid": false
},
"value": {
"name": "",
"value": 30,
"valid": true,
"helper": {
"observable": {}
}
}
},
{
"name": {
"name": "",
"value": "Item 2",
"valid": false
},
"value": {
"name": "",
"value": 63,
"valid": true,
"helper": {
"observable": {}
}
}
},
{
"name": {
"name": "",
"value": "Item 3",
"valid": false
},
"value": {
"name": "",
"value": 48,
"valid": true,
"helper": {
"observable": {}
}
}
},
{
"name": {
"name": "",
"value": "Item 4",
"valid": false
},
"value": {
"name": "",
"value": 84,
"valid": true,
"helper": {
"observable": {}
}
}
},
{
"name": {
"name": "",
"value": "Item 5",
"valid": false
},
"value": {
"name": "",
"value": 70,
"valid": true,
"helper": {
"observable": {}
}
}
}
]
Notice how the internal elements of the StringProperty and IntegerProperty are serialized, including the listeners, which are almost certainly irrelevant to the data that you want to persist or transmit.
In your exception, you see the serialization of the listeners causing an exception (somewhere it appears you have a binding or an explicit weak listener registered on one or more of the properties: the weak listener cannot be serialized).
Worse, this cannot be deserialized:
List<Item> itemsFromGson = gson.fromJson(gsonJson, new TypeToken<List<Item>>() {}.getType());
generates an exception, because StringProperty and IntegerProperty cannot be constructed.
One solution here is to define custom serializers and deserializers for the StringProperty and IntegerProperty (and other Property) classes, which simply serialize and deserialize the contained value:
public class App {
public static void main(String[] args) throws Exception {
Random rng = new Random();
rng.setSeed(42);
List<Item> items = new ArrayList<>();
for (int i = 1 ; i <= 5 ; i++) {
Item item = new Item();
item.setName("Item "+i);
item.valueProperty().set(rng.nextInt(100));
item.valueProperty().addListener((obs, oldValue, newValue) -> System.out.println(newValue));
items.add(item);
}
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(StringProperty.class, new JsonSerializer<StringProperty>() {
#Override
public JsonElement serialize(StringProperty src, Type typeOfSrc, JsonSerializationContext context) {
return new JsonPrimitive(src.get());
}
});
gsonBuilder.registerTypeAdapter(StringProperty.class, new JsonDeserializer<StringProperty>() {
#Override
public StringProperty deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) {
return new SimpleStringProperty(json.getAsJsonPrimitive().getAsString());
}
});
gsonBuilder.registerTypeAdapter(IntegerProperty.class, new JsonSerializer<IntegerProperty>() {
#Override
public JsonElement serialize(IntegerProperty src, Type typeOfSrc, JsonSerializationContext context) {
return new JsonPrimitive(src.get());
}
});
gsonBuilder.registerTypeAdapter(IntegerProperty.class, new JsonDeserializer<IntegerProperty>() {
#Override
public IntegerProperty deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) {
return new SimpleIntegerProperty(json.getAsJsonPrimitive().getAsInt());
}
});
Gson gson = gsonBuilder.setPrettyPrinting().create();
String gsonJson = gson.toJson(items);
System.out.println(gsonJson);
System.out.println("\n================\n");
List<Item> itemsFromGson = gson.fromJson(gsonJson, new TypeToken<List<Item>>() {}.getType());
System.out.println(itemsFromGson);
}
}
This version generates the expected
[
{
"name": "Item 1",
"value": 30
},
{
"name": "Item 2",
"value": 63
},
{
"name": "Item 3",
"value": 48
},
{
"name": "Item 4",
"value": 84
},
{
"name": "Item 5",
"value": 70
}
]
It's perhaps worth noting that the Jackson serialization libraries, by default, use "property access", i.e. they use get and set methods to serialize and deserialize the fields. Consequently, Jackson works very nicely with bean classes that follow the standard JavaFX Property pattern (like the Item class above) as long as the properties are all read/write (i.e. they have corresponding get and set methods); extra work is needed for read-only properties.
I just had to put Rectangle (in my Auto-class) as a transient variable. FxGson can handle JavaFX-Properties, but not Shape instances. So I ignored that field on serialization and made sure, that I initialized that field on another way.

How to deserialize a JSON file ( using Google JSON) consisting of same key name but uses different type?

Consider the following JSON File:
{
"version": "1.0",
"firstData": {
"meta": "this is string",
"version": "1"
},
"SecondData": {
"meta": ["string1", "string2", "string3"],
"version": "1"
},
"ThirdData": {
"meta": true,
"version": "1"
},
"FourthData": {
"meta": [true, false, false, true],
"version": "1"
},
"FifthData": {
"meta": [{
"meta": "string",
"version": "2"
},
{
"meta": ["string1","string2"],
"version": "2"
}]
"version": "1"
}
}
As seen, The "meta" attribute has different data type, sometimes it is String, sometimes it is ArrayOfString, sometimes Boolean etc.
Since my JSON file has several data,
I want it to follow the following Structure :
class information
{
String version;
HashMap<String,Data> details;
}
class Data
{
variable meta;
String version;
}
How do I create a corresponding POJO and deserialize it using Google GSON?
Just define your meta as JsonElement. Then you will have sort methods like: getAsString, getAsBoolean, getAsJsonObject, getAsJsonArray, ..., and also you are able to deserialize it again after you find out what is the type.
So your class could look like:
public class SomeClass {
private int version;
private JsonElement meta;
//getters and setters and other stuff
}
Edit: More elaboration and implementation
Define two classes: GeneralItem and GeneralData
class GeneralItem
{
public final int version;
public final JsonElement meta;
}
class GeneralData
{
public final String version;
public final Map<String, GeneralItem> items;
public GeneralData(String version, Map<String, GeneralItem> items)
{
this.version = version;
this.items = items;
}
}
And then we define a custom deserializer for our GeneralData:
class GeneralDataDeserializer implements JsonDeserializer<GeneralData>
{
#Override
public GeneralData deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException
{
final JsonObject object = json.getAsJsonObject();
final String version = object.get("version").getAsString();
object.remove("version");
HashMap<String, GeneralItem> items = new HashMap<>(object.size());
for (Map.Entry<String, JsonElement> item : object.entrySet())
items.put(item.getKey(), context.deserialize(item.getValue(), GeneralItem.class));
return new GeneralData(version, items);
}
}
Finally registering the deserializer to our gson instance and getting the data:
final Gson gson = new GsonBuilder()
.registerTypeAdapter(GeneralData.class, new GeneralDataDeserializer())
.create();
final String json = "your json here";
final GeneralData data = gson.fromJson(json, GeneralData.class);
System.out.println(data.items.get("firstData").meta.getAsString());
//other parts you want
(Note that constructors, getter and setters, error checking, etc. are removed for the sake of brevity)

Bucket lifecycle configuration using json

I am trying to apply Lifecycle Configurations on S3 bucket. Trying to apply using following JSON:
[{
"id": "tmpdelete",
"status": "Enabled",
"filter": {
"predicate": {
"prefix": "tmp"
}
},
"transitions": [{
"days": "1",
"storageClass": "GLACIER"
}],
"noncurrentVersionTransitions": [{
"days": "1",
"storageClass": "GLACIER"
}],
"expirationInDays": "2",
"noncurrentVersionExpirationInDays": "2",
"expiredObjectDeleteMarker": "true"
}]
When i am trying to map it with Rule[].class it is not working. I am using following code:
String json = above_json;
Rule[] rules = null;
Gson gson = new GsonBuilder().serializeNulls().excludeFieldsWithModifiers(Modifier.FINAL,
Modifier.TRANSIENT, Modifier.STATIC, Modifier.ABSTRACT).create();
rules = gson.fromJson(json, Rule[].class);
try {
amazonS3.setBucketLifecycleConfiguration(bucketName, new BucketLifecycleConfiguration().withRules(rules));
} catch (Exception e) {
throw e;
}
It throws error saying Failed to invoke public com.amazonaws.services.s3.model.lifecycle.LifecycleFilterPredicate() with no args. LifecycleFilterPredicate is an abstract class which implements Serializable and it doesn't have no-args contructor. How to solve this problem.?
Ok, I think I found your problem: when GSON tries to construct the objects from that json string into an actual object (or, in this case, a list of objects), the process fails because when it gets to the filter.predicate bit, it probably tries to do something like this:
LifecycleFilterPredicate predicate = new LifecycleFilterPredicate();
predicate.setPrefix("tmp");
Which doesn't work because LifecycleFilterPredicate doesn't have a public constructor without any arguments, as you've stated.
I think that, unfortunately, your only solution is to parse the JSON in a different way.
UPDATE
You'll need to make use of a GSON TypeAdapter as follows:
class LifecycleFilterPredicateAdapter extends TypeAdapter<LifecycleFilterPredicate>
{
#Override
public LifecycleFilterPredicate read(JsonReader reader)
throws IOException
{
if (reader.peek() == JsonToken.NULL) {
reader.nextNull();
return null;
}
reader.beginObject();
if(!"prefix".equals(reader.nextName()))
{
return null;
}
String prefix = reader.nextString();
LifecyclePrefixPredicate predicate = new LifecyclePrefixPredicate(prefix);
reader.endObject();
return predicate;
}
#Override
public void write(JsonWriter writer, LifecycleFilterPredicate predicate)
throws IOException
{
//nothing here
}
}
...
Gson gson = new GsonBuilder().serializeNulls().excludeFieldsWithModifiers(Modifier.FINAL,
Modifier.TRANSIENT, Modifier.STATIC, Modifier.ABSTRACT)
.registerTypeAdapter(LifecycleFilterPredicate.class, new LifecycleFilterPredicateAdapter()).create();
I've tried it locally and don't get the exception anymore :)
I tried this and it worked for me
public class RuleInstanceCreator implements InstanceCreator<LifecycleFilterPredicate> {
#Override
public LifecycleFilterPredicate createInstance(Type type) {
return new LifecycleFilterPredicate() {
private static final long serialVersionUID = 1L;
#Override
public void accept(LifecyclePredicateVisitor lifecyclePredicateVisitor) {
}
};
}
}
Gson gson = new GsonBuilder()
.registerTypeAdapter(LifecycleFilterPredicate.class, new LifecycleFilterPredicateAdapter()).create();
rules = gson.fromJson(json, Rule[].class);

How to parse dynamic json in android with retrofit 2 using annotations

I have a JSON structure which I want to parse using retrofit 2 (#Expose). Below I have mentioned the JSON. Need help to parse it using dynamic annotations.
{
"status": 1,
"message": "success",
"data" : [
{
"type": 1,
"heading": "",
"description": "",
"created_on": 141123213,
"author_id": 123,
"author_name": "some name",
"author_pic": "some_pic",
"read_time": "3.1 min",
"post_pic_url": "",
"post_web_url": "",
"isLiked": false,
"isSaved": false,
"totalLikes": 12
},
{
"type": 2,
"author_id": 123,
"author_name": "some name",
"author_pic": "some pic",
"author_about": "",
"tags":[
"travel", "weekends"
],
"isFollowing": false
},
{
"type": 3,
"poll_name": "Some name",
"poll_options": [
"opt1", "opt2", "opt3"
],
"author_id": 123,
"author_name": "some name",
"author_pic": "some pic",
"isLiked": true,
"isFollowing": false
},
{
"type": 4,
"ad_url": "url",
"ad_pic": "pic"
},
{
"type": 5,
"tags": [
"tag1", "tag2", "tag3"
]
}
]
}
I have updated the JSON structure with all 5 types.
1 Use Retrofit convert
example GSON convert
2 Add com.squareup.retrofit2:converter-gson in gradle file
3 Add converter factory in Retrofit object
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(Ws_Url)
.addConverterFactory(GsonConverterFactory.create())
.client(clientBuilder.build())
.build();
4 Create Model class for Your response
Use below link to generate model class
http://www.jsonschema2pojo.org/
Retrofit does not do serialization and deserialization, but Gson does.
You might want to use RuntimeTypeAdapterFactory from the Google Gson extras package.
It's not published at artifact repositories, and you can simply copy the code to your project.
If type adapters are somewhat complex (as they work with JSON streams), you might find JsonDeserializer<T> easier to use and probably maintain (they work with JSON trees consuming some more memory, but it's the only way to go here anyway).
Define your mappings similar to:
// There might be no the common root, and target lists might be parameterized with Object, but it's up to you
abstract class Element {
final int type = Integer.valueOf(0);
// Since the number of types is really finite, we can define all known types in one place
private Element() {
}
static final class Type1Element
extends Element {
// the rest of properties go here
// Gson does not need constructors, neither we do (at least public ones)
private Type1Element() {
}
}
static final class Type2Element
extends Element {
// the rest of properties go here
private Type2Element() {
}
}
}
final class Response<T> {
final int status = Integer.valueOf(0);
final String message = null;
final T data = null;
}
Now the deserializer itself:
final class ElementJsonDeserializer
implements JsonDeserializer<Element> {
private static final JsonDeserializer<Element> elementJsonDeserializer = new ElementJsonDeserializer();
private ElementJsonDeserializer() {
}
// The deserializer is essentially a singleton, but we hide away this fact making sure that only 1 instance exists
static JsonDeserializer<Element> getElementJsonDeserializer() {
return elementJsonDeserializer;
}
#Override
public Element deserialize(final JsonElement jsonElement, final Type type, final JsonDeserializationContext context)
throws JsonParseException {
final int typeCode = jsonElement.getAsJsonObject().getAsJsonPrimitive("type").getAsInt();
// Simple dispatching here
// RuntimeTypeAdapterFactory basically does the same
switch ( typeCode ) {
case 1:
return context.deserialize(jsonElement, Type1Element.class);
case 2:
return context.deserialize(jsonElement, Type2Element.class);
default:
throw new JsonParseException("Unrecognized type: " + typeCode);
}
}
}
Now get it all working together (response.json is your JSON document resource):
private static final Type type = new TypeToken<Response<List<Element>>>() {
}.getType();
private static final Gson gson = new GsonBuilder()
.registerTypeAdapter(Element.class, getElementJsonDeserializer())
.create();
public static void main(final String... args)
throws IOException {
try ( final JsonReader jsonReader = getPackageResourceJsonReader(Q43802350.class, "response.json") ) {
final Response<List<Element>> response = gson.fromJson(jsonReader, type);
response.data
.stream()
.map(Element::getClass)
.map(Class::getSimpleName)
.forEach(System.out::println);
}
}
Output:
Type1Element
Type2Element
Of course, don't forget to register the gson instance with GsonConverterFactory.create(gson) in your Retrofit builder.

Deserialize Generic class Jackson or Gson

From the land of .NET I have a generic class define like so..
public class SyncWrapper<T, I>
{
public IList<T> Data { get; set; }
public IList<I> DeleteIds { get; set; }
public DateTime LastSyncDateTime { get; set; }
}
I was able to create an instance of this object from json by simply calling ...
JsonConvert.DeserializeObject<SyncWrapper<T, Guid>>(json);
Now I've been given the task of porting this code over to Java/Android. Having never touched Java before, I've a lot to learn!
Anyway, so far I've tried Gson and Jackson to get the object from json but no joy. I think that I won't be able to call andthing with the <T> involved gson.fromJson(json, SyncWrapper<T, UUID>.class) for example as there is a problem with type Erasure!
My efforts so far have looked like this....
Gson
Gson gson = new Gson();
SyncWrapper<MyClass, UUID> result = gson.fromJson(json, new TypeToken<SyncWrapper<MyClass, UUID>>() { }.getType());
This compiles but the result is an empty SyncWrapper
Jackson
ObjectMapper mapper = new ObjectMapper();
SyncWrapper<MyClass, UUID> result = mapper.readValue(json, new TypeReference<SyncWrapper<MyClass, UUID>>() { });
This compiles but crashes the app when executed!!!
My Java version of SyncWrapper....
public class SyncWrapper<T, I> {
private DateTime lastSyncDateTime;
private Collection<T> data;
private Collection<I> deleteIds;
public Collection<T> getData() {
return data;
}
public void setData(Collection<T> data) {
this.data = data;
}
public Collection<I> getDeleteIds() {
return deleteIds;
}
public void setDeleteIds(Collection<I> deleteIds) {
this.deleteIds = deleteIds;
}
public DateTime getLastSyncDateTime() {
return lastSyncDateTime;
}
public void setLastSyncDateTime(DateTime lastSyncDateTime) {
this.lastSyncDateTime = lastSyncDateTime;
}
}
I've been really thrown in at the deep end by the powers that be (all programming is the same isn't it?), so any help really appreciated.
I'm not precious about which library I use (Gson, Jackson, etc)
Update
An example of the Json that is to be deserialized...
{
"Data": [
{
"Name": "Company A",
"Id": "7d5d236c-c2b5-42dc-aea5-99e6752c8a52"
},
{
"Name": "Company B",
"Id": "44444444-0000-0000-0000-444444444444"
},
{
"Name": "Company C",
"Id": "249a4558-05c6-483f-9835-0056804791c9"
}
],
"DeleteIds": [
"5f7873a6-b2ee-4566-9714-1577b81384f4",
"1f224a39-16c3-441d-99de-8e58fa8f31c2"
],
"LastSyncDateTime": "\/Date(1393580073773+0000)\/"
}
..or this (more often than not, the DeleteIds will be null)...
{
"Data": [
{
"Name": "Company A",
"Id": "7d5d236c-c2b5-42dc-aea5-99e6752c8a52"
},
{
"Name": "Company B",
"Id": "44444444-0000-0000-0000-444444444444"
},
{
"Name": "Company C",
"Id": "249a4558-05c6-483f-9835-0056804791c9"
}
],
"DeleteIds": null,
"LastSyncDateTime": "\/Date(1393580073773+0000)\/"
}
For the above json I would be mapping to a SyncWrapper where T is Company...
public class Company extends ModelBase {
private String name;
public Company(UUID id, String name) {
super(id);
setName(name);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Here's the issues:
Your field names in your Java classes don't match the field names in the JSON; capitalization matters. This is why you're getting back absolutely nothing after parsing.
I'm going to go with Gson examples simply because I know that off the top of my head. You can do the same things in Jackson, but I'd need to look them up:
public class SyncWrapper<T, I> {
#SearializedName("LastSyncDateTime")
private DateTime lastSyncDateTime;
#SearializedName("Data")
private Collection<T> data;
#SearializedName("DeleteIds")
private Collection<I> deleteIds;
This tells Gson which fields in Java map to the fields in JSON. You could also go with a field naming policy instead, since it looks like all your fields are upper camel case:
Gson g = new GsonBuilder()
.setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE)
.build();
Now your fields will match up. The next issue is going to be that UUID class. That class in Java is not a string; it's a class that generates UUIDs. Just use String for the type that holds it in your Java class.
The DateTime class ... same issue. And on top of that you've got a bit of a weird value in your JSON for the date. You'll either want to store that as a String as well, or you're going to have to write a custom deserializer to deal with it.
With those changes, I think you're good to go.
Edit to add from the comments: If you really need the Java UUID class rather than just the String representation, you can write a chunk of code that takes care of this for you:
class UUIDDeserializer implements JsonDeserializer<UUID>
{
#Override
public UUID deserialize(JsonElement je, Type type, JsonDeserializationContext jdc) throws JsonParseException
{
return UUID.fromString(je.getAsString());
}
}
You can then register this with Gson:
Gson g = new GsonBuilder()
.setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE)
.registerTypeAdapter(UUID.class, new UUIDDeserializer())
.build();
This will populate the UUID typed fields in your class with UUID instances. This is the same thing you'd need to do with that funky date value.
I suggest using Jackson for this; it has a more clear API and does not require creating a new type as Gson (where you have to extend a class to be able to do that).
Example:
public static <T> T fromJsonToGenericPojo(
String json, Class<?> classType, Class<?>... genericTypes) {
JavaType javaType = TypeFactory.defaultInstance()
.constructParametricType(classType, genericTypes);
try {
return OBJECT_MAPPER.readValue(json, javaType);
} catch (IOException e) {
LOGGER.error(e.getMessage(), e);
throw new IllegalArgumentException(e);
}
}

Categories

Resources