0

I'm migrating a project from Spring Boot 2.7.x to 3.0.x. One of my entities has a collection with a composite type:

@Entity
@Audited
public class Specialist {

    @Id
    @GeneratedValue
    private Long id;

    @ElementCollection
    @CompositeType(QualificationConverter.class)
    private Set<Qualification> qualifications;

    // ... 
}

public class Qualification implements Serializable {

    private LocalDate date = LocalDate.now();
    private String customData;

    // ...
}

public class Expert extends Qualification {
    // ...
}

public class Professional extends Qualification {
    // ...
}

The converter class (irrelevant parts ommitted):

public class QualificationConverter implements CompositeUserType<Qualification> {

    @Override
    public Object getPropertyValue(Qualification qualification, int i) throws HibernateException {
        return switch (i) {
            case 0 -> qualification.getCustomData();
            case 1 -> qualification.getDate();
            case 2 -> qualification.getClass().getName();
            default -> null;
        };
    }

    @Override
    public Qualification instantiate(ValueAccess valueAccess, SessionFactoryImplementor sessionFactoryImplementor) {
        String type = valueAccess.getValue(2, String.class);
        try {
            QualificationBuilder builder = (QualificationBuilder) Class.forName(type).getMethod("builder").invoke(null);
            return builder.customData(valueAccess.getValue(0, String.class))
                    .date(valueAccess.getValue(1, LocalDate.class))
                    .build();
        } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException | ClassNotFoundException ex) {
            throw new HibernateException(ex);
        }
    }

    @Override
    public Class<?> embeddable() {
        return QualificationMapper.class;
    }

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

    // ...

    public static class QualificationMapper {

        String customData;
        LocalDate date;
        String type;

    }
}

When I start the application, Hibernate Envers logs the audit mapping for qualifications collection:

<hibernate-mapping xmlns="http://www.hibernate.org/xsd/orm/hbm">
    <class table="specialist_qualifications_AUD" entity-name="specialist_qualifications_AUD">
        <composite-id name="originalId">
            <key-many-to-one class="org.hibernate.envers.DefaultRevisionEntity" name="REV">
                <column name="REV"/>
            </key-many-to-one>
            <key-property name="REVTYPE" type="org.hibernate.envers.internal.entities.RevisionTypeType"/>
            <key-property name="Specialist_id">
                <column name="specialist_id"/>
                <type name="long">
                    <param name="org.hibernate.type.ParameterType.primaryKey">false</param>
                    <param name="org.hibernate.type.ParameterType.dynamic">true</param>
                    <param name="org.hibernate.type.ParameterType.returnedClass">java.lang.Long</param>
                    <param name="org.hibernate.type.ParameterType.accessType">field</param>
                    <param name="org.hibernate.type.ParameterType.entityClass">com.example.hibernate6enverscompositeusertype.domain.Specialist</param>
                    <param name="org.hibernate.type.ParameterType.propertyName">id</param>
                </type>
            </key-property>
            <key-property name="SETORDINAL" type="integer">
                <column name="SETORDINAL"/>
            </key-property>
        </composite-id>
    </class>
</hibernate-mapping>

This is not what I expect nor want. Instead of the setordinal column I need the columns customData, date and type.

I read the docs twice, googled, searched this site, and hibernate issues but couldn't find any solution. I tried adding @Colums or @AttributeOverride annotations but all without success.

How can I tell Envers to generate the same columns in the audit table as in the collection table?

Of course, it worked with Spring Boot 2.7.x and the old @Type(Def) annotations and implementations.

1 Answers1

0

This looks like a bug to me, so please create an issue in the issue tracker(https://hibernate.atlassian.net) with a test case(https://github.com/hibernate/hibernate-test-case-templates/blob/master/orm/hibernate-orm-6/src/test/java/org/hibernate/bugs/JPAUnitTestCase.java) that reproduces the issue. Don't forget to report back the issue you created ;)

Christian Beikov
  • 15,141
  • 2
  • 32
  • 58