views:

83

answers:

4

Hi

I am de-serializing a JSON object with the ObjectMapper class in java. I am getting objects of different types (? extends Something) and wanted to know if there is any way to de-serialize them in some generic way. The readValue method gets some Class type object of the type of the output object so it is somehow strongly typed.

A: 

Have you tried JSON in Java?

Thierry-Dimitri Roy
It does not object-binding, just DOM-like trees.
StaxMan
A: 

I have been using Json-lib library to accomplish this goal and was quite pleased with the results. Have look at the library examples http://json-lib.sourceforge.net/ You can register custom morphers that would transform nested elements of json into proper classes. I was able to get pretty complicated structures from json to java and access all nested fields.

Hope it helps

Greg
Thats a nice solution , I might consider using it in future
Roman
+1  A: 

Jackson can take not only type-erased class as target type, but also TypeReference which uses the usual "super type token" pattern. From Jackson FAQ:

List<MyBean> result = mapper.readValue(src, new TypeReference<List<MyBean>>() { });

and this works for all kinds of generic types, not just Maps and Collections. This in case you were thinking of generic types; so that you just have a single class but multiple parametric variations.

But it sounds like maybe what you want is actually support for deserializing polymorphic types; and this is also support (as of Jackson 1.5, see http://wiki.fasterxml.com/JacksonPolymorphicDeserialization).

EDIT: given sample classes in the other answer, Jackson way would be to do:

import org.codehaus.jackson.annotate.JsonTypeInfo;

@JsonTypeInfo(use=JsonTypeInfo.Id.CLASS)
public abstract class Message
{
    protected Message(){ }
}

and deserialize by:

Message msg = objectMapper.readValue(json, Message.class);

to get any sub-class of Message. And serialize using 'objectMapper.writeValue();'

StaxMan
A: 

Here is an answer I came to:

First of all I have switched from ObjectMapper to Gson. Define an abstract class and an enum of types:

public abstract class Message {

    private MessageType type;

    protected Message(){
        type = setType();
    }

    protected abstract MessageType setType();

    public MessageType getType() {
        return type;
    }

    public void setType(MessageType type) {
        this.type = type;
    }

}

public enum MessageType {

   PRESENCE(PresenceMessage.class),
   TEXT(TextMessage.class);

   private Class<? extends Message> clazz;

   private MessageType(Class<? extends Message> clazz){
       this.clazz = clazz;
   }

   public Class<? extends Message> getClazz() {
      return clazz;
   }
}

Every class that extends the Message is the actual one we are sending over Json. It has to implement the getType() method.

So when desirializing just use that code :

    String line;
    BufferedReader reader = new BufferedReader(new InputStreamReader(get.getResponseBodyAsStream(),"UTF-8"));
    while ((line = reader.readLine()) != null){
        builder.append(line);
    }
    if (clazz == Message.class){
        String string = builder.toString();
        Message message = gson.fromJson(string,Message.class);
        if (message.getType() == null)
            throw new IllegalStateException("Could not de-serialize message " + builder.toString() );
        return (T)gson.fromJson(string,message.getType().getClazz());
    }

I hope you can fill the missing parts by yourself.

Roman
Lots of work for something Jackson could do automatically with just a single @JsonTypeInfo annotation on base class. :)But good luck with that solution at any rate!
StaxMan
You are the man....!! Thanks a lot
Roman
You should write it as an answer , so i can accept it.
Roman