Spring 对象映射器 covertValue 方法不转换某些字段
Spring object mapper covertValue method doesn't convert some fields
我有一个 Spring Boot 2 应用程序,它使用 ObjectMapper.convertValue
方法转换 from/to 实体和 DTO。
我一直在想明白为什么那个方法不转换某些字段,具体看下面的场景:
产品实体:
@Entity
@Table(name = "product")
@Getter
@Setter
@NoArgsConstructor(access = AccessLevel.PUBLIC)
@AllArgsConstructor
public class Product extends AbstractPersistable<Long> {
@Column
private String name;
@Column
private String description;
@Column
private BigDecimal price;
@Column
private int weight;
@Column
private int stock = 0;
@Column(name = "image_url", length = 254, unique = true)
private String imageUrl;
@NotEmpty
@Column(name = "banner_image_url", length = 254, unique = true)
private String bannerImageUrl;
@ManyToOne(optional = false, fetch = FetchType.EAGER, cascade = CascadeType.ALL)
@JoinColumn(name = "product_category_id")
@JsonBackReference
private Category category;
@OneToMany(mappedBy = "product", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
@OrderBy
@JsonManagedReference
private SortedSet<ProductThumbnail> thumbnails;
public Product(Long id) {
this.setId(id);
}
public Product(String name, String description, BigDecimal price, int weight) {
this.name = name;
this.description = description;
this.price = price;
this.weight = weight;
}
}
产品 DTO:
@Getter
@Setter
@NoArgsConstructor
public class ProductDTO {
private Long id;
private String name;
private String description;
private BigDecimal price;
private int weight;
private String imageUrl;
private String bannerImageUrl;
private CategoryDTO category;
private SortedSet<ProductThumbnailDTO> thumbnails;
public ProductDTO(@JsonProperty("id") Long id) {
this.id = id;
}
@JsonCreator
public ProductDTO(@JsonProperty("id") Long id,
@JsonProperty("name") String name,
@JsonProperty("description") String description,
@JsonProperty("price") BigDecimal price,
@JsonProperty("weight") int weight,
@JsonProperty("imageUrl") String imageUrl,
@JsonProperty("category") CategoryDTO category,
@JsonProperty("variants") Set<ProductVariantDTO> variants) {
this.id = id;
this.name = name;
this.description = description;
this.price = price;
this.weight = weight;
this.imageUrl = imageUrl;
this.category = category;
this.variants = variants;
}
}
执行以下代码时,每个字段都会自动转换:
ProductDTO productDTO = objectMapper.convertValue(product, ProductDTO.class);
但 category
除外。所以product
变量中的category被设置了,而转换后的productDTO.category字段为null。
类别实体:
@Entity
@Table(name = "product_category")
@Getter
@Setter
@NoArgsConstructor(access = AccessLevel.PUBLIC)
@AllArgsConstructor
@Immutable
public class Category extends AbstractPersistable<Long> {
@Column
private String name;
@Column
private String description;
@OneToMany(mappedBy = "category", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@JsonManagedReference
private Set<Product> products = new HashSet<>();
}
类别 DTO:
@Data
@NoArgsConstructor
public class CategoryDTO {
private String name;
private String description;
@JsonIgnore
private Set<Product> products = new HashSet<>();
@JsonCreator
public CategoryDTO(@JsonProperty("name") String name, @JsonProperty("description") String description) {
this.name = name;
this.description = description;
}
}
那么问题来了,为什么ObjectMapper不能自动转换category字段呢?有什么条件可以阻止它发生吗?因为根本没有抛出任何错误。
以下是 objectmapper bean:
@Bean
public ObjectMapper objectMapper() {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS);
objectMapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
objectMapper.findAndRegisterModules();
objectMapper.registerModules(module(), new Jdk8Module());
return objectMapper;
}
jackson dep 版本 2.10.1
谢谢
所以您代码中的罪魁祸首是 @JsonBackReference
。由于 @JsonBackReference
注释分配给
@JsonBackReference
private Category category;
此类别在序列化时被自动删除。来自 this reference:
@JsonManagedReference is the forward part of reference – the one that gets serialized normally.
@JsonBackReference is the back part of reference – it will be omitted from serialization.
因此请尝试使用 @JsonManagedReference
.
而不是 @JsonBackReference
希望这能解决您的问题。
我有一个 Spring Boot 2 应用程序,它使用 ObjectMapper.convertValue
方法转换 from/to 实体和 DTO。
我一直在想明白为什么那个方法不转换某些字段,具体看下面的场景:
产品实体:
@Entity
@Table(name = "product")
@Getter
@Setter
@NoArgsConstructor(access = AccessLevel.PUBLIC)
@AllArgsConstructor
public class Product extends AbstractPersistable<Long> {
@Column
private String name;
@Column
private String description;
@Column
private BigDecimal price;
@Column
private int weight;
@Column
private int stock = 0;
@Column(name = "image_url", length = 254, unique = true)
private String imageUrl;
@NotEmpty
@Column(name = "banner_image_url", length = 254, unique = true)
private String bannerImageUrl;
@ManyToOne(optional = false, fetch = FetchType.EAGER, cascade = CascadeType.ALL)
@JoinColumn(name = "product_category_id")
@JsonBackReference
private Category category;
@OneToMany(mappedBy = "product", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
@OrderBy
@JsonManagedReference
private SortedSet<ProductThumbnail> thumbnails;
public Product(Long id) {
this.setId(id);
}
public Product(String name, String description, BigDecimal price, int weight) {
this.name = name;
this.description = description;
this.price = price;
this.weight = weight;
}
}
产品 DTO:
@Getter
@Setter
@NoArgsConstructor
public class ProductDTO {
private Long id;
private String name;
private String description;
private BigDecimal price;
private int weight;
private String imageUrl;
private String bannerImageUrl;
private CategoryDTO category;
private SortedSet<ProductThumbnailDTO> thumbnails;
public ProductDTO(@JsonProperty("id") Long id) {
this.id = id;
}
@JsonCreator
public ProductDTO(@JsonProperty("id") Long id,
@JsonProperty("name") String name,
@JsonProperty("description") String description,
@JsonProperty("price") BigDecimal price,
@JsonProperty("weight") int weight,
@JsonProperty("imageUrl") String imageUrl,
@JsonProperty("category") CategoryDTO category,
@JsonProperty("variants") Set<ProductVariantDTO> variants) {
this.id = id;
this.name = name;
this.description = description;
this.price = price;
this.weight = weight;
this.imageUrl = imageUrl;
this.category = category;
this.variants = variants;
}
}
执行以下代码时,每个字段都会自动转换:
ProductDTO productDTO = objectMapper.convertValue(product, ProductDTO.class);
但 category
除外。所以product
变量中的category被设置了,而转换后的productDTO.category字段为null。
类别实体:
@Entity
@Table(name = "product_category")
@Getter
@Setter
@NoArgsConstructor(access = AccessLevel.PUBLIC)
@AllArgsConstructor
@Immutable
public class Category extends AbstractPersistable<Long> {
@Column
private String name;
@Column
private String description;
@OneToMany(mappedBy = "category", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@JsonManagedReference
private Set<Product> products = new HashSet<>();
}
类别 DTO:
@Data
@NoArgsConstructor
public class CategoryDTO {
private String name;
private String description;
@JsonIgnore
private Set<Product> products = new HashSet<>();
@JsonCreator
public CategoryDTO(@JsonProperty("name") String name, @JsonProperty("description") String description) {
this.name = name;
this.description = description;
}
}
那么问题来了,为什么ObjectMapper不能自动转换category字段呢?有什么条件可以阻止它发生吗?因为根本没有抛出任何错误。
以下是 objectmapper bean:
@Bean
public ObjectMapper objectMapper() {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS);
objectMapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
objectMapper.findAndRegisterModules();
objectMapper.registerModules(module(), new Jdk8Module());
return objectMapper;
}
jackson dep 版本 2.10.1
谢谢
所以您代码中的罪魁祸首是 @JsonBackReference
。由于 @JsonBackReference
注释分配给
@JsonBackReference
private Category category;
此类别在序列化时被自动删除。来自 this reference:
@JsonManagedReference is the forward part of reference – the one that gets serialized normally. @JsonBackReference is the back part of reference – it will be omitted from serialization.
因此请尝试使用 @JsonManagedReference
.
@JsonBackReference
希望这能解决您的问题。