Hi,
I’m upgrading my application from Hibernate 5 to 6.4.4 with Java 17. Migrated my composite user type to use new CompositeType implementation.
Mappings:
@MappedSuperclass
public abstract class PersistentEntity {
@Id
@GeneratedValue(strategy= GenerationType.TABLE)
private Long id;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
protected Object clone() throws CloneNotSupportedException {
PersistentEntity clone = PersistentEntity.class.cast(super.clone());
clone.id = null;
return clone;
}
}
@MappedSuperclass
public abstract class TemporalWrapper <V> extends PersistentEntity {
@Embedded
@AttributeOverride(name = "firstName", column = @Column(name = "firstName"))
@AttributeOverride(name = "lastName", column = @Column(name = "lastName"))
@CompositeType(NameCompositeUserType.class)
public Name name;
public Name getName() {
return name;
}
public void setName(Name name) {
this.name = name;
}
protected TemporalWrapper() {
}
public TemporalWrapper(V value){
setValue(value);
}
protected abstract void setValue(V value);
}
@MappedSuperclass
public class Temporal<T> extends TemporalWrapper<T> {
@Embedded
private T value;
public T getValue() {
return value;
}
public void setValue(T value) {
this.value = value;
}
protected Temporal() {}
protected Temporal(T state) {
super(state);
}
public boolean equals(Object obj) {
Temporal<T> other = (Temporal<T>)obj;
if (other == null) return false;
return this.getId() == other.getId();
}
}
My entity class
@Entity
@Table(name = "User")
public class User extends PersistentEntity {
@Entity
@Table(name = "UserTemporal")
public static class Address extends Temporal<AddressRelation> {
public Address() {}
public Address(User.AddressRelation value) {
super(value);
}
}
@Embeddable
public static class AddressRelation {
@ManyToOne
@Cascade(value = { org.hibernate.annotations.CascadeType.ALL, org.hibernate.annotations.CascadeType.DELETE })
@JoinColumn(name = "objektId")
public User objekt;
public AddressRelation() {}
public User getUser() {
return objekt;
}
public void setUser(User objekt) {
this.objekt = objekt;
}
}
}
Composite class:
public class Name implements Serializable {
private final String first;
private final String last;
public Name(String first, String last) {
this.first = first;
this.last = last;
}
public String firstName() {
return first;
}
public String lastName() {
return last;
}
}
and implementation of CompositeUserType
public class NameCompositeUserType implements CompositeUserType<Name> {
public NameCompositeUserType() {
}
public static class NameMapper {
String firstName;
String lastName;
}
@Override
public Class<?> embeddable() {
return NameMapper.class;
}
@Override
public Class<Name> returnedClass() {
return Name.class;
}
@Override
public Name instantiate(ValueAccess valueAccess, SessionFactoryImplementor sessionFactory) {
final String first = valueAccess.getValue( 0, String.class );
final String last = valueAccess.getValue( 1, String.class );
return new Name(first, last);
}
@Override
public Object getPropertyValue(Name component, int property) throws HibernateException {
switch ( property ) {
case 0:
return component.firstName();
case 1:
return component.lastName();
}
return null;
}
@Override
public boolean equals(Name x, Name y) {
return x == y || x != null && Objects.equals( x.firstName(), y.firstName() )
&& Objects.equals( x.lastName(), y.lastName() );
}
@Override
public int hashCode(Name x) {
return Objects.hash( x.firstName(), x.lastName() );
}
@Override
public Name deepCopy(Name value) {
return value;
}
@Override
public boolean isMutable() {
return false;
}
@Override
public Serializable disassemble(Name value) {
return new String[] { value.firstName(), value.lastName() };
}
@Override
public Name assemble(Serializable cached, Object owner) {
final String[] parts = (String[]) cached;
return new Name( parts[0], parts[1] );
}
@Override
public Name replace(Name detached, Name managed, Object owner) {
return detached;
}
}
During the startup I’m getting such an error:
Caused by: org.hibernate.InstantiationException: Could not instantiate managed bean directly 'org.hibernate.bugs.Name' due to: org.hibernate.bugs.Name.<init>()
at org.hibernate.resource.beans.internal.FallbackBeanInstanceProducer.produceBeanInstance(FallbackBeanInstanceProducer.java:46)
at org.hibernate.mapping.Component.createCompositeUserType(Component.java:345)
at org.hibernate.mapping.Component.getType(Component.java:373)
at org.hibernate.mapping.Component.getType(Component.java:66)
at org.hibernate.metamodel.internal.AttributeFactory.determineAttributeMetadata(AttributeFactory.java:404)
at org.hibernate.metamodel.internal.AttributeFactory.buildAttribute(AttributeFactory.java:112)
at org.hibernate.metamodel.internal.AttributeFactory.buildAttribute(AttributeFactory.java:98)
at org.hibernate.metamodel.internal.MetadataContext.buildAttribute(MetadataContext.java:278)
at org.hibernate.metamodel.internal.MetadataContext.wrapUp(MetadataContext.java:362)
at org.hibernate.metamodel.model.domain.internal.JpaMetamodelImpl.processJpa(JpaMetamodelImpl.java:524)
at org.hibernate.metamodel.model.domain.internal.MappingMetamodelImpl.finishInitialization(MappingMetamodelImpl.java:214)
at org.hibernate.internal.SessionFactoryImpl.initializeMappingModel(SessionFactoryImpl.java:364)
My question is whether is this mapping is correct?
For some reason hibernate tries to create an instance of class that represents property and cast to CompositeUserType instead of to do it with implementation NameCompositeUserType that I provided.
I created a reproducer based on your test case template.
Regards,
ToD