我试图用Java1.3为多态类型实现根森序列化,包括:
Number%sEnum类下面的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对象,包括:
查看EnumConverter类,我发现我需要提供一个自定义Converter。但是,我不太清楚如何正确注册deserialization.,以便在Converter期间调用它如何使用Genson解决这个序列化问题?
发布于 2015-11-06 23:35:32
很好地提供了一个完整的例子!
第一个问题是DTO没有no arg构造函数,但是Genson支持类,即使有参数的构造函数也是如此。您只需使用“useConstructorWithArguments(True)”通过构建器启用它即可。
然而,这并不能完全解决问题。目前,Genson只对序列化为json对象的类型提供完全多态支持。因为Genson将向其添加一个名为“@class”的属性。这有一个公开发行。
在大多数情况下,最好的解决方案可能是定义一个转换器,自动包装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设置为真正的...but--我想这是可以接受的,因为它是一个optim,可以修复,但可能意味着Gensons代码中的一些更改,其余的仍然有效。
如果你对这个问题感兴趣,那将是很棒的,你试图给这个问题一个尝试,并打开一个公关,以提供作为Genson的一部分这个功能。
https://stackoverflow.com/questions/33568019
复制相似问题