2014-11-05 133 views
0

我使用傑克遜2.4來轉換POJO /從地圖。我寫了一個小測試程序如下。Java傑克遜默認類型映射

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 

爲什麼類型在某些情況下,正確的,但不是在別人的映射?有沒有辦法控制這個,而不需要對我的類做任何改變?

+4

的源代碼你所說的 「正確」 是什麼意思?您是否希望傑克遜在您的領域沒有聲明任何特定類型時能夠閱讀您的想法? – chrylis 2014-11-05 08:50:52

+0

你能否澄清一下問題?究竟是什麼問題? – 2014-11-05 09:00:04

+0

差異是Byte-> Integer和Float-> Double。 Json中沒有Byte類型。所以Float和Byte將被轉換爲JSON中的Number類型。 請參閱http://www.tutorialspoint.com/json/json_data_types.htm,因此Number是JavaScript中的雙精度浮點格式 – nomoa 2014-11-05 09:23:26

回答

2

爲什麼類型的映射在某些情況下是正確的,但在其他情況下卻不正確?

這是從Jackson預計的行爲。如果考慮到JSON支持的數據類型(如下所示),那麼Jackson將相應地轉換值的數據類型是完全合理的。

  • Number - 可能包含一個小數部分,可以使用指數E符號有符號十進制數。 JSON不允許像NaN這樣的非數字,也不會在整數和浮點之間做任何區分。 (即使JavaScript對其所有數字值使用雙精度浮點格式,實現JSON的其他語言也可能對數字編碼的方式不同)
  • String - 零個或多個Unicode字符序列,儘管BMP之外的字符必須被表示爲代理對。字符串用雙引號分隔,並支持反斜槓轉義語法。
  • Boolean - 任一值的真或假
  • Array - 零個或更多個值,其中的每一個可以是任何類型的一個有序列表。數組以逗號分隔的元素使用方括號表示法。
  • Object - 一個無序的關聯數組(名稱/值對)。對象使用大括號分隔,並使用逗號分隔每對,而在每對中,冒號「:」字符將鍵或名稱與其值分開。所有的鍵都必須是字符串,並且在該對象內應該彼此不同。
  • null - 一個空值時,用的是空

有控制這個沒有做我的 類的任何改變的一種方式?

它可以控制,而傑克遜是用來反序列化,但不是在序列化時。以下堆棧溢出答案可能對你有一些幫助。

Java Jackson - prevent float to int conversion when deserializing

UPDATE

爲了一個對象轉換爲另一種,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

+0

我從原始問題中刪除了JSON,因爲我意識到它在這裏並不真正相關。我只是在談論地圖。 – Peter 2014-11-05 10:22:06

+0

更新了我的答案。 – 2014-11-05 11:48:57

+0

謝謝,這說明了爲什麼映射的工作原理就像它一樣。 – Peter 2014-11-05 15:08:45