在Jackson上使用TypeReference

时间:2014-10-05 09:07:01

标签: java jackson

以下测试失败

java.util.LinkedHashMap cannot be cast to org.dabd.mapping2.MapperImplNGTest$Foo
java.lang.ClassCastException
    at org.dabd.mapping2.MapperImplNGTest.testFromMap(MapperImplNGTest.java:82)

我能找到的唯一解决方案是将fromMap签名更改为T fromMap(S map, Class<T> clazz),但我认为没有必要明确地传递该类。 TypeReference不足以实例化类型T吗?感谢。

import java.util.Map;

public interface Mapper<T extends Object, S extends Map<String, Object>> {
    public S toMap(T obj);
    public T fromMap(S map);
}


import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.Map;

public class MapperImpl<T extends Object, S extends Map<String, Object>>
        implements Mapper<T, S> {

    public S toMap(T obj) {
        ObjectMapper objectMapper = new ObjectMapper();
        Map<String, Object> map = objectMapper.convertValue(obj, Map.class);
        return (S) map;
    }

    public T fromMap(S map) {
        ObjectMapper objectMapper = new ObjectMapper();
        T obj = objectMapper.convertValue(map, new TypeReference<T>() {
        });
        return obj;
    }

}

测试

import java.util.HashMap;
import java.util.Map;
import static org.testng.Assert.*;
import org.testng.annotations.Test;


public class MapperImplNGTest {

    public static class Foo {

        private String a;

        public String getA() {
            return a;
        }

        public void setA(String a) {
            this.a = a;
        }

    }

    public MapperImplNGTest() {
    }

    @Test
    public void testFromMap() {

        Map<String, Object> map = new HashMap<String, Object>();
        map.put("a", "aa");

        MapperImpl<Foo, Map<String, Object>> mapper = new MapperImpl<Foo, Map<String, Object>>();
        Foo foo = mapper.fromMap(map);
        assertEquals(foo.getA(), map.get("a"));

    }

}

2 个答案:

答案 0 :(得分:2)

不,您不能以T方式使用TypeReference等类型变量:您必须传递实际参数化。这是因为这里没有与T相关的运行时信息:它只是一个占位符。所以它被有效地视为java.lang.Object

但您可以使用TypeFactory以编程方式构建结构化类型(其实例可通过ObjetMapper.getTypeFactory()获得)。您仍然需要表示键和值类型的Class个实例,但有了这些信息,就可以构造包含您需要的完整类型信息的JavaType值。

答案 1 :(得分:0)

你可以这样做

public T fromMap(S map, TypeReference<T> typeReference) { 
        ObjectMapper objectMapper = new ObjectMapper();
        T obj = objectMapper.convertValue(map, typeReference);
        return obj;
    }