Как отобразить дочерний элемент Set <UUID>, используя @ElementCollection - PullRequest
0 голосов
/ 10 октября 2019

Я использую UUID в качестве PK для сущности, и у этой сущности есть Set<UUID> дочернее свойство, сопоставленное с использованием @ElementCollection. При сохранении родительской сущности я получаю java.lang.ClassCastException: java.lang.String cannot be cast to java.util.UUID

Я смотрел аннотации @MapKeyClass, @Column, @CollectionTable и @JoinColumn, но никто не предлагает способ указать, что дочерний набор использует UUIDдля ФК и для его значений. Моя последняя попытка состояла в том, чтобы добавить это к атрибуту @CollectionTable(name = "test_target_files_ids", joinColumns = @JoinColumn(name = "campaign_id", referencedColumnName="id", columnDefinition="binary(16) not null"))

Моя сущность:

@Entity
public class Campaign
{
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    UUID id;
    String name;
    // more attributes...

    @ElementCollection
    Set<UUID> targetFilesIds; // This is just a list of UUIDs representing external files or any other object, it does not matter

Я ожидаю, что сущность и ее дочерний список UUID будут сохранены, но сохраняется только сущность. Я получаю это сообщение об ошибке

java.lang.ClassCastException: java.lang.String cannot be cast to java.util.UUID
    at org.hibernate.type.descriptor.java.UUIDTypeDescriptor.unwrap(UUIDTypeDescriptor.java:20) ~[hibernate-core-5.3.12.Final.jar:5.3.12.Final]
    at org.hibernate.type.descriptor.sql.VarbinaryTypeDescriptor$1.doBind(VarbinaryTypeDescriptor.java:45) ~[hibernate-core-5.3.12.Final.jar:5.3.12.Final]
    at org.hibernate.type.descriptor.sql.BasicBinder.bind(BasicBinder.java:74) ~[hibernate-core-5.3.12.Final.jar:5.3.12.Final]
    at org.hibernate.type.AbstractStandardBasicType.nullSafeSet(AbstractStandardBasicType.java:276) ~[hibernate-core-5.3.12.Final.jar:5.3.12.Final]
    at org.hibernate.type.AbstractStandardBasicType.nullSafeSet(AbstractStandardBasicType.java:271) ~[hibernate-core-5.3.12.Final.jar:5.3.12.Final]
    at org.hibernate.type.AbstractSingleColumnStandardBasicType.nullSafeSet(AbstractSingleColumnStandardBasicType.java:39) ~[hibernate-core-5.3.12.Final.jar:5.3.12.Final]
    at org.hibernate.persister.collection.AbstractCollectionPersister.writeElement(AbstractCollectionPersister.java:912) ~[hibernate-core-5.3.12.Final.jar:5.3.12.Final]
    at org.hibernate.persister.collection.AbstractCollectionPersister.recreate(AbstractCollectionPersister.java:1335) ~[hibernate-core-5.3.12.Final.jar:5.3.12.Final]
    at org.hibernate.action.internal.CollectionRecreateAction.execute(CollectionRecreateAction.java:50) ~[hibernate-core-5.3.12.Final.jar:5.3.12.Final]
    at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:604) ~[hibernate-core-5.3.12.Final.jar:5.3.12.Final]
    at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:478) ~[hibernate-core-5.3.12.Final.jar:5.3.12.Final]
    at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:356) ~[hibernate-core-5.3.12.Final.jar:5.3.12.Final]
    at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:39) ~[hibernate-core-5.3.12.Final.jar:5.3.12.Final]
    at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1483) ~[hibernate-core-5.3.12.Final.jar:5.3.12.Final]
    at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:512) ~[hibernate-core-5.3.12.Final.jar:5.3.12.Final]
    at org.hibernate.internal.SessionImpl.flushBeforeTransactionCompletion(SessionImpl.java:3321) ~[hibernate-core-5.3.12.Final.jar:5.3.12.Final]
    at org.hibernate.internal.SessionImpl.beforeTransactionCompletion(SessionImpl.java:2517) ~[hibernate-core-5.3.12.Final.jar:5.3.12.Final]
    at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.beforeTransactionCompletion(JdbcCoordinatorImpl.java:447) ~[hibernate-core-5.3.12.Final.jar:5.3.12.Final]
    at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.beforeCompletionCallback(JdbcResourceLocalTransactionCoordinatorImpl.java:178) ~[hibernate-core-5.3.12.Final.jar:5.3.12.Final]
    at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.access$300(JdbcResourceLocalTransactionCoordinatorImpl.java:39) ~[hibernate-core-5.3.12.Final.jar:5.3.12.Final]
    at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.commit(JdbcResourceLocalTransactionCoordinatorImpl.java:271) ~[hibernate-core-5.3.12.Final.jar:5.3.12.Final]
    at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:104) ~[hibernate-core-5.3.12.Final.jar:5.3.12.Final]
    at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:533) ~[spring-orm-5.1.10.RELEASE.jar:5.1.10.RELEASE]
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:746) ~[spring-tx-5.1.10.RELEASE.jar:5.1.10.RELEASE]
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:714) ~[spring-tx-5.1.10.RELEASE.jar:5.1.10.RELEASE]
    at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:534) ~[spring-tx-5.1.10.RELEASE.jar:5.1.10.RELEASE]
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:305) ~[spring-tx-5.1.10.RELEASE.jar:5.1.10.RELEASE]
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98) ~[spring-tx-5.1.10.RELEASE.jar:5.1.10.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.1.10.RELEASE.jar:5.1.10.RELEASE]
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139) ~[spring-tx-5.1.10.RELEASE.jar:5.1.10.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.1.10.RELEASE.jar:5.1.10.RELEASE]
    at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:144) ~[spring-data-jpa-2.1.11.RELEASE.jar:2.1.11.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.1.10.RELEASE.jar:5.1.10.RELEASE]
    at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$ExposeRepositoryInvocationInterceptor.invoke(CrudMethodMetadataPostProcessor.java:364) ~[spring-data-jpa-2.1.11.RELEASE.jar:2.1.11.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.1.10.RELEASE.jar:5.1.10.RELEASE]
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:93) ~[spring-aop-5.1.10.RELEASE.jar:5.1.10.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.1.10.RELEASE.jar:5.1.10.RELEASE]
    at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:61) ~[spring-data-commons-2.1.11.RELEASE.jar:2.1.11.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.1.10.RELEASE.jar:5.1.10.RELEASE]
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212) ~[spring-aop-5.1.10.RELEASE.jar:5.1.10.RELEASE]
    at com.sun.proxy.$Proxy123.save(Unknown Source) ~[na:na]
    at com.mysoftware.service.CampaignService.save(CampaignService.java:83) ~[classes/:na]

