[英]Map JSON string column of a JPA entity to Java object automatically
我有一个具有以下结构的JPA实体对象:
@Table(name="item_info")
class Item(){
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
@Column(name="item_name")
private String itemName;
@Column(name="product_sku")
private String productSku;
@Column(name="item_json")
private String itemJsonString;
@Transient
private ItemJson itemJson;
//Getters and setters
}
itemJsonString字段包含json字符串值,例如'{"key1":"value1","key2":"value2"}'
并且itemJson字段包含对应的对象,该对象映射到json字符串。
我从数据库中获取此实体对象,如下所示:
Item item = itemRepository.findOne(1L); // Returns item with id 1
现在,itemJson字段为空,因为它是一个瞬态字段。 而且我必须使用Jackson的ObjectMapper手动设置它,如下所示:
itemJson = objectMapper.readValue(item.getItemJsonString(), ItemJson.class);
我怎样才能做到,当我执行itemRepository.findOne()
,它返回一个Item对象,该对象的itemJson字段自动映射到json字符串?
最好的选择是实现javax.persistence.Converter。 它看起来像:
import javax.persistence.AttributeConverter;
import javax.persistence.Converter;
@Converter(autoApply = true)
public class LocalDateAttributeConverter implements AttributeConverter<ItemJson, String> {
@Override
public String convertToDatabaseColumn(ItemJson entityValue) {
if( entityValue == null )
return null;
ObjectMapper mapper = new ObjectMapper();
return mapper.writeValueAsString(entityValue);
}
@Override
public ItemJson convertToEntityAttribute(String databaseValue) {
if( databaseValue == null )
return null;
ObjectMapper mapper = new ObjectMapper();
return mapper.readValue(databaseValue, ItemJson.class);
}
}
我已经在WildFly中使用了它,除了将其保存在我正在部署的war文件中之外,无需执行任何操作。
这是AttributeConverter
+ JPA + Kotlin的完整版本。
实体类别
在我的情况下,数据库是mysql(8.x),它支持JSON作为列定义的基础数据类型,我们可以使用@Convert
注释应用自定义转换器。
@Entity
data class Monitor (
@Id
val id: Long? = null,
@Column(columnDefinition = "JSON")
@Convert(converter = AlertConverter::class)
var alerts: List<Alert> = emptyList(),
var active: Boolean = false
)
转换器定义属性转换器需要指定从数据到db以及反向的转换机制。 我们正在使用Jackson将Java对象转换为String格式,反之亦然。
@Converter(autoApply = true)
class AlertConverter : AttributeConverter<List<Alert>, String> {
private val objectMapper = ObjectMapper()
override fun convertToDatabaseColumn(data: List<Alert>?): String {
return if (data != null && !data.isEmpty())
objectMapper.writeValueAsString(data)
else ""
}
override fun convertToEntityAttribute(dbData: String?): List<Alert> {
if (StringUtils.isEmpty(dbData)) {
return emptyList()
}
return objectMapper.readValue(dbData, object : TypeReference<List<Alert>>() {})
}
}
您可以在实体加载后通过postLoad 回调操作实体。 所以在您的实体类中尝试这样的事情
@PostLoad
public void afterLoad() {
ObjectMapper mapper = new ObjectMapper();
itemJson = mapper.readValue(item.getItemJsonString(), ItemJson.class);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.