龙目岛1.18.0和杰克逊2.9.6无法一起使用

时间:2018-07-22 11:40:19

标签: java spring-boot jackson lombok jackson-databind

更新后反序列化失败。

我将微服务从Spring 1.5.10.RELEASE更新为Spring 2.0.3.RELEASE,还将lombok1.16.14更新为1.18.0,并将jackson-datatype-jsr310从{ {1}}至2.9.4

JSON字符串-

2.9.6

班级-

{"heading":"Validation failed","detail":"field must not be null"}

方法调用-

@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
public class ErrorDetail {

   private final String heading;
   private final String detail;
   private String type;
}

用于反序列化的方法-

ErrorDetail errorDetail = asObject(jsonString, ErrorDetail.class);

错误-

import com.fasterxml.jackson.databind.ObjectMapper;
// more imports and class defination.

private static <T> T asObject(final String str, Class<T> clazz) {
    try {
        return new ObjectMapper().readValue(str, clazz);
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

5 个答案:

答案 0 :(得分:16)

Lombok停止在版本1.16.20(请参阅changelog)的构造函数上生成@ConstructorProperties,因为它可能会破坏使用模块的Java 9+应用程序。该注释包含构造函数参数的名称(编译类时将其删除,因此这是一种变通方法,以便仍可以在运行时检索参数名称)。由于默认情况下现在不生成注释,因此Jackson无法将字段名称映射到构造函数参数。

解决方案1: 使用@NoArgsConstructor@Setter,但会失去不变性(如果这对您很重要)。

更新:仅@NoArgsConstructor@Getter(不包含@Setter)也可以工作(因为INFER_PROPERTY_MUTATORS=true)。这样,您可以使类至少从常规(非反射)代码中保持不变。

解决方案2: 配置lombok再次生成注释,using a lombok.config file包含行lombok.anyConstructor.addConstructorProperties = true。 (如果您使用的是模块,请确保java.desktop位于模块路径上。)

解决方案3:here或本问题的@Randakar answer所述,结合使用杰克逊的建造者支持和龙目岛的@Builder

答案 1 :(得分:1)

您想反序列化具有final字段的类。因此,您需要声明一个包含要反序列化的final字段的构造函数。

@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
public class ErrorDetail {

private final String heading;
private final String detail;
private String type;

@JsonCreator
public ErrorDetail(@JsonProperty("heading") String heading, @JsonProperty("detail") String detail) {
    this.heading = heading;
    this.detail = detail;
}
}

,当使用映射器反序列化时,需要 MapperFeature.ALLOW_FINAL_FIELDS_AS_MUTATORS 将此属性设置为 false

private static <T> T asObject(final String str, Class<T> clazz) {
    try {
        return new ObjectMapper().configure(MapperFeature.ALLOW_FINAL_FIELDS_AS_MUTATORS,false).readValue(str, clazz);
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

答案 2 :(得分:1)

使jackson和lombok一起发挥作用的最佳方法是始终使DTO不可变,并告诉jackson使用生成器将其反序列化为对象。

不可变对象是一个好主意,原因很简单,当无法原位修改字段时,编译器可以进行更积极的优化。

为此,您需要两个注释:JsonDeserialize和JsonPojoBuilder。

示例:

@Builder
@Value // instead of @Data
@RequiredArgsConstructor
@NonNull // Best practice, see below.
@JsonDeserialize(builder = ErrorDetail.ErrorDetailBuilder.class)
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
public class ErrorDetail {

   private final String heading;

   // Set defaults if fields can be missing, like this:
   @Builder.Default
   private final String detail = "default detail";

   // Example of how to do optional fields, you will need to configure
   // your object mapper to support that and include the JDK 8 module in your dependencies..
   @Builder.Default
   private Optional<String> type = Optional.empty()

   @JsonPOJOBuilder(withPrefix = "")
   public static final class ErrorDetailBuilder {
   }
}

答案 3 :(得分:0)

解决方案4

  • 自己编写NoArgsConstructor。这至少对lombok 1.18.8和Jackson 2.9.9
  • 对我有用
    @Builder
    @Getter
    @AllArgsConstructor
    public class EventDTO {

        private String id;
        private Integer isCancelled;

        private String recurringEventId;

        private String summary;
        private String description;
        private String location;
        private String startDateTime;
        private String endDateTime;

        /**
         * Make Jackson happy
         */
        public EventDTO() {
        }
    }

答案 4 :(得分:-1)

在我看来,使用var PTSans = ... 注释是不好的方法。 请将@Data更改为@Data@Getting@Setter,依此类推..

如果有帮助,请在这里写。

更新

我建议@EqualsAndHashcode创建@Data,它是具有最终字段且没有@RequiredArgsConstructor的构造函数;