2014-11-05 3 views
0

Я использую Jackson 2.4 для преобразования POJO в/из Maps. Я написал небольшую тестовую программу, как показано ниже.Отображение типа Java Jackson по умолчанию

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

+0

Не могли бы вы прояснить вопросы? В чем именно проблема? –

+0

Разница - Byte-> Integer и Float-> Double. В Json нет типа Byte. Таким образом, Float и Byte будут преобразованы в тип Number в JSON. См. Http://www.tutorialspoint.com/json/json_data_types.htm, так что это имеет смысл, поскольку Number - формат с плавающей запятой с двойной точностью в JavaScript. – nomoa

ответ

2

Почему отображение типов правильное в некоторых случаях, но не в других?

Ожидаемое поведение от Jackson. Если вы учтете типы данных, которые поддерживаются JSON, которые приведены ниже, для Джеффсона вполне разумно преобразовать типы данных.

  • Number - знаковое десятичное число, которое может содержать дробную часть и может использовать экспоненциальную E обозначения. JSON не допускает чисел, отличных от NaN, и не делает различий между целыми числами и плавающей точкой. (Несмотря на то, что JavaScript использует формат с плавающей запятой с двойной точностью для всех своих числовых значений, другие языки, реализующие JSON, могут кодировать номера по-разному)
  • String - последовательность из ноль или более символов Юникода, быть представленной в качестве суррогатной пары. Строки разделяются двойными кавычками и поддерживают синтаксис обратной косой черты.
  • Boolean - либо из значений истинным или ложным
  • Array - упорядоченный список из нуля или более значений, каждое из которых может быть любого типа. Массивы используют квадратную скобку с элементами, разделенными запятой.
  • Object - неупорядоченный ассоциативный массив (пары имя/значение). Объекты ограничены фигурными скобками и используют запятые для разделения каждой пары, в то время как внутри каждой пары символ двоеточия:: отделяет ключ или имя от его значения. Все ключи должны быть строками и должны отличаться друг от друга внутри этого объекта.
  • null - пустое значение, используя слово нулевого

Есть ли способ контролировать это, не делая какие-либо изменения в мои классы?

Его можно контролировать, когда Джексон используется для десериализации, но не во время сериализации. Следующий ответ «Переполнение стека» может вам помочь.

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

+0

Я удалил JSON из моего первоначального вопроса, поскольку понимаю, что здесь это не очень важно. Я говорю только о Картах. – Peter

+0

Обновлен мой ответ. –

+0

Спасибо, что дает понять, почему отображение работает так, как будто это происходит. – Peter

Смежные вопросы