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

时间:2019-01-24 15:49:38

标签: java jackson mixins builder lombok

我有一个第三方Lombok构建器POJO,我无法对其进行修改,我想使用jackson对其进行序列化。值得注意的是,没有没有NoArgsConstructor。

export const getCookies = async page => {
  const { cookies } = await page._client.send("Network.getAllCookies", {});

  return cookies;
};

从表面上看,这似乎很简单,但实际上令人沮丧,因为每种可能的选择似乎都因不同的并发症而被抵消。本质上,我很难让外部龙目岛 builder 与杰克逊 mixin 一起使用。

Lombok产生@Data @Builder public class ExternalClass { private String name; private String data; // etc. } 风格的流利的二传手,而Jackson的内置生成器反序列化器期望.name(String name)。龙目岛文档以及其他地方的食谱,例如here建议在预先声明的内部存根构建器上结合使用.withName(String name)@JsonDeserialize(builder=ExternalClass.ExternalClassBuilder.class)。但这是不可能的,因为Lombok类在外部库中。

将这些注释应用于mixin无效。

@JsonPOJOBuilder(withPrefix="")

我发现唯一可行的方法是利用@JsonDeserialize(ExternalClass.ExternalClassBuilder.class) public abstract class ExternalClassMixin { @JsonPOJOBuilder(withPrefix="") public static ExternalClassBuilder { } } 创建的包访问AllArgsConstructor并使用以下构造函数填充mixin

@Builder

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

我的问题是-是否有一种健壮,可维护的方法来使用Jackson序列化此外部生成器类,而无需使用mixin或完整的反序列化器对其进行修改?

更新

我实现了@ jan-rieke的出色回答,其中包括使用反射来查找内部构建器类的建议。

public abstract class ExternalClassMixin {
   @JsonCreator public ExternalClassMixin(
      @JsonProperty("name") String name,
      @JsonProperty("data") String data,
      // etc.
  ) {} 
} 

2 个答案:

答案 0 :(得分:3)

这可以通过创建两个 mixin 来实现:一个用于 ExternalClass(指定要使用的构建器),另一个用于 ExternalClass.ExternalClassBuilder(指定构建器方法中缺少前缀)。

@JsonDeserialize(builder = ExternalClass.ExternalClassBuilder.class)
public interface ExternalClassMixin {
}

@JsonPOJOBuilder(withPrefix="")
public interface ExternalClassBuilderMixin {
}

这会根据需要序列化和反序列化 JSON:

public static void main(String[] args) throws JsonProcessingException {
    String json = "{\"name\": \"The Name\", \"data\": \"The Data\"}";

    ObjectMapper mapper = new ObjectMapper()
            .addMixIn(ExternalClass.class, ExternalClassMixin.class)
            .addMixIn(ExternalClass.ExternalClassBuilder.class, ExternalClassBuilderMixin.class);

    System.out.println(mapper.readValue(json, ExternalClass.class));
    System.out.println(mapper.writeValueAsString(mapper.readValue(json, ExternalClass.class)));
}

输出:

ExternalClass(name=The Name, data=The Data)
{"name":"The Name","data":"The Data"}

答案 1 :(得分:1)

您可以按照以下步骤自定义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", "");
        }
    });

这将

  • 明确配置ExternalClass的反序列化使用其生成器,并且
  • 将构建器设置器方法的默认前缀设置为""(存在@JsonPOJOBuilder注释时除外)。

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