eclipselink + @convert(json) + postgres + list property

折月煮酒 提交于 2019-12-23 11:58:22

问题


I'm using eclipselink 2.6 as a persistence provider of spring data jpa, that in my understanding, now allows you to serialize a subtree of an entity as json using the internal moxy serializer.

So I'm trying to mix this to migrate from embedded element collections to a serialized json using the json datatype of postgres. I have an entity named Product, and this entity have the following mapped property:

@Convert(Convert.JSON) 
private List<MetadataIndex> indexes=new ArrayList<MetadataIndex> ();

In which metadata index is a simple class with a few string properties. I would like to convert this list of object into a json and store it into a column of json data type in postgres.

I thought that the above code should suffice, but it does not. The application crashes on boot (can't create entitymanager factory - npe somwhere inside eclipselink).

If I change the converter to @Convert(Convert.SERIALIZED) it works. It creates a field on the table Products named indexes of type bytea and store the serialized list in it. Is this an eclipselink bug or I'm missing something?

Thank you.


回答1:


well, I've used a custom eclipselink converter to convert my classes into json objects, then store them into the db using directly the postgres driver. This is the converter.

import fr.gael.dhus.database.jpa.domain.MetadataIndex;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.type.TypeReference;
import org.eclipse.persistence.mappings.DatabaseMapping;
import org.eclipse.persistence.sessions.Session;
import org.postgresql.util.PGobject;

import javax.persistence.AttributeConverter;
import javax.persistence.Converter;
import java.io.IOException;
import java.sql.SQLException;
import java.util.Collection;
import java.util.List;

/**
 * Created by fmarino on 20/03/2015.
 */
@Converter
public class JsonConverter implements org.eclipse.persistence.mappings.converters.Converter {

    private static ObjectMapper mapper =  new ObjectMapper();

    @Override
    public Object convertObjectValueToDataValue(Object objectValue, Session session) {
        try {
            PGobject out = new PGobject();
            out.setType("jsonb");
            out.setValue( mapper.writerWithType( new TypeReference<Collection<MetadataIndex>>() {} )
                    .writeValueAsString(objectValue) );
            return out;
        } catch (IOException e) {
            throw new IllegalArgumentException("Unable to serialize to json field ", e);
        } catch (SQLException e) {
            throw new IllegalArgumentException("Unable to serialize to json field ", e);
        }
    }

    @Override
    public Object convertDataValueToObjectValue(Object dataValue, Session session) {
        try {
            if(dataValue instanceof PGobject && ((PGobject) dataValue).getType().equals("jsonb"))
                return mapper.reader( new TypeReference<Collection<MetadataIndex>>() {}).readValue(((PGobject) dataValue).getValue());
            return "-";
        } catch (IOException e) {
            throw new IllegalArgumentException("Unable to deserialize to json field ", e);
        }
    }

    @Override
    public boolean isMutable() {
        return false;
    }

    @Override
    public void initialize(DatabaseMapping mapping, Session session) {

    }

}

as you can see I use jackson for serialization, and specify the datatype as Collection. You can use the type you want here.

Inside my classes, I've mapped my field with this:

@Convert(converter = JsonConverter.class)
@Column (nullable = true, columnDefinition = "jsonb")

adding also this annotation to the class:

@Converter(converterClass = JsonConverter.class, name = "jsonConverter")

To make things works properly with jackson I've also added to my MetadataIndex class this annotation, on the class element:

@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "@class")

I personally like using directly the postgres driver to store those kind of special datatype. I didn't manage to achieve the same with hibernate. As for the converter, I've would preferred a more general solution, but jackson forced me to state the object type I want to convert. If you find a better way to do it, let me know.

With a similar approach, I've also manage to use the hstore datatype of postgres.



来源:https://stackoverflow.com/questions/29149167/eclipselink-convertjson-postgres-list-property

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!