Are JPA (EclipseLink) custom types possible?

后端 未结 2 1701
不知归路
不知归路 2020-12-08 06:20

In particular I am interested in using PostgreSQLs json type.

The core of the problem seems to be that there is no internal mapping in Eclipselink to <

相关标签:
2条回答
  • 2020-12-08 06:23

    PostgreSQL is too strict about implicit casts between text-like types. The simplest way is a workaround by creating a cast; see this answer.

    The clean way to do it would be to create a JPA provider extension that calls setObject(my_json), and/or teach your JPA provider to explicitly add CAST('myvalue' AS json) when it generates queries. This is a pain, as it requires JPA provider specific extensions.

    This Stack Overflow search will find a bunch of related questions for the xml type, which people have similar problems with.

    0 讨论(0)
  • 2020-12-08 06:48

    Walking through SO I've found many questions like this regarding JSON or XML types for mapping into Postgres. It looks like nobody have faced the problem of reading from custom Postgres type, so here the solution for both reading and writing using pure JPA type conversion mechanism.

    Postgres JDBC driver maps all attributes for unknown (to Java) types into org.postgresql.util.PGobject object, so it is enough to make converter for this type. Here is entity example:

    @Entity
    public class Course extends AbstractEntity {
        @Column(name = "course_mapped", columnDefinition = "json")
        @Convert(converter = CourseMappedConverter.class)
        private CourseMapped courseMapped;  // have no idea why would you use String json instead of the object to map
    
        // getters and setters
    }
    

    Here the converter example:

    @Converter
    public class CourseMappedConverter implements AttributeConverter<CourseMapped, PGobject> {
        @Override
        public PGobject convertToDatabaseColumn(CourseMapped courseMapped) {
            try {
                PGobject po = new PGobject();
                // here we tell Postgres to use JSON as type to treat our json
                po.setType("json");
                // this is Jackson already added as dependency to project, it could be any JSON marshaller
                po.setValue((new ObjectMapper()).writeValueAsString(courseMapped));
                return po;
            } catch (JsonProcessingException e) {
                e.printStackTrace();
                return null;
            } catch (SQLException e) {
                e.printStackTrace();
                return null;
            }
        }
    
        @Override
        public CourseMapped convertToEntityAttribute(PGobject po) {
            try {
                return (new ObjectMapper()).readValue(po.getValue(),CourseMapped.class);
            } catch (IOException e) {
                e.printStackTrace();
                return null;
            }
        }
    }
    

    If you really need to stick to String JSON representation in your entity, you can make converter like this for String type

    implements AttributeConverter<String, PGobject>
    

    Here is very dirty (though working) proof of concept, it also uses fake object serialization to tell JPA that object was changed if it was

    https://github.com/sasa7812/psql-cache-evict-POC

    0 讨论(0)
提交回复
热议问题