(... more lines and no other cause in the stacktrace)

at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-9.0.26.jar:9.0.26]
    at java.lang.Thread.run(Thread.java:748) [na:1.8.0_222]

Ответы [ 2 ]

0 голосов
/ 10 октября 2019

Это была моя вина: я получаю RequestObject (CampaignRequest) через REST API, а затем использую DozerBeanMapper в контроллере REST с пользовательским конвертером бульдозера для преобразования из / в String и UUID:API получает UUID в виде строк (в запросе), а затем Dozer преобразует их в java.util.UUID (для использования в сущности).

В отладчике я обнаружил, что в соответствии с моей конфигурацией DozerMapper преобразуетодиночные свойства (то есть: id) в и из UUID или String без каких-либо проблем с использованием моего пользовательского преобразователя, однако для набора UUID Dozer отображает атрибут Set (входящий в запрос) в другой Set в Entity.

Я действительно не знаю, почему моя сущность, которая имеет строго типизированный атрибут Set<UUID>, позволяет Dozer установить для этого атрибута другой тип (Set<String>).

Теперь я изменил свой код, чтобы вручную преобразовать входящий набор (в запросе) в набор (в сущности), и ошибка исчезла. Это не была ошибка, связанная с отображением JPA, это была проблема, связанная с отображением Dozer. Этот код исправил проблему, но мне все еще нужно найти способ использовать Dozer для преобразования Set<String> в Set<UUID> (я все еще читаю это: http://dozer.sourceforge.net/documentation/collectionandarraymapping.html):

if (campaignRequest.getTargetFilesIds() != null)
{
    final HashSet<UUID> ids = new HashSet<>();
    campaignRequest.getTargetFilesIds().forEach(id -> ids.add(UUID.fromString(id)));
    campaign.setTargetFilesIds(ids);
}
0 голосов
/ 10 октября 2019

Вы должны добавить аннотацию @CollectionTable и указать соответствующие имена полей. Примерно так: @CollectionTable(name = "target_files_ids", joinColumns = @JoinColumn(name = "id")) Имя параметра в @CollectionTable - это имя таблицы, в которой будет храниться информация. Имя параметра в @Joincolumn - это имя поля в вашей сущности Campaign, которое будет использоваться дляидентифицируйте данные в таблице target_files_ids.

Для более глубокого понимания взгляните на этот пример. https://www.callicoder.com/hibernate-spring-boot-jpa-element-collection-demo/

Надеюсь, это поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...