Java Lombok 1.18.0 和 Jackson 2.9.6 不能一起工作

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/51464720/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 00:08:48  来源:igfitidea点击:

Lombok 1.18.0 and Hymanson 2.9.6 not working together

javaspring-bootHymansonlombokHymanson-databind

提问by JHS

The deserialization is failing after the update.

更新后反序列化失败。

I updated my micro-service from Spring 1.5.10.RELEASEto Spring 2.0.3.RELEASEand also updated the lombokfrom 1.16.14to 1.18.0and Hymanson-datatype-jsr310from 2.9.4to 2.9.6.

我从我的更新微服Spring 1.5.10.RELEASESpring 2.0.3.RELEASE,也更新了lombok1.16.141.18.0Hymanson-datatype-jsr3102.9.42.9.6

The JSON string -

JSON 字符串 -

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

The Class -

班上 -

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

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

Method call -

方法调用——

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

The method used to deserialize -

用于反序列化的方法 -

import com.fasterxml.Hymanson.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);
    }
}

Error -

错误 -

java.lang.RuntimeException: com.fasterxml.Hymanson.databind.exc.InvalidDefinitionException: Cannot construct instance of `com.foo.bar.ErrorDetail` (no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
at [Source: (String)"{"heading":"Validation failed","detail":"field must not be null"}"; line: 1, column: 2]

采纳答案by Jan Rieke

Lombok stopped generating @ConstructorPropertieson constructors with version 1.16.20 (see changelog), because it might break Java 9+ applications that use modules. That annotation contains the names of the constructor's parameters (they are removed when compiling the class, so that's a workaround so that the parameter names still can be retrieved at runtime). Because the annotation is now not being generated by default, Hymanson cannot map the field names to the constructor parameters.

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

Solution 1:Use a @NoArgsConstructorand @Setter, but you will loose immutability (if that's important to you).

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

Update:Just @NoArgsConstructorand @Getter(without @Setter) may also work (because INFER_PROPERTY_MUTATORS=true). In this way, you can keep the class immutable, at least from regular (non-reflective) code.

更新:Just@NoArgsConstructor@Getter(without @Setter) 也可以工作(因为INFER_PROPERTY_MUTATORS=true)。通过这种方式,您可以保持类不可变,至少在常规(非反射)代码中是这样。

Solution 2:Configure lombok to generate the annotations again, using a lombok.configfilecontaining the line lombok.anyConstructor.addConstructorProperties = true. (If you are using modules, make sure java.desktopis on your module path.)

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

Solution 3:Use Hymanson's builder support in combination with lombok's @Builder, as described here, or in @Randakar answerto this question.

解决方案 3:将 Hymanson 的 builder 支持与 lombok 的 结合使用@Builder,如here@Randakar对此问题的回答所述。

回答by lord_hokage

Using @Dataannotation is bad approach, in my opinion. Please change @Datato @Getting, @Setter, @EqualsAndHashcodeand so on ..

@Data在我看来,使用注释是不好的方法。请@Data改为@Getting, @Setter,@EqualsAndHashcode等等..

and write here please, if it will help.

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

update

更新

I suggest, that @Datacreate @RequiredArgsConstructor, and it is constructor with final fields, and without private String type;

我建议,@Datacreate @RequiredArgsConstructor,它是带有 final 字段的构造函数,而没有 private String type;

回答by GolamMazid Sajib

You want to deserialize a class which has final field. so u need to declare a constructor which contains final field to deserialize.

您想反序列化具有 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;
}
}

and when deserialize with mapper need to MapperFeature.ALLOW_FINAL_FIELDS_AS_MUTATORSset this property false.

并且当使用映射器反序列化时需要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);
    }
}

回答by Randakar

The best way to make Hymanson and lombok play well together is to always make your DTO's immutable, and tell Hymanson to use the builder to deserialize into your objects.

让 Hymanson 和 lombok 一起玩的最好方法是始终使您的 DTO 不可变,并告诉 Hymanson 使用构建器反序列化为您的对象。

Immutable objects are good idea for the simple reason that when fields cannot be modified in situ compilers can do much more aggressive optimisations.

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

In order to do this you need two annotations: JsonDeserialize, and JsonPojoBuilder.

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

Example:

例子:

@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 {
   }
}

回答by LukeSolar

Solution 4

解决方案4

  • Write the NoArgsConstructor yourself. This at least worked for me with lombok 1.18.8and Hymanson 2.9.9
  • 自己编写 NoArgsConstructor 。这至少对我对 lombok1.18.8和 Hymanson有用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 Hymanson happy
         */
        public EventDTO() {
        }
    }