Michu93
Michu93

Reputation: 5727

Initial SessionFactory creation failed - org.hibernate.MappingException: An association from the table X refers to an unmapped class: Y

I am migrating application from Hibernate 4 to Hibernate 5. I can't win with naming strategy. Of course I have already read: hibernate ImprovedNamingStrategy overrides Table name in entity and ImprovedNamingStrategy no longer working in Hibernate 5

In hibernate.cfg.xml I have both:

<mapping resource="com/ubs/investor/cpss/domain/BonusHis.hbm.xml"/>
<mapping resource="com/ubs/investor/cpss/domain/Instrument.hbm.xml"/>

I already changed AnnotationConfiguration to Configuration and now I have:

private void reloadHibernateSessionFactoryFromConf(Map<String, String> prop) {
        try {
            sessionFactory = null;
            Configuration config = new Configuration(); //hibernate5

            for(Map.Entry<String, String> entry : prop.entrySet()) {
                config.setProperty(entry.getKey(), entry.getValue());
            }
            if(namingStrategy!=null){
                configuration.setNamingStrategy(namingStrategy); //code which I think spoil application
            }
            if(annotatedEntityPackages!=null){
                addAnnotatedClasses(config);
            }
            sessionFactory = config.configure().buildSessionFactory();
        } catch (final HibernateException e) {
            LOGGER.error("SessionFactory creation failed", e);
        }

and namingStrategy was put by:

<property name="namingStrategy">
            <bean class="org.hibernate.cfg.ImprovedNamingStrategy"/>
        </property>

I already tried to comment configuration.setNamingStrategy(namingStrategy); at all. I tried configuration.setPhysicalNamingStrategy(PhysicalNamingStrategyImpl.INSTANCE); but also CamelCase, UpperCase etc. and everytime error is the same. Whatever I do with this namingStrategy class won't be mapped.

Example class:

public class UpperCaseNamingStrategy extends PhysicalNamingStrategyStandardImpl {

    @Override
    public Identifier toPhysicalColumnName(Identifier name, JdbcEnvironment context) {
        return context.getIdentifierHelper().toIdentifier(
                StringUtils.upperCase(name.getText(), Locale.ENGLISH));
    }

    @Override
    public Identifier toPhysicalCatalogName(final Identifier name, final JdbcEnvironment context) {
        return context.getIdentifierHelper().toIdentifier(
                StringUtils.upperCase(name.getText(), Locale.ENGLISH));
    }

    @Override
    public Identifier toPhysicalSchemaName(final Identifier name, final JdbcEnvironment context) {
        return context.getIdentifierHelper().toIdentifier(
                StringUtils.upperCase(name.getText(), Locale.ENGLISH));
    }

    @Override
    public Identifier toPhysicalSequenceName(final Identifier name, final JdbcEnvironment context) {
        return context.getIdentifierHelper().toIdentifier(
                StringUtils.upperCase(name.getText(), Locale.ENGLISH));
    }

    @Override
    public Identifier toPhysicalTableName(final Identifier name, final JdbcEnvironment context) {
        return context.getIdentifierHelper().toIdentifier(
                StringUtils.upperCase(name.getText(), Locale.ENGLISH));
    }

}

but still I can see in logs:

org.hibernate.MappingException: An association from the table BONUS_HIS refers to an unmapped class: domain.Instrument at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:709) at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:746) at repository.legacy.HibernateSessionManager.reloadHibernateSessionFactoryFromConf

So what is implementation of org.hibernate.cfg.ImprovedNamingStrategy in hibernate 5?

@Edit

Actually I used:

public class PhysicalNamingStrategyImpl extends PhysicalNamingStrategyStandardImpl implements Serializable {

    public static final PhysicalNamingStrategyImpl INSTANCE = new PhysicalNamingStrategyImpl();

    @Override
    public Identifier toPhysicalTableName(Identifier name, JdbcEnvironment context) {
        return new Identifier(addUnderscores(name.getText()), name.isQuoted());
    }
   
    protected static String addUnderscores(String name) {
        final StringBuilder buf = new StringBuilder( name.replace('.', '_') );
        for (int i=1; i<buf.length()-1; i++) {
            if (
                    Character.isLowerCase( buf.charAt(i-1) ) &&
                            Character.isUpperCase( buf.charAt(i) ) &&
                            Character.isLowerCase( buf.charAt(i+1) )
            ) {
                buf.insert(i++, '_');
            }
        }
        return buf.toString().toLowerCase(Locale.ROOT);
    }
}

and completely removed:

<property name="namingStrategy">
     <bean class="org.hibernate.cfg.ImprovedNamingStrategy"/>
</property>

but I don't think it's correct solutions because I can still see: org.hibernate.MappingException: An association from the table BONUS_HIS refers to an unmapped class: domain.Instrument

Upvotes: 0

Views: 121

Answers (2)

Michu93
Michu93

Reputation: 5727

When using a mixed approach with annotations and XML, it is crucial to follow the correct order for creating the SessionFactory to avoid issues. The correct sequence is as follows:

Initialize the Configuration object:

Configuration config = new Configuration();

Add the annotated classes:

addAnnotatedClasses(config);

Build the SessionFactory:

sessionFactory = config.buildSessionFactory();

If this order is not followed, the XML configurations may override the annotations, leading to potential conflicts and errors.

Upvotes: 0

Siddhesh
Siddhesh

Reputation: 1173

Try following:

  1. Correct Configuration:

    // Set the Physical and Implicit Naming Strategies config.setPhysicalNamingStrategy(new PhysicalNamingStrategyImpl()); config.setImplicitNamingStrategy(ImplicitNamingStrategyLegacyJpaImpl.INSTANCE);

  2. Check Entity Mappings:

Ensure that all your entities are correctly annotated with @Entity and that all entity classes are registered in the configuration (i.e., listed in addAnnotatedClasses(config) or via config.addPackage("com.example")). The error you see often comes up when Hibernate cannot find an entity or tries to map an association with a non-existent class. Double-check that your mappings (tables, columns, and associations) are correct in your domain model.

  1. Fix Entity Name and Table Name Mappings: If you are using custom table or column names, make sure that those match the table names generated by your PhysicalNamingStrategy

example: @Table(name = "USER_ACCOUNT")

and your strategy converts userAccount to user_account, you will encounter issues unless the table is indeed named USER_ACCOUNT in the database.

Updated Code:

private void reloadHibernateSessionFactoryFromConf(Map<String, String> prop) {
    try {
        sessionFactory = null;
        Configuration config = new Configuration(); //hibernate5

        // Set properties
        for (Map.Entry<String, String> entry : prop.entrySet()) {
            config.setProperty(entry.getKey(), entry.getValue());
        }

        // Set naming strategies
        config.setPhysicalNamingStrategy(new PhysicalNamingStrategyImpl());
        config.setImplicitNamingStrategy(ImplicitNamingStrategyLegacyJpaImpl.INSTANCE);

        // Add annotated classes
        if (annotatedEntityPackages != null) {
            addAnnotatedClasses(config);
        }

        // Build session factory
        sessionFactory = config.configure().buildSessionFactory();
    } catch (final HibernateException e) {
        LOGGER.error("SessionFactory creation failed", e);
    }
}

Upvotes: 1

Related Questions