Problems with CompositeUserType when returning an abstract class

<component name="mainContact" class="ContactUserType">
    <property column="CUSTOMER_CONTACT1" name="name"/>
    <property formula="customer1" name="customerName"/>
</component>
public class ContactUserType implements CompositeUserType<Contact> {
    @Override
    public Class<?> embeddable() {
        return ContactData.class;
    }
    
    @Override
    public Class<?> embeddable() {
        return ContactEmbeddable.class;
    }

    @Override
    public Class<Contact> returnedClass() {
        return Contact.class;  // Contact is an abstract class
//, which implements getters and setters for name and customerName
    }

    public static class ContactEmbeddable {
        private String name;
        private String customerName;
        // getters, setters
    }

@Override
    public Contact instantiate(ValueAccess values, SessionFactoryImplementor sessionFactory) {
        String contactName = values.getValue(0, String.class);
        String customerName = values.getValue(1, String.class);
        // various logic to conditionally return different implementations of Contact abstract
    }

    // other methods excluded for brevity    
}

My code keeps failing with

Exception Details:
  Location:
    ContactUserType$ContactEmbeddable$HibernateAccessOptimizeracustomerNameaname.getPropertyValues(Ljava/lang/Object;)[Ljava/lang/Object; @12: invokevirtual
  Reason:
    Type 'ContactUserType$ContactEmbeddable' (current frame, stack[3]) is not assignable to 'Contact'
  Current Frame:
    bci: @12
    flags: { }
    locals: { 'ContactUserType$ContactEmbeddable$HibernateAccessOptimizeracustomerNameaname', 'java/lang/Object' }
    stack: { '[Ljava/lang/Object;', '[Ljava/lang/Object;', integer, 'ContactUserType$ContactEmbeddable' }
  Bytecode:
    0000000: 1209 bd00 0459 120c 2bc0 0015 b600 1b53
    0000010: 5912 0f2b c000 15b6 001e 53b0

	at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:342)
	at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:113)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1707)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1452)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:619)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542)
	at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335)
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:955)
	at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:929)
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:591)
	at org.unitils.spring.util.ApplicationContextManager.createInstanceForValues(ApplicationContextManager.java:117)

org.hibernate.orm:hibernate-core:6.6.31.Final

I have similar embedded mappings of non-abstract classes and they seem to be working ok, it’s just any abstracts that seem to be experiencing this issue.

Please try to create a reproducer with our test case template and if you are able to reproduce the issue, create a bug ticket in our issue tracker and attach that reproducer.

@beikov In reproducing the issue I have found the root cause but I’m not sure if it’s a Hibernate bug or a problem with my implementation.

It’s not anything to do with abstract classes, that was just a coincidence in my project… What I found was that any access properties within the CompositeUserType, or the parent which has that property, are seemingly ignored. Only the value of the default-access property on the main hibernate-mapping is taken into account, so…

<hibernate-mapping default-lazy="false" auto-import="false">
    <class name="entities.Job" table="Job">
        <id name="jobNumber"/>
        <component name="parent" class="entities.Parent" access="field"> <!-- ❌ doesn't work -->
            <component name="mainContact" class="user_types.CustomerContactUserType" access="field"> <!-- ❌ doesn't work -->
                <property name="name" column="CUSTOMER_CONTACT1" />
                <property name="customerName" formula="customer1" />
            </component>
        </component>
    </class>
</hibernate-mapping>
<hibernate-mapping default-lazy="false" auto-import="false" 
default-access="field"> <!-- âś… works -->
    <class name="entities.Job" table="Job">
        <id name="jobNumber"/>
        <component name="parent" class="entities.Parent">
            <component name="mainContact" class="user_types.CustomerContactUserType">
                <property name="name" column="CUSTOMER_CONTACT1" />
                <property name="customerName" formula="customer1" />
            </component>
        </component>
    </class>
</hibernate-mapping>

It seems a bug to me as there may be use cases where the main mapping file would need to stay at property access. If you agree I’ll continue with making the issue.

Not sure why you’re explicitly mentioning

but then your example only defines the access type of components, not the properties within the CompositeUserType component.

Since you are in control of the ContactEmbeddable class, you can put the annotations on either fields or getters, as well as annotate the class itself with @Access(FIELD) to configure this.

I don’t really know what you’re trying to achieve or what the exact issue is, so if you still have a problem, please try to create a reproducer with our test case template and share that here.

Sorry, my wording was a bit confusing - when I said “properties within” I meant the actual attributes for the <component …> tag. I’d assumed that having the component set to <component ...access="field"> would also apply to all the <property> child elements, but it appears I was wrong.

Setting the access type on the <property...> has achieved the desired outcome, thanks for your help!