Java Jackson默认类型映射

时间:2014-11-05 08:47:48

标签: java types jackson

我正在使用Jackson 2.4将POJO转换为地图。我写了一个小测试程序,如下所示。

import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.Map;

public class TestObjectMapper {

    private Object byteVal;
    private Object shortVal;
    private Object intVal;
    private Object longVal;
    private Object floatVal;
    private Object doubleVal;

    public TestObjectMapper() {
        byteVal = (byte) 127;
        shortVal = (short) 255;
        intVal = 10;
        longVal = 20L;
        floatVal = 1.2F;
        doubleVal = 1.4;
        System.out.println("Constructor");
        System.out.println("byteVal.getClass() = " + byteVal.getClass());
        System.out.println("shortVal.getClass() = " + shortVal.getClass());
        System.out.println("intVal.getClass() = " + intVal.getClass());
        System.out.println("longVal.getClass() = " + longVal.getClass());
        System.out.println("floatVal.getClass() = " + floatVal.getClass());
        System.out.println("doubleVal.getClass() = " + doubleVal.getClass());
        System.out.println();
    }

    public Object getByteVal() {
        return byteVal;
    }

    public Object getShortVal() {
        return shortVal;
    }

    public Object getIntVal() {
        return intVal;
    }

    public Object getLongVal() {
        return longVal;
    }

    public Object getFloatVal() {
        return floatVal;
    }

    public Object getDoubleVal() {
        return doubleVal;
    }

    public static void main(String[] args) {
        ObjectMapper mapper = new ObjectMapper();
        TestObjectMapper t = new TestObjectMapper();
        Map map = mapper.convertValue(t, Map.class);
        System.out.println("map = " + map);
        System.out.println();
        for (Object key : map.keySet()) {
            System.out.format("map.get(\"%s\").getClass() = %s\n", key, map.get(key).getClass());
        }
        String k = "byteVal";
        System.out.format("((Integer) map.get(\"%s\")).byteValue() = %d\n",
                k, ((Integer) map.get(k)).byteValue());
        k = "floatVal";
        System.out.format("((Double) map.get(\"%s\")).floatValue() = %f\n",
                k, ((Double) map.get(k)).floatValue());
    }

}

生成以下输出:

Constructor
byteVal.getClass() = class java.lang.Byte
shortVal.getClass() = class java.lang.Short
intVal.getClass() = class java.lang.Integer
longVal.getClass() = class java.lang.Long
floatVal.getClass() = class java.lang.Float
doubleVal.getClass() = class java.lang.Double

map = {byteVal=127, shortVal=255, intVal=10, longVal=20, floatVal=1.2000000476837158, doubleVal=1.4}

map.get("byteVal").getClass() = class java.lang.Integer
map.get("shortVal").getClass() = class java.lang.Short
map.get("intVal").getClass() = class java.lang.Integer
map.get("longVal").getClass() = class java.lang.Long
map.get("floatVal").getClass() = class java.lang.Double
map.get("doubleVal").getClass() = class java.lang.Double
((Integer) map.get("byteVal")).byteValue() = 127
((Double) map.get("floatVal")).floatValue() = 1.200000

为什么类型的映射在某些情况下是正确的而在其他情况下却不正确?有没有办法控制这个而不对我的班级做任何改变?

1 个答案:

答案 0 :(得分:2)

  

为什么类型的映射在某些情况下是正确的而在其他情况下却不正确?

这是来自Jackson的预期行为。如果您考虑JSON支持的数据类型(如下所示),则Jackson完全有理由相应地转换值的数据类型。

  • Number - 包含小数部分的带符号十进制数,可以使用指数式E表示法。 JSON不允许像NaN这样的非数字,也不允许对整数和浮点进行任何区分。 (尽管JavaScript对其所有数值使用双精度浮点格式,但实现JSON的其他语言可能会以不同方式编码数字)
  • String - 零个或多个Unicode字符的序列,但BMP之外的字符必须表示为代理项对。字符串用双引号分隔,并支持反斜杠转义语法。
  • Boolean - 值为true或false
  • Array - 零个或多个值的有序列表,每个值可以是任何类型。数组使用方括号表示法,元素以逗号分隔。
  • Object - 无序的关联数组(名称/值对)。对象用大括号分隔,并使用逗号分隔每对,而在每对内,冒号':'字符将键或名称与其值分开。所有键必须是字符串,并且在该对象中应该彼此不同。
  • null - 空值,使用单词null
  

有没有办法控制这个而不对我做任何改变   类?

在Jackson用于反序列化时可以控制它,但在序列化时不能。以下Stack Overflow回答可能对您有所帮助。

Java Jackson - prevent float to int conversion when deserializing

<强>更新

为了将一个对象转换为另一个对象,ObjectMapper首先将源对象序列化为JsonParser对象,然后将此JsonParser对象反序列化为目标类型对象。因此,它使ObjectMapper的这种行为非常明显。

/

**
     * Actual conversion implementation: instead of using existing read
     * and write methods, much of code is inlined. Reason for this is
     * that we must avoid wrapping/unwrapping both for efficiency and
     * for correctness. If wrapping/unwrapping is actually desired,
     * caller must use explicit <code>writeValue</code> and
     * <code>readValue</code> methods.
     */
    protected Object _convert(Object fromValue, JavaType toValueType)
        throws IllegalArgumentException
    {
        // sanity check for null first:
        if (fromValue == null) return null;
        /* Then use TokenBuffer, which is a JsonGenerator:
         * (see [JACKSON-175])
         */
        TokenBuffer buf = new TokenBuffer(this);
        try {
            // inlined 'writeValue' with minor changes:
            // first: disable wrapping when writing
            SerializationConfig config = getSerializationConfig().without(SerializationFeature.WRAP_ROOT_VALUE);
            // no need to check for closing of TokenBuffer
            _serializerProvider(config).serializeValue(buf, fromValue);

            // then matching read, inlined 'readValue' with minor mods:
            final JsonParser jp = buf.asParser();
            Object result;
            // ok to pass in existing feature flags; unwrapping handled by mapper
            final DeserializationConfig deserConfig = getDeserializationConfig();
            JsonToken t = _initForReading(jp);
            if (t == JsonToken.VALUE_NULL) {
                DeserializationContext ctxt = createDeserializationContext(jp, deserConfig);
                result = _findRootDeserializer(ctxt, toValueType).getNullValue();
            } else if (t == JsonToken.END_ARRAY || t == JsonToken.END_OBJECT) {
                result = null;
            } else { // pointing to event other than null
                DeserializationContext ctxt = createDeserializationContext(jp, deserConfig);
                JsonDeserializer<Object> deser = _findRootDeserializer(ctxt, toValueType);
                // note: no handling of unwarpping
                result = deser.deserialize(jp, ctxt);
            }
            jp.close();
            return result;
        } catch (IOException e) { // should not occur, no real i/o...
            throw new IllegalArgumentException(e.getMessage(), e);
        }
    }

来自http://grepcode.com/file/repo1.maven.org/maven2/com.fasterxml.jackson.core/jackson-databind/2.0.0-RC1/com/fasterxml/jackson/databind/ObjectMapper.java#ObjectMapper.convertValue%28java.lang.Object%2Cjava.lang.Class%29

的源代码