Hibernate 6 can’t seem to resolve Custom Types specified in .hbm.xml files, throws MappingException

Hi,

We use .hbm.xml files along with the hbm2java task to generate entity classes from our mapping files. For a specific use case, we have defined a custom type, which we reference in these mapping files.
In Hibernate 5, this custom type was resolved without any issues. However, after upgrading to Hibernate 6, we are encountering a compilation error: org.hibernate.MappingException: Could not resolve named type : CustomTypeName

It seems Hibernate 6 is unable to recognize the custom type during compilation.

Any suggestions would be greatly appreciated.
Thanks in advance.

What does this custom type look like? Please share your hbm.xml mappings here if you wish for anyone to help you, but do note that the hbm xml format is no longer supported and will be official deprecated soon. Our suggestion would be to consider a migration to annotations, or at least to the supported orm.xml format.

hbm.xml file

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

<hibernate-mapping package="org.example.model">

    <class name="PersonalUser" table="personalUser">
        <id name="id_Checking" column="id" type="big_decimal">
            <generator class="assigned"/>
        </id>

        <property name="name" type="org.example.model.NameType">
            <column name="name"/>
            <column name="extendedname"/>
        </property>

    </class>

</hibernate-mapping>

This is our custom type implementation

package org.example.model;

import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.metamodel.spi.ValueAccess;
import org.hibernate.usertype.CompositeUserType;

import java.io.Serializable;

public class NameType implements CompositeUserType<NameData> {

    public static class NameMapper {
        String firstName;
        String lastName;
    }

    @Override
    public Object getPropertyValue(NameData component, int property) throws HibernateException {
        switch ( property ) {
            case 0:
                return component.getName();
            case 1:
                return component.getExtendedName();
        }
        return null;
    }

    @Override
    public NameData instantiate(ValueAccess valueAccess, SessionFactoryImplementor sessionFactory) {
        final String first = valueAccess.getValue( 0, String.class );
        final String last = valueAccess.getValue( 1, String.class );
        return new NameData( first, last );
    }

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

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

    @Override
    public boolean equals(NameData x, NameData y) {
        return x != null &&
                x == y && x.getName().equals(y.getName()) && x.getExtendedName().equals(y.getExtendedName());
    }

    @Override
    public int hashCode(NameData x) {
        return 0;
    }

    @Override
    public NameData deepCopy(NameData value) {
        return value;
    }

    @Override
    public boolean isMutable() {
        return false;
    }

    @Override
    public Serializable disassemble(NameData value) {
        return new String[] {value.getName(), value.extendedName};
    }

    @Override
    public NameData assemble(Serializable cached, Object owner) {
        final String[] parts = (String[]) cached;
        return new NameData( parts[0], parts[1] );
    }

    @Override
    public NameData replace(NameData detached, NameData managed, Object owner) {
        return null;
    }
}

This is the exception we are facing

org.hibernate.MappingException: Could not resolve named type org.example.model.NameType
        at org.hibernate.mapping.BasicValue.interpretExplicitlyNamedType(BasicValue.java:953)
        at org.hibernate.mapping.BasicValue.buildResolution(BasicValue.java:439)
        at org.hibernate.mapping.BasicValue.resolve(BasicValue.java:351)
        at org.hibernate.mapping.BasicValue.resolve(BasicValue.java:341)
        at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.lambda$processValueResolvers$6(InFlightMetadataCollectorImpl.java:1827)
        at java.base/java.util.ArrayList.removeIf(ArrayList.java:1765)
        at java.base/java.util.ArrayList.removeIf(ArrayList.java:1743)
        at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processValueResolvers(InFlightMetadataCollectorImpl.java:1826)
        at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processSecondPasses(InFlightMetadataCollectorImpl.java:1812)
        at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete(MetadataBuildingProcess.java:334)
        at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.build(MetadataBuildingProcess.java:129)
        at org.hibernate.boot.internal.MetadataBuilderImpl.build(MetadataBuilderImpl.java:449)
        at org.hibernate.boot.internal.MetadataBuilderImpl.build(MetadataBuilderImpl.java:101)
        at org.hibernate.boot.MetadataSources.buildMetadata(MetadataSources.java:214)
        at org.hibernate.tool.internal.metadata.NativeMetadataDescriptor.createMetadata(NativeMetadataDescriptor.java:51)
        at org.hibernate.tool.internal.export.common.AbstractExporter.buildMetadata(AbstractExporter.java:194)
        at org.hibernate.tool.internal.export.common.AbstractExporter.getMetadata(AbstractExporter.java:56)
        at org.hibernate.tool.internal.export.common.AbstractExporter.setupContext(AbstractExporter.java:164)
        at org.hibernate.tool.internal.export.java.JavaExporter.setupContext(JavaExporter.java:37)
        at org.hibernate.tool.internal.export.common.AbstractExporter.start(AbstractExporter.java:88)
        at org.hibernate.tool.ant.ExporterTask.execute(ExporterTask.java:54)
        at org.hibernate.tool.ant.HibernateToolTask.execute(HibernateToolTask.java:188)
        at org.apache.tools.ant.UnknownElement.execute(UnknownElement.java:292)
        at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
        at java.base/java.lang.reflect.Method.invoke(Method.java:580)
        at org.apache.tools.ant.dispatch.DispatchUtils.execute(DispatchUtils.java:99)
        at org.apache.tools.ant.Task.perform(Task.java:350)
        at org.apache.tools.ant.Target.execute(Target.java:449)
        at org.apache.tools.ant.Target.performTasks(Target.java:470)
        at org.apache.tools.ant.Project.executeSortedTargets(Project.java:1388)
        at org.apache.tools.ant.Project.executeTarget(Project.java:1361)
        at org.apache.tools.ant.helper.DefaultExecutor.executeTargets(DefaultExecutor.java:41)
        at org.apache.tools.ant.Project.executeTargets(Project.java:1251)
        at org.apache.tools.ant.Main.runBuild(Main.java:834)
        at org.apache.tools.ant.Main.startAnt(Main.java:223)
        at org.apache.tools.ant.launch.Launcher.run(Launcher.java:284)
        at org.apache.tools.ant.launch.Launcher.main(Launcher.java:101)

org.example.model.NameType is a CompositeUserType, but you’re mapping the name attribute as a simple property. This should be a component instead:

        <component name="name" type="org.example.model.NameType">
            <column name="name"/>
            <column name="extendedname"/>
        </component>

The <component> tag does not have a type attribute, so I used the class attribute instead. However, during hbm2java conversion using Hibernate Tools, it is generating a new NameType class with those two columns, rather than using the existing NameType class that we created by extending CompositeUserType.

Sorry, you should use the class attribute instead of the type for <component>, see e.g. this xml mapping from Hibernate’s test cases.