Determining the type of an object from JSON and creating an object using GSON

I use Gson in my application, where I have several Java objects that I represent in the front-end, by converting it to JSON using GSON. I know how to convert JSON back to a Java object using gson.

I have this use case: When I pass a specific JSON string to GSON, I want it to find the type of object from which the JSON string was obtained, and give me an object of that type.

Using GSON, I can only return an object back if I pass the Object class in the fromJson method. But still, can I do gson to determine this on my own? I have no control over objects generated on the other hand.

Example:

 Person person = new Person(); SomeRandomObject obj = new SomeRandomObject(); String personJson = gson.toJson(person); String anotherJson = gson.toJson(obj); 

Now, if I want to convert it back to an object, I use this:

 Person p = gson.fromJson(personJson,Person.class); 

But still, I can get the object as follows:

 Object object = gson.fromJson(anotherJson,*TheCorrespondingObject.class*) 

I know that I can achieve this by trying my JSON string with different objects on which Gons throws an exception, but I don't think this is the right way to do this.

+4
source share
3 answers

The best, easiest way is to wrap the JSON itself in a container containing this type.

For instance:

 { "foo":"bar" } 

becomes

 { "type":"FooContainer" "value": { "foo":"bar" } } 

However, you said that you cannot do this, so I will not go into details about how to actually deserialize. If you can make this limited change, you can write a TypeAdapterFactory and let Gson do the rest of the work by using the passed Gson object in the create() method and gson.fromJson() in the read method, which will be much less code than the method below.


Think about what really needs to happen here. Somehow you need to determine what data is in the MQ Websphere objects and use it to figure it out. Finding it this way is going to take the code, analyze what data you received, and spit out the correct object.

The first problem you will encounter is that you do not want to do this:

 Object myObj = gson.fromJson(jsonString, Object.class); 

This means that you are redefining the default base deserializer, which can have all kinds of unpleasant side effects. It is better to wrap the behavior in a TypeAdapter for a kind of custom object:

 public class Wrapper { public Object data; // Encapsulate this if you want, this is just for brevity } 

I will leave you casting / generics. There are many ways to do this, but I recommend the Visitor Template as a good choice, or perhaps create an object of type enum . It would be better if all the resulting object types implemented some kind of interface to make it easier, but, again, this is not your main problem.

Your main problem is that they really detect these classes in code. Now that we have a wrapper class, we can use this:

 Wrapper myWrapper = gson.fromJson(jsonString, Wrapper.class); 

Now each class generated is the same class, so Gson is happy. But where do we set the rules? They go in your regular TypeAdapter :

 public class WrapperTypeAdapter extends TypeAdapter<Wrapper> { @Override public final void write(JsonWriter out, Wrapper value) throws IOException { if(value == null) { out.nullValue(); return; } // Don't worry about Write for now, obviously } @Override public final Wrapper read(JsonReader in) throws IOException { if(in.peek() == JsonToken.NULL) { in.nextNull(); return null; } Wrapper wrapper = new Wrapper(); // HERE IS WHERE YOU GET TO WRITE CODE return wrapper; } } 

In the read method, when you are stream tokens, you can use the rules based on what you expect from the JSON tokens themselves to decide which class it will be, and then build a new object. I recommend breaking this down into many methods like MyFoo readMyFoo(JsonReader) , MyBar readMyBar(JsonReader) , etc. I find it difficult to go into much more detailed information without knowing more about JSON itself, but this should be enough to get you started.

+5
source

General answer: you need to add something to the generated JSON to indicate what it was created from.

Let's say instead

 { "name": "John" } 

You would create something like:

 { "type": "Customer" "name": "John" } 

How to do it in GSON remains as an exercise for the reader .;)


Edit: Oh, you cannot interfere with JSON. Then Nevermind.

However, it would be difficult to do this in general terms without any identifier, especially considering that some classes may have exactly the same fields.

0
source

Manually parsing the source string:

 if (jsonString.indexOf(..) > 0) { //reading Person } else { //reading SomeRandomObject } 

or you can use JSON Simple and read any JSON

0
source

All Articles