|
||||||||||
PREV CLASS NEXT CLASS | FRAMES NO FRAMES | |||||||||
SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |
java.lang.Object flexjson.JSONDeserializer<T>
public class JSONDeserializer<T>
JSONDeserializer takes as input a json string and produces a static typed object graph from that
json representation. By default it uses the class property in the json data in order to map the
untyped generic json data into a specific Java type. However, you are limited to only json strings
with class information embedded when resolving it into a Java type. But, for now let's just look at
the simplest case of class attributes in your json. We'll look at how JSONSerializer
and
JSONDeserializer pair together out of the box.
Say we have a simple object like Hero (see the superhero package under the test and mock). To create a json represenation of Hero we'd do the following:
Hero harveyBirdman = new Hero("Harvey Birdman", new SecretIdentity("Attorney At Law"), new SecretLair("Sebben & Sebben") ); String jsonHarvey = new JSONSerialize().serialize(hero);
Now to reconsitute Harvey to fight for the law we'd use JSONDeserializer like so:
Hero hero = new JSONDeserializer().deserialize( jsonHarvey );
Pretty easy when all the type information is included with the JSON data. Now let's look at the more difficult case of how we might reconstitute something missing type info.
Let's exclude the class attribute in our json like so:
String jsonHarvey = new JSONSerialize().exclude("*.class").serialize(hero);
The big trick here is to replace that type information when we instantiate the deserializer.
To do that we'll use the use(String, Class)
method like so:
Hero hero = new JSONDeserializer().use( null, Hero.class ).deserialize( jsonHarvey );
Like riding a horse with no saddle without our type information. So what is happening here is we've registered
the Hero class to the root of the json. The use(String, Class)
method uses
the object graph path to attach certain classes to those locations. So, when the deserializer is deserializing
it knows where it is in the object graph. It uses that graph path to look up the java class it should use
when reconstituting the object.
Notice that in our json you'd see there is no type information in the stream. However, all we had to do is point the class at the Hero object, and it figured it out. That's because it uses the target type (in this case Hero) to figure out the other types by inspecting that class. Meaning notice that we didn't have to tell it about SecretLair or SecretIdentity. That's because it can figure that out from the Hero class.
Pretty cool. Where this fails is when we starting working with interfaces, abstract classes, and subclasses. Yea our friend polymorphism can be a pain when deserializing. Why? Well if you haven't realized by now inspecting the type from our target class won't help us because either it's not a concrete class or we can't tell the subclass by looking at the super class alone. Next section we're going to stand up on our bare back horse. Ready? Let's do it.
Before we showed how the use(String, Class)
method would allow us to
plug in a single class for a given path. That might work when you know exactly which class you want to
instantiate, but when the class type depends on external factors we really need a way to specify several
possibilities. That's where the second version of use(String, ClassLocator)
comes into play. ClassLocator
allow you to use a stradegy for finding which java Class
you want to attach at a particular object path.
use(String, ClassLocator)
have access to the intermediate form of
the object as a Map. Given the Map at the object path the ClassLocator figures out which Class
Flexjson will bind the parameters into that object.
Let's take a look at how this can be done using our Hero class. All Heros have a list of super powers. These super powers are things like X Ray Vision, Heat Vision, Flight, etc. Each super power is represented by a subclass of SuperPower. If we serialize a Hero without class information embedded we'll need a way to figure out which instance to instantiate when we deserialize. In this example I'm going to use a Transformer during serialization to embed a special type information into the object. All this transformer does is strip off the package information on the class property.
String json = new JSONSerializer() .include("powers.class") .transform( new SimpleTransformer(), "powers.class") .exclude("*.class") .serialize( superhero ); Hero hero = new JSONDeserializer() .use("powers.class", new PackageClassLocator()) .deserialize( json );
All objects that pass through the deserializer must have a no argument constructor. The no argument
constructor does not have to be public. That allows you to maintain some encapsulation. JSONDeserializer
will bind parameters using setter methods of the objects instantiated if available. If a setter method
is not available it will using reflection to set the value directly into the field. You can use setter
methods transform the any data from json into the object structure you want. That way json structure
can be different from your Java object structure. The works very much in the same way getters do for
the JSONSerializer
.
Collections and Maps have changed the path structure in order to specify concrete classes for both the Collection implementation and the contained values. Normally you would use generics to specify the concrete class to load. However, if you're contained class is an interface or abstract class then you'll need to define those concrete classes using paths. To specify the concrete class for a Collection use the path to the collection. To specify the contained instance's concrete class append "values" onto the path. For example, if your collection path is "person.friends" you can specify the collection type using:
new JSONDeserializer().use("person.friends", ArrayList.class).use("person.friends.values", Frienemies.class)
Notice that append "values" onto the "person.friends" to specify the class to use inside the Collection. Maps have both keys and values within them. For Maps you can specify those by appending "keys" and "values" to the path.
Now onto the advanced topics of the deserializer. ObjectFactory
interface is the
underpinnings of the deserializer. All object creation is controlled by ObjectFactories. By default
there are many ObjectFactories registered to handle all of the default types supported. However, you
can add your own implementations to handle specialized formats. For example, say you've encoded your
Dates using yyyy.MM.dd. If you want to read these into java.util.Date objects you can register a
DateTransformer
to deserialize dates into Date objects.
Constructor Summary | |
---|---|
JSONDeserializer()
|
Method Summary | |
---|---|
T |
deserialize(Reader input)
Same as deserialize(String) , but uses an instance of
java.io.Reader as json input. |
T |
deserialize(Reader input,
Class root)
Same as deserialize(String, Class) , but uses an instance of
java.io.Reader as json input. |
T |
deserialize(Reader input,
ObjectFactory factory)
Same as deserialize(String, ObjectFactory) , but uses an instance of
java.io.Reader as json input. |
T |
deserialize(Reader input,
String path,
Class root)
Same as deserialize(java.io.Reader, Class) but it starts binding into
the instance of the given Class at the given path. |
T |
deserialize(Reader input,
String path,
ObjectFactory factory)
Same as deserialize(String, ObjectFactory) , it starts binding into
the instance of the given Class at the given path. |
T |
deserialize(String input)
Deserialize the given json formatted input into a Java object. |
T |
deserialize(String input,
Class root)
Deserialize the given json input, and use the given Class as the type of the initial object to deserialize into. |
T |
deserialize(String input,
ObjectFactory factory)
Deserialize the given json input, and use the given ObjectFactory to create the initial object to deserialize into. |
T |
deserialize(String input,
String path,
Class root)
Same as deserialize(String, Class) but it starts binding into
the instance of the given Class at the given path. |
T |
deserialize(String input,
String path,
ObjectFactory factory)
Same as deserialize(String, ObjectFactory) , it starts binding into
the instance of the given Class at the given path. |
T |
deserializeInto(Reader input,
String path,
T target)
Same as deserializeInto(String, String, Object) , but uses an instance of
java.io.Reader as json input. |
T |
deserializeInto(Reader input,
T target)
Same as deserializeInto(String, Object) , but uses an instance of
java.io.Reader as json input. |
T |
deserializeInto(String input,
String path,
T target)
Deserialize the given input into the existing object target. |
T |
deserializeInto(String input,
T target)
Deserialize the given input into the existing object target. |
JSONDeserializer<T> |
use(Class clazz,
ObjectFactory factory)
|
JSONDeserializer<T> |
use(ObjectFactory factory,
String... paths)
|
JSONDeserializer<T> |
use(String path,
Class clazz)
|
JSONDeserializer<T> |
use(String path,
ClassLocator locator)
|
JSONDeserializer<T> |
use(String path,
ObjectFactory factory)
|
Methods inherited from class java.lang.Object |
---|
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait |
Constructor Detail |
---|
public JSONDeserializer()
Method Detail |
---|
public T deserialize(String input)
input
- a json formatted string.
public T deserialize(Reader input)
deserialize(String)
, but uses an instance of
java.io.Reader as json input.
input
- the stream where the json input is coming from.
public T deserialize(String input, Class root)
input
- a json formatted string.root
- a Class used to create the initial object.
public T deserialize(Reader input, Class root)
deserialize(String, Class)
, but uses an instance of
java.io.Reader as json input.
input
- the stream where the json input is coming from.root
- a Class used to create the initial object.
public T deserialize(String input, String path, Class root)
deserialize(String, Class)
but it starts binding into
the instance of the given Class at the given path.
input
- a json format string.path
- a path to an instance of the given class.root
- the Class used to create the initial object. Must have a no-arg constructor.
public T deserialize(Reader input, String path, Class root)
deserialize(java.io.Reader, Class)
but it starts binding into
the instance of the given Class at the given path.
input
- the stream where the json input is coming from.path
- a path to an instance of the given class.root
- the Class used to create the initial object. Must have a no-arg constructor.
public T deserialize(String input, ObjectFactory factory)
input
- a json formatted string.factory
- an ObjectFactory used to create the initial object.
public T deserialize(Reader input, ObjectFactory factory)
deserialize(String, ObjectFactory)
, but uses an instance of
java.io.Reader as json input.
input
- the stream where the json input is coming from.factory
- an ObjectFactory used to create the initial object.
public T deserialize(String input, String path, ObjectFactory factory)
deserialize(String, ObjectFactory)
, it starts binding into
the instance of the given Class at the given path.
input
- a json formatted string.path
- the path two which you start binding.factory
- an ObjectFactory used to create the initial object.
public T deserialize(Reader input, String path, ObjectFactory factory)
deserialize(String, ObjectFactory)
, it starts binding into
the instance of the given Class at the given path.
input
- the stream where the json input is coming from.path
- the path two which you start binding.factory
- an ObjectFactory used to create the initial object.
public T deserializeInto(String input, T target)
input
- a json formatted string.target
- an instance to set values into from the json string.
public T deserializeInto(Reader input, T target)
deserializeInto(String, Object)
, but uses an instance of
java.io.Reader as json input.
input
- the stream where the json input is coming from.target
- an instance to set values into from the json string.
public T deserializeInto(String input, String path, T target)
input
- a json formatted string.path
- the path two which you start binding.target
- an instance to set values into from the json string.
public T deserializeInto(Reader input, String path, T target)
deserializeInto(String, String, Object)
, but uses an instance of
java.io.Reader as json input.
input
- the stream where the json input is coming from.path
- the path two which you start binding.target
- an instance to set values into from the json string.
public JSONDeserializer<T> use(String path, ClassLocator locator)
public JSONDeserializer<T> use(String path, Class clazz)
public JSONDeserializer<T> use(Class clazz, ObjectFactory factory)
public JSONDeserializer<T> use(String path, ObjectFactory factory)
public JSONDeserializer<T> use(ObjectFactory factory, String... paths)
|
||||||||||
PREV CLASS NEXT CLASS | FRAMES NO FRAMES | |||||||||
SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |