更新后反序列化失败。
我将微服务从Spring 1.5.10.RELEASE
更新为Spring 2.0.3.RELEASE
,还将lombok
从1.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);
}
}
答案 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
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
的构造函数;