Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deserialization of generic type with Map.class #1297

Closed
arekgabiga opened this issue Jul 14, 2016 · 2 comments
Closed

Deserialization of generic type with Map.class #1297

arekgabiga opened this issue Jul 14, 2016 · 2 comments
Milestone

Comments

@arekgabiga
Copy link

There is some problem with deserialization of generic types with Map.class. Bug scenario looks like this:

package tst;

import java.util.HashMap;
import java.util.Map;

import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;

public class MapTest {
    public static class Wrapper<T> {
        private T content;

        public T getContent() {
            return content;
        }

        public void setContent(T content) {
            this.content = content;
        }
    }

    public static void main(String[] args) throws Exception {
        ObjectMapper mapper = new ObjectMapper();
        Wrapper<Map> wrapper = buildSample();
        String wrapperJson = mapper.writeValueAsString(wrapper);

        //throws NPE
        JavaType type = mapper.getTypeFactory().constructParametricType(Wrapper.class, Map.class);
        Wrapper<Map> result = mapper.readValue(wrapperJson, type);
        System.out.println(result.getContent());
    }

    private static Wrapper<Map> buildSample() {
        Map map = new HashMap<>();
        map.put("a", "b");

        Wrapper<Map> wrapper = new Wrapper<>();
        wrapper.setContent(map);
        return wrapper;
    }
}

I've checked it with version 2.7.x and 2.8.0 and that code throws NPE (stacktrace from 2.8.0):

Exception in thread "main" java.lang.NullPointerException
    at com.fasterxml.jackson.databind.type.TypeFactory._mapType(TypeFactory.java:1022)
    at com.fasterxml.jackson.databind.type.TypeFactory._fromWellKnownClass(TypeFactory.java:1313)
    at com.fasterxml.jackson.databind.type.TypeFactory._fromClass(TypeFactory.java:1262)
    at com.fasterxml.jackson.databind.type.TypeFactory.constructParametricType(TypeFactory.java:885)

However version 2.4.1 seems to work fine. What I can tell, problem exists only when Map.class is provided. What is more, when I construct JavaType mapType = mapper.getTypeFactory().constructMapType(Map.class, String.class, String.class); deserialize, and then try to deserialize using generic Map.class it works as in the sample below:

package tst;

import java.util.HashMap;
import java.util.Map;

import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;

public class MapTest {
    public static class Wrapper<T> {
        private T content;

        public T getContent() {
            return content;
        }

        public void setContent(T content) {
            this.content = content;
        }
    }

    public static void main(String[] args) throws Exception {
        ObjectMapper mapper = new ObjectMapper();
        Wrapper<Map> wrapper = buildSample();
        String wrapperJson = mapper.writeValueAsString(wrapper);

        JavaType mapType = mapper.getTypeFactory().constructMapType(Map.class, String.class, String.class);
        JavaType resultType = mapper.getTypeFactory().constructParametricType(Wrapper.class, mapType);
        Wrapper<Map> result1 = mapper.readValue(wrapperJson, resultType);
        System.out.println(result1.getContent());

        //does not throw NPE now
        JavaType type = mapper.getTypeFactory().constructParametricType(Wrapper.class, Map.class);
        Wrapper<Map> result2 = mapper.readValue(wrapperJson, type);
        System.out.println(result2.getContent());
    }

    private static Wrapper<Map> buildSample() {
        Map map = new HashMap<>();
        map.put("a", "b");

        Wrapper<Map> wrapper = new Wrapper<>();
        wrapper.setContent(map);
        return wrapper;
    }
}

Looking into the code, Map type is recognized properly, however the code assumes that TypeBindings exist, which is wrong at that state. Situation changes is the second scenario, because Map type gets loaded into the typeCache first and then it is used whenever Map type needs to be constructed.

@cowtowncoder
Copy link
Member

Thank you for reporting this. I'll see how to resolve that -- it does indeed look like the lack of type parameters for Map would trigger this (ideally it would be typed; but in absence of that, Object.class should be provided as per "raw" type handling in Java). And definitely no NPE should occur.

@cowtowncoder
Copy link
Member

I can reproduce this locally by just using resolution call.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants