简体   繁体   English

Java Jpa 自定义实体属性转换器及规范

[英]Java Jpa Custom entity attribute converter and Specification

In my Java code, I have a JPA entity define as below在我的 Java 代码中,我有一个 JPA 实体定义如下

public class Entity {

    @Id
    private Long id;

    ... other attributes;

    @Column(name = "ctx")
    @Convert(converter = MapToJsonStringConverter.class)
    private Map<String, String> ctx;
}

@Convert
public class MapToJsonStringConverter implements AttributeConverter<Map<String, String>, String> {

    @Autowired
    private JsonParserService jsonParserService;

    @Override
    public String convertToDatabaseColumn(final Map<String, String> map) {
        return Optional.ofNullable(map)
                .map(jsonParserService::writeValueAsString)
                .orElse(null);
    }

    @Override
    public Map<String, String> convertToEntityAttribute(final String string) {
        return Optional.ofNullable(string)
                .map(jsonParserService::readValueAsMap)
                .orElse(null);
    }
}

A Jpa attribute converter is used to convert the ctx attribute to/ from a JSON string. Jpa 属性转换器用于将ctx属性与 JSON 字符串相互转换。 I need to create a JPA specification that allows me to query the ctx field in the database using a LIKE clause:我需要创建一个 JPA 规范,允许我使用LIKE子句查询数据库中的ctx字段:

ctx LIKE '%test-value%'

Of course, when I try to create such specification the criteria builder cannot match the type of the attribute as it is expecting a map when instead I only supply a string当然,当我尝试创建这样的规范时,标准构建器无法匹配属性的类型,因为它期望 map 而我只提供一个字符串

cb.like(root.get(Entity_.ctx), string))  <--- compile error Cannot resolve method 'like(javax.persistence.criteria.Expression<M>, java.lang.String)'

Is there a way to make this work instead of using a native query?有没有办法使这项工作而不是使用本机查询? Consider that the final specification also involves other attributes of the same entity.考虑到最终规范还涉及同一实体的其他属性。

As mentionned in commentaries正如评论中提到的

cb.like(root.<String>get("ctx"), clause);

Does not work as root.get(Entity_.ctx) or its equivalent does return a Map<String, String> and explicitly typing the generic ( <String>get(...) ) won't help as Map is not instanceof String .不能作为root.get(Entity_.ctx)或它的等价物返回一个Map<String, String>并且显式输入泛型( <String>get(...) )将无济于事,因为Map不是instanceof String . The solution as mentionned here is to use as provided by Criteria. 这里提到的解决方案是as Criteria 提供的方式使用。

cb.like(root.get(Entity_.ctx).as(String.class), string)

It does work thanks to Map overriding Object.toString() .由于Map覆盖Object.toString() ,它确实有效。 Otherwise you would need to create your own class extending Map and custom the override to toString() to return your custom representation (which is used by default by Json libs).否则,您需要创建自己的 class 扩展Map并将覆盖自定义为toString()以返回您的自定义表示(默认情况下由 Json 库使用)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM