Я пытаюсь использовать Битемпоральный фреймворк Эрвина Вервеета для хранения в Hibernate временную коллекцию вместо временного свойства, как в его примере.
(презентация рамок здесь )
Я пытаюсь сохранить коллекцию адресов, которые со временем меняются, то есть человек может иметь несколько адресов одновременно, и этот набор адресов может меняться.
Отображение работает, я имею в виду таблицы создаются в БД, но я получаю следующую ошибку времени выполнения:
java.lang.ClassCastException: com.ervacon.bitemporal.AddressSet cannot be cast to java.util.Collection
Я не понимаю ошибки. Я понимаю, что приведение происходит, когда Hibernate пытается собрать мешок addresses
из Person
, но почему он получает ClassCastException
? Если я закомментирую отображение value
в отображении entity-name="AddressSet"
, у меня не будет ошибок, но адреса не сохраняются. Так что проблема в том отображении, которое я считаю.
Я также не понимаю, можно ли добиться того, чего я пытаюсь достичь, с помощью этого фреймворка.
Вы можете мне помочь?
Как я изменил пример Vervaet: я добавил класс AddressSet и изменил отображение Hibernate, Person и тестовый класс
Участвуют следующие классы:
Человек
/*
* (c) Copyright Ervacon 2016.
* All Rights Reserved.
*/
package com.ervacon.bitemporal;
import java.io.Serializable;
import java.util.Collection;
import java.util.LinkedList;
public class Person implements Serializable {
private Long id;
private String name;
private Collection<BitemporalWrapper<AddressSet>> addresses = new LinkedList<>();
private Collection<BitemporalWrapper<Boolean>> alive = new LinkedList<>();
/**
* For Hibernate.
*/
@SuppressWarnings("unused")
private Person() {
}
public Person(String name) {
if (name == null) {
throw new IllegalArgumentException("Name is required");
}
this.name = name;
}
public Long getId() {
return id;
}
public String getName() {
return name;
}
public WrappedBitemporalProperty<AddressSet> addresses() {
return new WrappedBitemporalProperty<>(addresses);
}
public WrappedBitemporalProperty<Boolean> alive() {
return new WrappedBitemporalProperty<>(alive);
}
@Override
public String toString() {
return getName();
}
}
Адрес
/*
* (c) Copyright Ervacon 2016.
* All Rights Reserved.
*/
package com.ervacon.bitemporal;
import java.io.Serializable;
public class Address implements Serializable {
private String line1;
private String line2;
private String line3;
private long id;
/**
* For Hibernate.
Address.java*/
@SuppressWarnings("unused")
private Address() {
}
public Address(String line1, String line2, String line3) {
this.line1 = line1;
this.line2 = line2;
this.line3 = line3;
}
public String getLine1() {
return line1;
}
public String getLine2() {
return line2;
}
public String getLine3() {
return line3;
}
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (obj instanceof Address) {
Address other = (Address) obj;
return other.line1.equals(this.line1)
&& other.line2.equals(this.line2)
&& other.line3.equals(this.line3);
}
return false;
}
@Override
public int hashCode() {
return this.line1.hashCode() + this.line2.hashCode() + this.line3.hashCode();
}
@Override
public String toString() {
return this.line1 + " " + line2 + " " + line3;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
}
AddressSet
package com.ervacon.bitemporal;
import java.io.Serializable;
import java.util.Set;
public class AddressSet implements Serializable {
private List<Address> addressSet;
private long id;
private AddressSet() {
}
public AddressSet(List<Address> a) {
this.addressSet = a;
}
public List<Address> getAddressSet() {
return addressSet;
}
public void setAddressSet(List<Address> addressSet) {
this.addressSet = addressSet;
}
}
Отображение:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping default-access="field">
<class name="com.ervacon.bitemporal.BitemporalWrapper" entity-name="AddressSet">
<id name="id" type="long">
<generator class="native"/>
</id>
<bag name="value">
<key column="addressSet_id"/>
<one-to-many class="com.ervacon.bitemporal.Address"/>
</bag>
<property name="validityInterval" type="com.ervacon.bitemporal.support.PersistentInterval">
<column name="validityStart"/>
<column name="validityEnd"/>
</property>
<property name="recordInterval" type="com.ervacon.bitemporal.support.PersistentInterval">
<column name="recordStart"/>
<column name="recordEnd"/>
</property>
</class>
<class name="com.ervacon.bitemporal.Person">
<id name="id" type="long">
<generator class="native"/>
</id>
<property name="name"/>
<!-- <bag name="address" cascade="all-delete-orphan">
<key column="person_id" not-null="true" update="false"/>
<one-to-many entity-name="Address"/>
</bag>
-->
<bag name="addresses" cascade="all-delete-orphan">
<key column="person_id" not-null="true" update="false"/>
<one-to-many entity-name="AddressSet"/>
</bag>
<bag name="alive" cascade="all-delete-orphan">
<key column="person_id" not-null="true" update="false"/>
<one-to-many entity-name="Alive"/>
</bag>
</class>
<class name="com.ervacon.bitemporal.Address">
<id name="id" type="long">
<generator class="native"/>
</id>
<property name="line1"/>
<property name="line2"/>
<property name="line3"/>
</class>
<class name="com.ervacon.bitemporal.BitemporalWrapper" entity-name="Alive">
<id name="id" type="long">
<generator class="native"/>
</id>
<property name="value" type="boolean"/>
<property name="validityInterval" type="com.ervacon.bitemporal.support.PersistentInterval">
<column name="validityStart"/>
<column name="validityEnd"/>
</property>
<property name="recordInterval" type="com.ervacon.bitemporal.support.PersistentInterval">
<column name="recordStart"/>
<column name="recordEnd"/>
</property>
</class>
</hibernate-mapping>
Тест
package com.ervacon.bitemporal;
import java.util.ArrayList;
import java.util.List;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.junit.Before;
import org.junit.Test;
public class HibernateTest {
private SessionFactory sessionFactory;
@Before
public void setUp() {
System.err.println("Before");
try {
sessionFactory = new Configuration().configure().buildSessionFactory();
} catch (HibernateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//@After
public void tearDown() throws Exception {
sessionFactory.close();
TimeUtils.clearReference();
}
@Test
public void testPersistence() {
System.err.println("Testing");
Session session = sessionFactory.openSession();
session.beginTransaction();
TimeUtils.setReference(TimeUtils.day(4, 4, 1975));
Person johnDoe = new Person("John Doe");
johnDoe.alive().set(
true,
TimeUtils.from(TimeUtils.day(3, 4, 1975)));
AddressSet addressSet = new AddressSet(new ArrayList<>());
List<Address> addressList1 = new ArrayList<>();
addressList1.add(new Address("Address1.1", "", ""));
addressSet.setAddressSet(addressList1);
johnDoe.addresses().set(
addressSet,
TimeUtils.from(TimeUtils.day(3, 4, 1975)));
AddressSet addressSet2 = new AddressSet(new ArrayList<>());
List<Address> addressList2 = new ArrayList<>();
addressList2.add(new Address("Address2.1", "", ""));
addressSet2.setAddressSet(addressList2);
johnDoe.addresses().set(
addressSet2,
TimeUtils.from(TimeUtils.day(3, 4, 1976)));
try {
session.save(johnDoe);
session.getTransaction().commit();
session.close();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Полное исключение:
java.lang.ClassCastException: com.ervacon.bitemporal.AddressSet cannot be cast to java.util.Collection
at org.hibernate.type.BagType.wrap(BagType.java:35)
at org.hibernate.event.internal.WrapVisitor.processArrayOrNewCollection(WrapVisitor.java:91)
at org.hibernate.event.internal.WrapVisitor.processCollection(WrapVisitor.java:56)
at org.hibernate.event.internal.AbstractVisitor.processValue(AbstractVisitor.java:104)
at org.hibernate.event.internal.WrapVisitor.processValue(WrapVisitor.java:108)
at org.hibernate.event.internal.AbstractVisitor.processEntityPropertyValues(AbstractVisitor.java:59)
at org.hibernate.event.internal.AbstractSaveEventListener.visitCollectionsBeforeSave(AbstractSaveEventListener.java:354)
at org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:260)
at org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:182)
at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:113)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:192)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:177)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:97)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:73)
at org.hibernate.internal.SessionImpl.fireSaveOrUpdate(SessionImpl.java:651)
at org.hibernate.internal.SessionImpl.saveOrUpdate(SessionImpl.java:643)
at org.hibernate.engine.spi.CascadingActions$5.cascade(CascadingActions.java:218)
at org.hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:391)
at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:316)
at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:155)
at org.hibernate.engine.internal.Cascade.cascadeCollectionElements(Cascade.java:424)
at org.hibernate.engine.internal.Cascade.cascadeCollection(Cascade.java:356)
at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:319)
at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:155)
at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:104)
at org.hibernate.event.internal.AbstractSaveEventListener.cascadeAfterSave(AbstractSaveEventListener.java:445)
at org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:281)
at org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:182)
at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:113)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:192)
at org.hibernate.event.internal.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(DefaultSaveEventListener.java:38)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:177)
at org.hibernate.event.internal.DefaultSaveEventListener.performSaveOrUpdate(DefaultSaveEventListener.java:32)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:73)
at org.hibernate.internal.SessionImpl.fireSave(SessionImpl.java:682)
at org.hibernate.internal.SessionImpl.save(SessionImpl.java:674)
at org.hibernate.internal.SessionImpl.save(SessionImpl.java:669)
at com.ervacon.bitemporal.HibernateTest.testPersistence(HibernateTest.java:60)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:678)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
edit : изменено Set
на List
в AddressSet
, потому что после использования решения Tijkijiki я получил ошибку, когда Hibernate собирал пакет. После этого тест пройден.
Но я добавил два набора AddressSet
к тесту (который теперь изменяется с момента первоначальной публикации), и теперь я получаю эту ошибку, кто-то может объяснить мне, почему? Объекты AddressSet кажутся мне другими.
ERROR: HHH000346: Error during managed flush [Found shared references to a collection: AddressSet.value.addressSet]
org.hibernate.HibernateException: Found shared references to a collection: AddressSet.value.addressSet
at org.hibernate.engine.internal.Collections.processReachableCollection(Collections.java:182)
at org.hibernate.event.internal.FlushVisitor.processCollection(FlushVisitor.java:42)
at org.hibernate.event.internal.AbstractVisitor.processValue(AbstractVisitor.java:104)
at org.hibernate.event.internal.AbstractVisitor.processValue(AbstractVisitor.java:65)
at org.hibernate.event.internal.AbstractVisitor.processValues(AbstractVisitor.java:44)
at org.hibernate.event.internal.AbstractVisitor.processComponent(AbstractVisitor.java:85)
at org.hibernate.event.internal.AbstractVisitor.processValue(AbstractVisitor.java:110)
at org.hibernate.event.internal.AbstractVisitor.processValue(AbstractVisitor.java:65)
at org.hibernate.event.internal.AbstractVisitor.processEntityPropertyValues(AbstractVisitor.java:59)
at org.hibernate.event.internal.DefaultFlushEntityEventListener.onFlushEntity(DefaultFlushEntityEventListener.java:155)
at org.hibernate.event.internal.AbstractFlushingEventListener.flushEntities(AbstractFlushingEventListener.java:216)
at org.hibernate.event.internal.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:85)
at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:38)
at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1295)
at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:468)
at org.hibernate.internal.SessionImpl.flushBeforeTransactionCompletion(SessionImpl.java:3135)
at org.hibernate.internal.SessionImpl.beforeTransactionCompletion(SessionImpl.java:2352)
at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.beforeTransactionCompletion(JdbcCoordinatorImpl.java:491)
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.beforeCompletionCallback(JdbcResourceLocalTransactionCoordinatorImpl.java:147)
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.access$100(JdbcResourceLocalTransactionCoordinatorImpl.java:38)
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.commit(JdbcResourceLocalTransactionCoordinatorImpl.java:231)
at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:65)
at com.ervacon.bitemporal.HibernateTest.testPersistence(HibernateTest.java:77)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:678)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)