如何使用 Jackson 反序列化外部 Lombok 构建器类

psc*_*scl 7 java builder mixins jackson lombok

我有一个第 3 方 Lombok builder POJO,一个我无法修改的,我想使用 jackson 进行序列化。值得注意的是它并没有有NoArgsConstructor。

@Data
@Builder
public class ExternalClass {
   private String name;
   private String data; 
   // etc.
} 
Run Code Online (Sandbox Code Playgroud)

从表面上看,这似乎很简单,但在实践中却令人难以置信地令人沮丧,因为每个可能的选项似乎都被不同的并发症所抵消。从本质上讲,我很难让外部Lombok构建器与 jackson mixin一起工作。

Lombok 生成流利的样式设置器,.name(String name)而 Jackson 的内置构建器解串器期望.withName(String name). Lombok 文档和其他地方的食谱(例如此处)建议@JsonDeserialize(builder=ExternalClass.ExternalClassBuilder.class)@JsonPOJOBuilder(withPrefix="")预先声明的内部存根构建器结合使用。但这是不可能的,因为 Lombok 类位于外部库中。

将这些注释应用于 mixin 没有任何效果。

@JsonDeserialize(ExternalClass.ExternalClassBuilder.class)
public abstract class ExternalClassMixin {
   @JsonPOJOBuilder(withPrefix="")
   public static ExternalClassBuilder {
   }
} 
Run Code Online (Sandbox Code Playgroud)

我发现唯一有效的方法是利用由@Builder以下构造函数创建的包访问 AllArgsConstructor并填充 mixin

public abstract class ExternalClassMixin {
   @JsonCreator public ExternalClassMixin(
      @JsonProperty("name") String name,
      @JsonProperty("data") String data,
      // etc.
  ) {} 
} 
Run Code Online (Sandbox Code Playgroud)

这显然是不可取的,因为它需要显式地迭代和硬编码每个类属性,使得 mixin 容易受到外部 POJO 中的任何更改的影响。

我的问题是 - 是否有一种健壮的、可维护的方法来使用 Jackson 序列化这个外部构建器类而不修改它,使用 mixin 或者可能是一个完整的反序列化器?

更新

我实现了@jan-rieke 的优秀答案,包括使用反射寻找内部构建器类的建议。

...
public Class<?> findPOJOBuilder(AnnotatedClass ac) {
   Class<?> innerBuilder;
   try {
      innerBuilder = Class.forName(ac.getName()+"$"+ac.getRawType().getSimpleName()+"Builder");
      log.info("Builder found: {}", ac.getName());
      return innerBuilder;
   } catch( ClassNotFoundException e ) {
      return super.findPOJOBuilder(ac);
   }
}
Run Code Online (Sandbox Code Playgroud)

Jan*_*eke 6

您可以ObjectMapper按如下方式自定义:

    ObjectMapper mapper = new ObjectMapper();
    mapper.setAnnotationIntrospector(new JacksonAnnotationIntrospector() {
        @Override
        public Class<?> findPOJOBuilder(AnnotatedClass ac) {
            if (ExternalClass.class.equals(ac.getRawType())) {
                return ExternalClass.ExternalClassBuilder.class;
            }
            return super.findPOJOBuilder(ac);
        }

        @Override
        public Value findPOJOBuilderConfig(AnnotatedClass ac) {
            if (ac.hasAnnotation(JsonPOJOBuilder.class)) {
                return super.findPOJOBuilderConfig(ac);
            }
            return new JsonPOJOBuilder.Value("build", "");
        }
    });
Run Code Online (Sandbox Code Playgroud)

这会

  • 显式配置反序列化以ExternalClass使用其构建器,并且
  • 将构建器 setter 方法的默认前缀设置为""(除非@JsonPOJOBuilder存在注释)。

如果您不想在 中显式列出所有外部类findPOJOBuilder(),您当然可以以编程方式查看该类以检查它是否具有看起来像构建器的内部类。