Ramishka Dasanayaka Ramishka Dasanayaka - 1 year ago 65
Java Question

How to deserialize JSON string into different complex class types?

I have a JSONNode object that can contain any JSON content. Example :

"fieldA": "aStringValue",
"fieldB": 10,
"fieldC": {
"TypeAFieldA": "aValue"
"fieldD": {
"TypeBFieldA": "aValue",
"TypeBFieldB": {
"TypeCFieldA": "aValue",
"TypeCFieldB": "bValue"

I want to deserialize each JSON field in this string into different types of java objects as below :

fieldA -> String object
fieldB -> int
fieldC -> TypeA object
fieldD -> TypeB object

Assume that I know the class type that each field should deserialize into.
What is the best and most optimal way to go about this?

Edit: To further clarify my requirement :

The approach I have thought of is I have created objects for TypeA, TypeB, TypeC etc and have annotated them with relevant JsonPropery annotations.
What I am unclear about is how do I go about deserializing each field individually? For this I would need to extract the json string from the JsonNode one by one and run through an object mapper with the relevant class type?

Example: To deserialize "fieldC" and its value into a class of TypeC, don't I have to do something like :

  1. Extract full Json string :

    String jsonString = "fieldC": { "TypeAFieldA": "aValue" }";

  2. Run it through an object mapper:

    mapper.readValue( jsonString, TypeC.class );

How do I extract the full json string for each field by looping through the JsonNode? Is this the most optimal way to go about this?


Inspired by the solutions posted here, I was able to come up with my own implementation for the problem.

I wrote a function that takes in a JsonNode, and a java.lang.reflect.Type parameter. This function would check the node for each primitive and non primitive data type that I will be using in my application and deserialize it into the appropriate type.

     * This function takes in a JSON node, a type info and converts the JSON into 
     * the given type.
     * @param node - node to deserialize
     * @param typeInfo - data type to deserialize into
     * @throws JsonMappingException
     * @throws JsonParseException
     * @throws IOException
    private void deserializeNode ( JsonNode node, Type typeInfo ) throws JsonMappingException, JsonParseException, IOException {

        Object deserializedValue = null;

        if ( node.isDouble()   ) {
            deserializedValue = node.asDouble();

        } else if ( node.isInt() ) {
            deserializedValue = node.asInt();

        } else if ( node.isLong() ) {
            deserializedValue = node.asLong();

        } else if ( node.isBoolean() ) {
            deserializedValue = node.asBoolean();

        } else if ( node.isArray() ) {
            //Json array is translated into a Java List. If this is a known type, it will translate
            //into a List<Type> instance.
            CollectionType collectionType = this.getActualTypeOfCollection( typeInfo );
            deserializedValue = mapper.readValue( node.toString(),  collectionType );

        } else if ( node.isObject() ) {
            JavaType objectType = mapper.getTypeFactory().constructType( typeInfo );
            deserializedValue = mapper.readValue( node.toString(), objectType );

        } else if ( node.isTextual() ) {
            deserializedValue = node.asText();


        this.deserializedValues.add( deserializedValue );


     * This function returns the actual collection type of a generic parameter.
     * I.e. It returns the proper Collection data complete with the generic type so
     * that Jackson could determine the proper type to deserialize the field into.
     * @param genericParameterType - java parameter type
     * @return Jackson collection type
    private CollectionType getActualTypeOfCollection ( Type genericParameterType ) {

        CollectionType collectionType = null;

        if(genericParameterType instanceof ParameterizedType){

            ParameterizedType aType = (ParameterizedType) genericParameterType;
            Type[] parameterArgTypes = aType.getActualTypeArguments();
            for ( Type parameterArgType : parameterArgTypes ) {
                collectionType = mapper.getTypeFactory().constructCollectionType(List.class, (Class<?>) parameterArgType ) ;

        return collectionType;      

Comments are welcome on the pros/cons of this approach.