尝试使用 Erwin Vervaet 的框架存储时间集合并获取 ClassCastException

Posted

技术标签:

【中文标题】尝试使用 Erwin Vervaet 的框架存储时间集合并获取 ClassCastException【英文标题】:Trying to store a temporal collection with Erwin Vervaet's framework and getting ClassCastException 【发布时间】:2019-09-21 07:32:01 【问题描述】:

我正在尝试使用 Erwin Vervaet 的 Bitemporal framework 与 Hibernate 一起存储时间集合,而不是他的示例中的时间属性。 (有框架的介绍here)

我正在尝试存储随时间变化的地址集合,即一个人可以同时拥有多个地址,而这组地址可以改变。

映射有效,我的意思是表是在数据库中创建的,但我收到以下运行时错误:

java.lang.ClassCastException: com.ervacon.bitemporal.AddressSet cannot be cast to java.util.Collection

我不明白这个错误。我知道当 Hibernate 尝试构建 Personaddresses 包时正在执行转换,但为什么它会得到 ClassCastException?如果我在entity-name="AddressSet" 映射中注释掉value 的映射,我没有错误,但地址没有保存。所以问题出在我认为的映射中。

我也不明白我想要实现的目标是否可以用这个框架来完成。

你能帮帮我吗?

我如何修改 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;
    



地址集

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)

编辑:将AddressSet 中的Set 更改为List,因为在使用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)

【问题讨论】:

【参考方案1】:

问题出在你的映射上,BitemporalWrapper&lt;AddressSet&gt; 应该将 value 映射到 AddressSet

<class name="com.ervacon.bitemporal.Person">
    <id name="id" type="long">
        <generator class="native"/>
    </id>

    <property name="name"/>
    <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.BitemporalWrapper" entity-name="AddressSet">
    <id name="id" type="long">
        <generator class="native"/>
    </id>

    <component name="value" class="com.ervacon.bitemporal.AddressSet">
        <bag name="addressSet" cascade="all-delete-orphan">
            <key column="addressSet_id" not-null="true" update="false"/>
            <one-to-many entity-name="Address"/>
        </bag>
    </component>

    <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.Address" entity-name="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>

在寻找解决方案时我发现,获取版本化实体是在 java 中完成的,not in a query。所以我个人不会走这条路。


编辑:来自this answer

当您尝试持久化多个时,Hibernate 会显示此错误 实体实例共享相同的集合引用(即 集合标识与集合相等性对比)。

所以我稍微深入研究了双时间框架,我认为,这个问题是here,它基本上是用新的记录间隔增加了附加值,但是value is not copied,在大多数情况下都不是问题。但是由于我们的对象在两个 BitemporalWrappers 中使用并且它具有相同的集合引用(因为它的对象相同),所以会引发异常。

为了证明我的理论(老实说,这对我来说有点薄冰;我不确定我的理解是否正确)我对框架进行了以下更改:V 的类型实现Serializabe,所以我克隆 BittemporalWrapper 时可以使用 commons-lang3 SerializationUtils 并返回 V value 的副本:

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.9</version>
</dependency>



public class BitemporalWrapper<V extends Serializable> implements Bitemporal, Serializable 

...
    @Override
    public Bitemporal copyWith(Interval validityInterval) 
        // force record interval to be 'from now'
        return new BitemporalWrapper<>(SerializationUtils.clone(value), validityInterval);
    
...


public class WrappedBitemporalProperty<V extends Serializable> extends BitemporalProperty<V, BitemporalWrapper<V>>  ...  

public class BitemporalProperty<V extends Serializable, T extends Bitemporal> implements Serializable  .. 

现在测试通过了。如果您有兴趣,我可以分享我的更改。

【讨论】:

谢谢,您的解决方案几乎没问题。你能解释一下为什么需要component 并且不能像 Vervaet 在示例中那样直接使用包吗?而且,你能帮我解决我现在遇到的错误吗? (请参阅帖子底部的编辑部分) 我不知道你的意思是这个例子,因为演示文稿包含他们的测试用例示例。看看这里github.com/klr8/bitemporal/blob/master/src/test/resources/com/…。值BitemporalWrapper 的映射是作为组件的实体。这就是ClassCastException 的原因,因为映射到包(集合)不能转换为AddressSet。我还更新了测试用例,将addressSet 的类型更改为您提到的列表,但我没有得到任何异常。你有什么改变吗? “示例”是指您所指的测试用例,但我错了(完全错过了),Vervaet 也使用了component,谢谢您指出。我没有更改任何其他内容,但是在名为“测试”的文件中,如果我设置addressSet(使用johnDoe.addresses().set(...))测试通过,但如果我也设置addressSet2,我得到共享引用错误。 当您回答原始问题时,我奖励您赏金,但在结束问题之前,我也对您对框架所做的更改感兴趣。除了您在此处发布的更改之外,还有其他更改吗? 出于序列化目的,我创建了AddressSet public 的空构造函数,还添加了getter 和setter。我不知道有任何其他更改。您还有其他问题吗?

以上是关于尝试使用 Erwin Vervaet 的框架存储时间集合并获取 ClassCastException的主要内容,如果未能解决你的问题,请参考以下文章

ERwin创建逻辑模型

将 DDL 导入到 CA Erwin Data Modeller r9.64 并带有注释

ERwin逻辑模型

通过ERWIN API 实现中文注释(Definition)批量替换成Attributes

ERwin DM Reverse Engineer 逆向工程介绍

在 Django REST 框架中使用 JWT 时,刷新令牌和访问令牌存储在哪里?