Java默认类型映射

Java默认类型映射,java,types,jackson,Java,Types,Jackson,我正在使用Jackson 2.4将POJO转换为地图/从地图转换为POJO。我编写了一个小测试程序,如下所示 import com.fasterxml.jackson.databind.ObjectMapper; import java.util.Map; public class TestObjectMapper { private Object byteVal; private Object shortVal; private Object intVal;

我正在使用Jackson 2.4将POJO转换为地图/从地图转换为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
为什么类型映射在某些情况下是正确的,而在其他情况下则不正确?有没有一种方法可以在不改变我的类的情况下控制它

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

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

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

它可以在Jackson用于反序列化时进行控制,但不能在序列化时进行控制。下面的堆栈溢出答案可能对您有所帮助

更新

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

/


源代码来自

您所说的“正确”是什么意思?当你没有在字段中声明任何特定类型时,你是否希望Jackson能读懂你的心思?你能澄清一下问题吗?到底是什么问题?区别在于字节->整数和浮点->双精度。Json中没有字节类型。所以Float和Byte将在JSON中转换为数字类型。请看,这很有意义,因为数字在Javascript中是双精度浮点格式。谢谢您的评论。是的,在本例中,我可以省略关于JSON的内容。因此,只需查看映射POJO->Map,在某些情况下,类型映射是正确的,但在其他情况下则不正确。类型信息在类的原始字段中可用。我从原始问题中删除了JSON,因为我意识到它在这里并不真正相关。我只是在说地图。谢谢你,这清楚地说明了为什么地图是这样工作的。
**
     * 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);
        }
    }