带有@Converter的通用类的Imlpement AttributeConverter

mad*_*nce 6 spring hibernate jpa

如何为泛型实现AttributeConverter?

就像是

class JSONConverter<T> implements AtttributeConverter<T,String>{
   //Here How do I get the generic class type with which I can convert a serialized object
}
Run Code Online (Sandbox Code Playgroud)

在实体类中调用转换器作为

@Column
@Convert( converter = JSONConverter.class) //How do I pass the Generic here
private SomeClass sm;
Run Code Online (Sandbox Code Playgroud)

小智 7

可以做得更简单一些,因为您不一定需要通过构造函数传递 typeReference:

public abstract class JsonConverter<T> implements AttributeConverter<T, String> {

    private final TypeReference<T> typeReference = new TypeReference<T>() {};

    @Resource
    private ObjectMapper objectMapper;

    @Override
    public String convertToDatabaseColumn(T object) {
        try {
            return objectMapper.writeValueAsString(object);
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public T convertToEntityAttribute(String json) {
        try {
            return objectMapper.readValue(json, typeReference);
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后是扩展 JsonConventer 的类,如下所示:

public class SomeClassConverter extends JsonConverter<SomeClass> { }
Run Code Online (Sandbox Code Playgroud)


Edw*_*Hoi 4

我在 Eclipselink 和 Java 8 中使用了以下解决方案。一个没有立即显现出来的问题是转换器类必须直接实现 AttributeConverter(至少要与 Eclipselink 一起使用)

步骤1.定义一个通用接口来实现Object <-> String Json转换。因为接口不能包含属性,所以我定义了两个方法getInstance(),并getObjectMapper()提供对运行时所需的对象实例的转换逻辑访问。转换器类需要提供这些方法的实现。

package au.com.sfamc.fusion.commons.jpa;
import java.io.IOException;
import javax.persistence.AttributeConverter;
import org.apache.commons.lang3.StringUtils;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

public interface GenericJsonAttributeConverter<X> extends AttributeConverter<X, String> {

X getInstance();
ObjectMapper getObjectMapper();

@Override
default String convertToDatabaseColumn(X attribute) {
    String jsonString = "";
    try {

        // conversion of POJO to json
        if(attribute != null) {
            jsonString = getObjectMapper().writeValueAsString(attribute);
        } else {
            jsonString = "{}"; // empty object to protect against NullPointerExceptions
        }
    } catch (JsonProcessingException ex) {
    }

    return jsonString;
}

@Override
default X convertToEntityAttribute(String dbData) {
    X attribute = null;

    try {
        if(StringUtils.isNoneBlank(dbData)) {
            attribute = getObjectMapper().readValue(dbData, (Class<X>)getInstance().getClass());
        } else {
            attribute = getObjectMapper().readValue("{}", (Class<X>)getInstance().getClass());
        }            
    } catch (IOException ex) {
    }

    return attribute;
}

}
Run Code Online (Sandbox Code Playgroud)

步骤 2.getObjectMapper()每个转换器类都会重复该方法实现,因此我引入了一个扩展的抽象类,GenericJsonAttributeConverter以节省在每个转换器类中实现此方法的必要性。

package au.com.sfamc.fusion.commons.jpa;

import com.fasterxml.jackson.databind.ObjectMapper;

public abstract class AbstractGenericJsonAttributeConverter<X> implements GenericJsonAttributeConverter<X> {

private static final ObjectMapper objectmapper = new ObjectMapper();

@Override
public ObjectMapper getObjectMapper() {
    return AbstractGenericJsonAttributeConverter.objectmapper;
}
}
Run Code Online (Sandbox Code Playgroud)

步骤 3.为您想要转换为 Json 或从 Json 转换的每个类创建一个具体实现AbstractGenericJsonAttributeConverter,即使您想要转换的每个类都需要其自己的具体转换器类,至少您不会重复转换代码...

package au.com.sfamc.fusion.main.client;

import javax.persistence.AttributeConverter;
import javax.persistence.Converter;

import au.com.sfamc.fusion.commons.jpa.AbstractGenericJsonAttributeConverter;

 @Converter
 public class ProjectMetricsReportJsonConverter extends AbstractGenericJsonAttributeConverter<ProjectMetricsReport> implements AttributeConverter<ProjectMetricsReport, String> {

private static final ProjectMetricsReport projectMetricsReport = new ProjectMetricsReport();

@Override
public ProjectMetricsReport getInstance() {
    return ProjectMetricsReportJsonConverter.projectMetricsReport;
}

}
Run Code Online (Sandbox Code Playgroud)

注意:现在让它与 Eclipselink 一起工作的技巧很微妙,但却是必需的。除了扩展AbstractGenericJsonAttributeConverter具体实现之外,还必须直接引用implements“AttributeConverter”接口(为实现通用转换工作而付出的代价很小)