Java 基于GSON中字段名的同类型序列化,不带注释

Java 基于GSON中字段名的同类型序列化,不带注释,java,gson,json-deserialization,Java,Gson,Json Deserialization,给定一个我无法修改的类 class ThirdPartyDTO { Instant foo; Instant bar; // many more fields. } 我有一个类的JSON表示,它使用两种不同的模式来表示foo和bar 如果字段名为foo,则使用此模式;如果字段名为bar,则使用其他模式 如何使用gson而不在每个字段名上添加(因为我不能)注释 谢谢。因此,正如我在上面的评论中提到的,Gson类型适配器无法访问它们序列化或反序列化的对象的完整上下文。例如,单个类型(层

给定一个我无法修改的类

class ThirdPartyDTO
{
  Instant foo;
  Instant bar;
  // many more fields.
}
我有一个类的JSON表示,它使用两种不同的模式来表示foo和bar

如果字段名为foo,则使用此模式;如果字段名为bar,则使用其他模式

如何使用gson而不在每个字段名上添加(因为我不能)注释


谢谢。

因此,正如我在上面的评论中提到的,Gson类型适配器无法访问它们序列化或反序列化的对象的完整上下文。例如,单个类型(层次结构)的类型适配器并不真正知道它可以应用于哪个字段(这就是本文中的问题)。为了为不同的字段应用不同的类型适配器,可以使用
JsonSerializer
JsonDeserializer
(因此每个字段都必须手动处理,这是一项繁琐的工作)。这里的另一个缺点是,本应处理这样的DTO的
ReflectTypeAdapterFactory
不能直接扩展,只能通过同样受限的
GsonBuilder
接口进行扩展

但是,可以实施使用以下算法的变通方法:

  • 创建一个在反序列化时总是跳过特殊字段的排除策略(这仅影响
    ReflectTypeAdapterFactory
  • 创建类型适配器工厂,为此类特殊字段创建类型适配器
  • 一旦Gson反序列化包装器对象,包装器对象中的特殊字段应该被跳过,但设置为
    null
    (原语情况下的其他默认值),post反序列化器类型适配器要求注入的策略反序列化以前被排除策略跳过的每个特殊字段,因此
    ReflectTypeAdapterFactory
这就是诀窍

接口工厂{
@非空
TypeAdapterFactory创建TypeAdapterFactory();
@非空
排除策略CreateExclutionStrategy();
}
@allargsconstuctor(access=AccessLevel.PRIVATE)
最后一级后处理工厂
实现IPosPatch工厂{
私有最终谓词>isClassPostPatched;
private final Iterable>fieldPatchesCopy=新阵列列表(fieldPatches);
最终集合postPatchedFields=fieldPatches.stream()
.map(FieldPatch::getField)
.collect(Collectors.toList());
最终集合postPatchedFieldAttributes=postPatchedFields.stream()
.map(FieldDatum::from)
.collect(Collectors.toList());
最终集合>isClassPostPatched=postPatchedFieldAttributes.stream()
.map(fieldDatum->fieldDatum.declaringClass)
.collect(Collectors.toList());
返回新的PostPatchFactory(postPatchedFieldAttributes::contains,isClassPostPatched::contains,fieldPatchesCopy);
}
@非空
@凌驾
公共类型适配器工厂createTypeAdapterFactory(){
返回新的PostPatchTypeAdapterFactory(isClassPostPatched,fieldPatches);
}
@非空
@凌驾
公共排除策略CreateExclutionStrategy(){
返回新的PostPatch策略(isFieldPostPatched);
}
@AllArgsConstructor(access=AccessLevel.PRIVATE)
私有静态最终类PostPatchTypeAdapterFactory
实现TypeAdapterFactory{
私有最终谓词>isClassPostPatched;
私有最终Iterable>fieldPatches;
@凌驾
公共无效写入(最终JsonWriter out,最终T值){
抛出新的不支持操作异常(“TODO”);
}
@凌驾
公共T读(最终JsonReader in){
final JsonElement bufferedJsonElement=JsonParser.parseReader(in);
最终T值=delegateTypeAdapter.fromJsonTree(BufferedJSOneElement);
用于(最终现场修补程序现场修补程序:现场修补程序){
final Field=fieldPatch.getField();
final-BiFunction反序列化=fieldPatch.getDeserialize();
final Object fieldValue=反序列化.apply(gson,bufferedJsonElement);
试一试{
field.set(值,fieldValue);
}捕获(最终非法访问例外){
抛出新的运行时异常(ex);
}
}
返回值;
}
}
}
私有静态最终类延迟策略
实施排他性战略{
私有最终谓词declaringClass;
私有最终字符串名;
来自(最终成员)的专用静态字段数据{
返回新的FieldDatum(member.getDeclaringClass(),member.getName());
}
来自的专用静态FieldDatum(最终FieldAttributes FieldAttributes){
返回新的FieldDatum(fieldAttributes.getDeclaringClass(),fieldAttributes.getName());
}
}
}
@allargsconstuctor(staticName=“of”)
@吸气剂
最后一节课现场补丁{
私人终场;
专用最终双功能>现场补丁;
静止的{
试一试{
最终字段thirdPartyDtoFooField=ThirdPartyDTO.class.getDeclaredField(“foo”);
第三方tofoofield.setAccessible(true);
最终字段thirdPartyDtoBarField=ThirdPartyDTO.class.getDeclaredField(“bar”);
第三方ToBarfield.setAccessible(true);

fieldPatches=ImmutableList。为
ThirdPartyTo
实现一个特殊类型适配器。这可能是在Gson中实现这一点的唯一方法。因此我必须自定义反序列化所有字段,因为我需要对一个字段进行特殊处理?不幸的是,是的,因为
TypeAdapter
TypeAdapterFactory
都不能访问cont