HibernateException: не удалось определить тип для исключения класса с помощью собственного запроса spring-data-jpa для postgresql - PullRequest
0 голосов
/ 07 апреля 2019

У меня есть приложение весенней загрузки с бином и хранилищем.Я использую postgresql в качестве базы данных.В базе данных есть таблица testjob с двумя столбцами: id (тип UUID) и параметры (тип jsonb).Я следовал этой статье для поддержки jsonb: https://thoughts -on-java.org / persist-postgresqls-jsonb-data-type-hibernate / Я создал все классы, упомянутые в статье, но когда я запускаю свойtest, который просто вызывает метод upsert для репозитория, выдает исключение по следующей причине:

Caused by: org.hibernate.HibernateException: Could not determine a type for class: com.test.Parameters

Это исключение выдается только при выполнении собственного запроса, но с JPQL все работает нормально.К сожалению, мне нужно запустить его на нативном, потому что в будущем мне придется использовать оператор postgresql ON_CONFLICT.Буду признателен за любые советы, спасибо.

Мои занятия:

TestJobBean.java

@Entity
@Table(name = "testjob")
public class TestJobBean {

    @Id
    private UUID id;

    @NotNull @Column(name = "parameters") @Type(type = "ParametersType")
    private Parameters parameters;
    ...
}
TestJobRepository.java

@Repository
@Transactional
public interface TestJobRepository extends JpaRepository<TestJobBean, UUID>, TestJobRepositoryCustom {
}
TestJobRepositoryCustom.java

public interface TestJobRepositoryCustom {
    int upsert(UUID id, Parameters parameters);
}
TestJobRepositoryCustomImpl.java

@Transactional
public class TestJobRepositoryCustomImpl implements TestJobRepositoryCustom {

    @PersistenceContext
    private EntityManager entityManager;

    @Override
    public int upsert(UUID id, Parameters parameters) {
        final Query query = entityManager.createNativeQuery("INSERT INTO testjob (id, parameters) VALUES(:id, :parameters)");
        query.setParameter("id", id);
        query.setParameter("parameters", parameters);
        return query.executeUpdate();
    }

}
package-info.java

@org.hibernate.annotations.TypeDef(name = "ParametersType", typeClass = ParametersType.class)
package com.test.job;
Parameters.java

@Immutable
public class Parameters {

    private final long from;
    private final long to;
    private final @Nonnull String name;

    public Parameters(@JsonProperty("from") long from, @JsonProperty("to") long to,
            @JsonProperty("name") String name) {
        this.from = from;
        this.to = to;
        this.name = name;
    }

    @JsonProperty("from")
    public long getFrom() {
        return from;
    }

    @JsonProperty("to")
    public long getTo() {
        return to;
    }

    @JsonProperty("name")
    public long getName() {
        return name;
    }
}
TestPostgreSQL95Dialect.java

public class TestPostgreSQL95Dialect extends PostgreSQL95Dialect {

    public TestPostgreSQL95Dialect() {
        this.registerColumnType(Types.JAVA_OBJECT, "jsonb");
    }
}
ParametersType.java

public class ParametersType implements UserType {

    private final @Nonnull ObjectMapper mapper = new ObjectMapper();

    @Override
    public int[] sqlTypes() {
        return new int[] {Types.JAVA_OBJECT};
    }

    @Override
    public Class<ParametersType> returnedClass() {
        return ParametersType.class;
    }

    @Override
    public Object nullSafeGet(final ResultSet rs, final String[] names, final SharedSessionContractImplementor session,
            final Object owner) throws HibernateException, SQLException {
        final String cellContent = rs.getString(names[0]);
        if (cellContent == null) {
            return null;
        }
        try {
            return mapper.readValue(cellContent, returnedClass());
        } catch (final IOException ex) {
            throw new RuntimeException("Failed to convert string to an instance!", ex);
        }
    }

    @Override
    public void nullSafeSet(final PreparedStatement ps, final Object value, final int idx,
            final SharedSessionContractImplementor session) throws HibernateException, SQLException {
        if (value == null) {
            ps.setNull(idx, Types.OTHER);
            return;
        }
        try {
            final String valueAsJson = mapper.writeValueAsString(value);
            ps.setObject(idx, valueAsJson, Types.OTHER);
        } catch (final Exception ex) {
            throw new RuntimeException("Failed to convert the instance to string!", ex);
        }
    }

    @Override
    public Object deepCopy(final Object value) throws HibernateException {
        return value;
    }

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

    @Override
    public Serializable disassemble(final Object value) throws HibernateException {
        try {
            final String valueAsJson = mapper.writeValueAsString(value);
            return valueAsJson;
        } catch (final Exception ex) {
            throw new RuntimeException("Failed to convert the instance to string!", ex);
        }
    }

    @Override
    public Object assemble(final Serializable cached, final Object owner) throws HibernateException {
        try {
            return mapper.readValue((String) cached, returnedClass());
        } catch (final IOException ex) {
            throw new RuntimeException("Failed to convert string to an instance!", ex);
        }
    }

    @Override
    public Object replace(final Object original, final Object target, final Object owner) throws HibernateException {
        return original;
    }

    @Override
    public boolean equals(final Object obj1, final Object obj2) throws HibernateException {
        return Objects.equals(obj1, obj2);
    }

    @Override
    public int hashCode(final Object obj) throws HibernateException {
        return obj.hashCode();
    }
}

1 Ответ

0 голосов
/ 09 апреля 2019

Из комментария coladict: «Реализации UserType не добавляются к распознанным типам, которые вы можете использовать в собственных запросах». Поэтому было принято решение преобразовать объект в строку и привести строку как jsonb.

TestJobRepositoryCustomImpl.java

@Transactional
public class TestJobRepositoryCustomImpl implements TestJobRepositoryCustom {

    @PersistenceContext
    private EntityManager entityManager;

    @Autowired
    private ObjectMapper objectMapper;

    @Override
    public int upsert(UUID id, Parameters parameters) {
        final String parametersAsString = objectMapper.writer().writeValueAsString(parameters);
        final Query query = entityManager.createNativeQuery("INSERT INTO testjob (id, parameters) VALUES(:id, cast(:parameters as jsonb))");
        query.setParameter("id", id);
        query.setParameter("parameters", parametersAsString);
        return query.executeUpdate();
    }

}
...