我正在使用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
为什么类型的映射在某些情况下是正确的而在其他情况下却不正确?有没有办法控制这个而不对我的班级做任何改变?
答案 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);
}
}
的源代码