EclipseLink JPA Postgres JsonОбъект в JSONB Конвертер - PullRequest
0 голосов
/ 06 июля 2018

Я относительно новичок в "расширенном" использовании EclipseLink и Postgres, поэтому я надеюсь, что кто-то может мне помочь.

У меня есть следующая модель:

package co.nayo.backend.models;

import co.nayo.backend.models.helpers.JSONConverter;
import co.nayo.backend.models.helpers.UUIDConverter;
import org.eclipse.persistence.annotations.Convert;
import org.eclipse.persistence.annotations.Converter;

import javax.json.JsonObject;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import java.util.Date;
import java.util.UUID;

@Entity
@Table(name = "subscriptions")
@Converter(name = "uuid_converter", converterClass = UUIDConverter.class)
@Converter(name = "json_converter", converterClass = JSONConverter.class)
public class Subscription {
    @Id
    @Column(name = "subscription_id", updatable = false)
    @Convert("uuid_converter")
    private UUID subscriptionId;

    @Column(name = "title")
    private String title;

    @Column(name = "description")
    private String description;

    @Column(name = "billing_cycle")
    private String billingCycle;

    @Column(name = "amount")
    private double amount;

    @Column(name = "currency")
    private String currency;

    @Column(name = "invoice_title")
    private String invoiceTitle;

    @Column(name = "invoice_description")
    private String invoiceDescription;

    @Column(name = "public")
    private boolean isPublic;

    @Column(name = "permissions")
    @Convert("json_converter")
    private JsonObject permissions;

    @Column(name = "active")
    private boolean active;

    @Column(name = "created_at")
    private Date createdAt;

    // Getters & Setters
}

В котором мне нужно / нужно javax.json.JsonObject для поля permissions, сопоставленного с типом данных JSONB postgres. Поэтому я написал этот конвертер для обработки преобразования.

package co.nayo.backend.models.helpers;

import org.eclipse.persistence.internal.helper.DatabaseField;
import org.eclipse.persistence.mappings.DatabaseMapping;
import org.eclipse.persistence.mappings.DirectCollectionMapping;
import org.eclipse.persistence.mappings.converters.Converter;
import org.eclipse.persistence.sessions.Session;

import javax.json.JsonObject;
import java.sql.Types;

public class JSONConverter implements Converter {
    @Override
    public JsonObject convertObjectValueToDataValue(Object objectValue, Session session) {
        return (JsonObject)objectValue;
    }

    @Override
    public JsonObject convertDataValueToObjectValue(Object dataValue, Session session) {
        return (JsonObject)dataValue;
    }

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

    @Override
    public void initialize(DatabaseMapping databaseMapping, Session session) {
        final DatabaseField field;
        if(databaseMapping instanceof DirectCollectionMapping) {
            field = ((DirectCollectionMapping)databaseMapping).getDirectField();
        } else {
            field = databaseMapping.getField();
        }

        field.setSqlType(Types.OTHER);
        field.setTypeName("JsonObject");
        field.setType(JsonObject.class);
        field.setColumnDefinition("jsonb");
    }
}

Когда я пытаюсь сохранить новую подписку, я получаю следующую ошибку:

Внутреннее исключение: org.postgresql.util.PSQLException: ОШИБКА: столбец «permissions» имеет тип jsonb, но выражение имеет тип hstore
Подсказка: вам нужно будет переписать или привести выражение. Позиция: 224 Код ошибки: 0

По какой-то причине (я пока не понимаю) EclipseLink, похоже, игнорирует привязку JSONB.

Когда я изменяю field.setColumnDefinition("jsonb"); на field.setColumnDefinition("hstore");, все работает нормально, но, конечно, тип данных postgres теперь hstore.

Может ли кто-нибудь привести меня в правильном направлении, как заставить его работать с типом данных JSONB?

Заранее спасибо и всего наилучшего, Боб

1 Ответ

0 голосов
/ 11 июля 2018

Мне пришлось расширить конфигурацию JpaBaseConfiguration, чтобы преобразователь работал:

@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";
    }
}
...