2015-11-06 102 views
1

我試圖用Java實現一個JSON序列化與Genson 1.3多態類型,包括:Genson多態/通用序列化

  • Number小號
  • 陣列
  • Enum

下面的SSCCE大致顯示了我試圖實現的目標:

import java.util.ArrayList; 
import java.util.Arrays; 
import java.util.List; 

import com.owlike.genson.Genson; 
import com.owlike.genson.GensonBuilder; 

/** 
* A Short, Self Contained, Compilable, Example for polymorphic serialization 
* and deserialization. 
*/ 
public class GensonPolymoprhicRoundTrip { 

    // our example enum 
    public static enum RainState { 
     NO_RAIN, 
     LIGHT_RAIN, 
     MODERATE_RAIN, 
     HEAVY_RAIN, 
     LIGHT_SNOW, 
     MODERATE_SNOW, 
     HEAVY_SNOW; 
    } 

    public static class Measurement<T> { 
     public T value; 
     public int qualityValue; 
     public String source; 

     public Measurement() { 
     } 
     public Measurement(T value, int qualityValue, String source) { 
      this.value = value; 
      this.qualityValue = qualityValue; 
      this.source = source; 
     } 
    } 

    public static class DTO { 
     public List<Measurement<?>> measurements; 

     public DTO(List<Measurement<?>> measurements) { 
      this.measurements = measurements; 
     } 
    } 

    public static void main(String... args) { 
     Genson genson = new GensonBuilder() 
     .useIndentation(true) 
     .useRuntimeType(true) 
     .useClassMetadataWithStaticType(false) 
     .addAlias("RainState", RainState.class) 
     .useClassMetadata(true) 
     .create(); 

     DTO dto = new DTO(
       new ArrayList(Arrays.asList(
         new Measurement<Double>(15.5, 8500, "TEMP_SENSOR"), 
         new Measurement<double[]>(new double[] { 
           2.5, 
           1.5, 
           2.0 
         }, 8500, "WIND_SPEED"), 
         new Measurement<RainState>(RainState.LIGHT_RAIN, 8500, "RAIN_SENSOR") 
         ))); 
     String json = genson.serialize(dto); 
     System.out.println(json); 
     DTO deserialized = genson.deserialize(json, DTO.class); 
    } 
} 

號和陣列行之有效外的開箱,但枚舉類是提供一個小小的挑戰。在這種情況下,序列化JSON形式必須是IMO一個JSON對象包括:

  • 類型成員
  • value成員

望着EnumConverter類我看到,我需要提供自定義Converter。不過,我不能完全掌握如何正確註冊Converter,以便它在反序列化被調用。如何用Genson解決這個序列化問題?

回答

1

非常適合提供完整的示例!

第一個問題是DTO沒有一個無參數的構造函數,但Genson支持類,即使有參數的構造。您只需通過構建器使用'useConstructorWithArguments(true)'來啓用它。

然而,這並不能解決問題齊全。就目前而言,Genson僅支持序列化爲json對象的類型。因爲Genson會爲它添加一個名爲'@class'的屬性。這是一個open issue

也許應該與大多數情況下工作最好的解決辦法是定義一個轉換器,自動包裝的JSON對象的所有值,這樣處理類的元數據轉換器將能夠生成它。這可以是一個「足夠好」的解決方案,同時等待它由Genson正式支持。

所以首先定義包裝器

public static class LiteralAsObjectConverter<T> implements Converter<T> { 
    private final Converter<T> concreteConverter; 

    public LiteralAsObjectConverter(Converter<T> concreteConverter) { 
     this.concreteConverter = concreteConverter; 
    } 

    @Override 
    public void serialize(T object, ObjectWriter writer, Context ctx) throws Exception { 
     writer.beginObject().writeName("value"); 
     concreteConverter.serialize(object, writer, ctx); 
     writer.endObject(); 
    } 

    @Override 
    public T deserialize(ObjectReader reader, Context ctx) throws Exception { 
     reader.beginObject(); 
     T instance = null; 
     while (reader.hasNext()) { 
      reader.next(); 
      if (reader.name().equals("value")) instance = concreteConverter.deserialize(reader, ctx); 
      else throw new IllegalStateException(String.format("Encountered unexpected property named '%s'", reader.name())); 
     } 
     reader.endObject(); 
     return instance; 
    } 
} 

然後你需要用ChainedFactory這將讓你委託給默認的轉換器(這種方式,與任何其他類型的自動工作)進行註冊。

Genson genson = new GensonBuilder() 
      .useIndentation(true) 
      .useConstructorWithArguments(true) 
      .useRuntimeType(true) 
      .addAlias("RainState", RainState.class) 
      .useClassMetadata(true) 
      .withConverterFactory(new ChainedFactory() { 
       @Override 
       protected Converter<?> create(Type type, Genson genson, Converter<?> nextConverter) { 
        if (Wrapper.toAnnotatedElement(nextConverter).isAnnotationPresent(HandleClassMetadata.class)) { 
         return new LiteralAsObjectConverter(nextConverter); 
        } else { 
         return nextConverter; 
        } 
       } 
      }).create(); 

這種解決方案的缺點是,useClassMetadataWithStaticType需要被設置爲true ...但嗯,我想這是可以接受的,因爲它是一個的Optim,可以固定的,但將意味着Gensons代碼一些變化,其餘的仍然有效。

如果你感到有興趣通過這個問題,將是巨大的,你試圖給一出手就這一問題,並打開一個PR來提供這項功能Genson的一部分。

+0

我實現了一個基於此的解決方案和[工廠]的javadocs(http://owlike.github.io/genson/Documentation/Javadoc/com/owlike/genson/Factory.html)和[ChainedFactory](http ://owlike.github.io/genson/Documentation/Javadoc/com/owlike/genson/convert/ChainedFactory.html),其中還提供了相關的代碼示例。 –