2015-11-06 103 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),其中还提供了相关的代码示例。 –