Search code examples
javaspring-booteclipselink

Eclipslink persitence converter not called


I wanted to create a org.eclipse.persistence.mappings.converters.Converter to convert a POJO to a JSON. I do this to store it in a Postgres jsonb field. This worked fine with Spring Boot 1.5.14. The new project is on Spring Boot 2.0.2 and the code does not work anymore. The Converter is not called anymore, which results in an type error on the database.

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.eclipse.persistence.mappings.DatabaseMapping;
import org.eclipse.persistence.sessions.Session;
import org.postgresql.util.PGobject;

import java.io.IOException;
import java.sql.SQLException;

public class MetadataConverter implements org.eclipse.persistence.mappings.converters.Converter {
    private ObjectMapper mapper = new ObjectMapper();

    @Override
    public Object convertObjectValueToDataValue(Object o, Session session) {
        try {
            PGobject out = new PGobject();
            out.setType("jsonb");
            out.setValue(mapper.writeValueAsString(o));
            return out;
        } catch (SQLException e) {
            throw new IllegalArgumentException("Unable to serialize to json field ", e);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
            throw new IllegalArgumentException("Unable to serialize to json field ", e);
        }

    }

    @Override
    public Metadata convertDataValueToObjectValue(Object o, Session session) {
        if (o == null) {
            return null;
        }

        try {
            if (o instanceof PGobject) {
                return mapper.readValue(((PGobject) o).getValue(), new TypeReference<Metadata>(){});
            } else {
                return mapper.readValue((String) o, new TypeReference<Metadata>(){});
            }

        } catch (IOException | ClassCastException e) { 
            throw new IllegalArgumentException("Unable to deserialize to json field ");
        }
    }

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

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

and here is the model:

...

@Data
@Entity
@JsonIgnoreProperties(ignoreUnknown = true)
@Table(name = "MY_TEST")
public class TestModel implements Serializable{

    @Id
    String id;

    @Column(columnDefinition = "jsonb")
    @Converter(converterClass = MetadataConverter.class, name = "metadataJsonConverter")
    @org.eclipse.persistence.annotations.Convert("metadataJsonConverter")
    Metadata metadata;
}

In both projects the eclipslink version is 2.6.3, Postgres Version is in the old one project 9.4.1212.jre7 (update is already planned) and in the new project 42.2.2

Does anybody has a idea what changed?

Best Regards

Lukas


Solution

  • The JpaConfiguration was incorrect, extending JpaBaseConfiguration solved the problem:

    @Configuration
    public class JpaConfiguration extends JpaBaseConfiguration {
        protected JpaConfiguration(DataSource dataSource, JpaProperties properties,
                                   ObjectProvider<JtaTransactionManager> jtaTransactionManagerProvider,
                                   ObjectProvider<TransactionManagerCustomizers> transactionManagerCustomizers) {
            super(dataSource, properties, jtaTransactionManagerProvider, transactionManagerCustomizers);
        }
    
        @Override
        protected AbstractJpaVendorAdapter createJpaVendorAdapter() {
            return new EclipseLinkJpaVendorAdapter();
        }
    
        @Override
        protected Map<String, Object> getVendorProperties() {
            final HashMap<String, Object> map = new HashMap<>();
            map.put(PersistenceUnitProperties.WEAVING, detectWeavingMode());
            map.put(PersistenceUnitProperties.VALIDATION_MODE, ValidationMode.NONE.toString());
            return map;
        }
    
        private String detectWeavingMode() {
            return InstrumentationLoadTimeWeaver.isInstrumentationAvailable() ? "true" : "static";
        }
    }