【问题标题】:Using TypeReference with Jackson将 TypeReference 与 Jackson 一起使用
【发布时间】:2014-10-05 09:07:00
【问题描述】:

以下测试因

而失败
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"));

    }

}

【问题讨论】:

    标签: java jackson


    【解决方案1】:

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

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

    【讨论】:

    • 您能否展示使用ObjectMapper.getTypeFactory() 解决我的问题的工作代码?谢谢。
    • 看看它的构造JavaTypes的方法。例如,要获得 Map&lt;String,Integer&gt; 的等价物,您可以使用 JavaType siMapType = typeFactory.constructMapType(Map.class, String.class, Integer.class)。然后传递这个而不是TypeReferenceClass。正如他们所说,休息留给读者作为练习......
    • 我之前试过这个,但问题是我的类型 T 是一个通用的 POJO。我应该使用哪种 typeFactory.construct* 方法?
    • 如果不是Map、数组或Collection,则应使用constructParametricType
    • 你能给我看一个测试用例吗?谢谢。
    【解决方案2】:

    你可以这样做

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

    【讨论】:

    • 请解释你的代码是做什么的以及它是怎么做的。
    猜你喜欢
    • 2016-04-07
    • 1970-01-01
    • 1970-01-01
    • 2014-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-09
    • 2015-09-12
    • 1970-01-01
    相关资源
    最近更新 更多