I’m having a problem in a Spring Configuration creating a bean which extends AnnotationSessionFactoryBean.
Here’s the definition of the class:
public class ExtendedAnnotationSessionFactoryBean extends AnnotationSessionFactoryBean {
private String[] basePackages;
private ClassLoader beanClassLoader;
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("ExtendedAnnotationSessionFactoryBean, in afterPropertiesSet");
Collection<Class<?>> entities = new ArrayList<Class<?>>();
ClassPathScanningCandidateComponentProvider scanner = this.createScanner();
for (String basePackage : this.basePackages) {
this.findEntities(scanner, entities, basePackage);
}
this.setAnnotatedClasses(entities.toArray(new Class<?>[entities.size()]));
super.afterPropertiesSet();
}
private ClassPathScanningCandidateComponentProvider createScanner() {
System.out.println("ExtendedAnnotationSessionFactoryBean, in createScanner");
ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false);
scanner.addIncludeFilter(new AnnotationTypeFilter(Entity.class));
return scanner;
}
private void findEntities(ClassPathScanningCandidateComponentProvider scanner,
Collection<Class<?>> entities, String basePackage) {
System.out.println("ExtendedAnnotationSessionFactoryBean, in findEntities");
Set<BeanDefinition> annotatedClasses = scanner.findCandidateComponents(basePackage);
for (BeanDefinition bd : annotatedClasses) {
String className = bd.getBeanClassName();
System.out.println("ExtendedAnnotationSessionFactoryBean, className: " + className);
Class<?> type = ClassUtils.resolveClassName(className, this.beanClassLoader);
entities.add(type);
}
}
public void setBasePackage(String basePackage) {
this.basePackages = new String[]{basePackage};
}
public void setBasePackages(String[] basePackages) {
this.basePackages = basePackages;
}
@Override
public void setBeanClassLoader(ClassLoader beanClassLoader) {
this.beanClassLoader = beanClassLoader;
}
}
Here’s how it’s configured:
<b:bean id="sessionFactory" class="com.mycompany.spring.ExtendedAnnotationSessionFactoryBean">
<b:property name="dataSource" ref="dataSource" />
<b:property name="configurationClass" value="org.hibernate.cfg.AnnotationConfiguration" />
<b:property name="hibernateProperties" ref="hibernateProperties" />
<b:property name="entityInterceptor" ref="baseEntityInterceptor" />
<b:property name="basePackages">
<b:list>
<b:value>com.mycompany.entities</b:value>
<b:value>com.mycompany.entities1_1</b:value>
</b:list>
</b:property>
</b:bean>
The source code in each package (com.mycompany.entities, com.mycompany.entities1_1) is identical except that the catalog is defined in the second one:
@Table(catalog="myDatabase1_1", name = "mytablename1")
When I run a test I get a crash with a stack trace which states that the same entity name is being used twice (although they are in different packages). At the end of the stack trace, it suggests setting the “auto-import” to false:
Caused by: org.hibernate.DuplicateMappingException: duplicate import: MyTableName1 refers to both com.mycompany.entities1_1.MyTableName1 and com.mycompany.entities.MyTableName1 (try using auto-import="false")
Questions: What auto-import mean, why would it work, and where would I specify it?
Here’s the entire stack trace:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sessionFactory' defined in URL [file:WEB-INF/myconfiguration.xml]: Invocation of init method failed; nested exception is org.hibernate.AnnotationException: Use of the same entity name twice: MyTableName1
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sessionFactory' defined in URL [file:WEB-INF/myconfiguration.xml]: Invocation of init method failed; nested exception is org.hibernate.AnnotationException: Use of the same entity name twice: MyTablenNme1
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1337)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:473)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory$1.run(AbstractAutowireCapableBeanFactory.java:409)
at java.security.AccessController.doPrivileged(Native Method)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:380)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:264)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:221)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:261)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:185)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:164)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:423)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:729)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:381)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:93)
at com.nuval.infrastructure.test.BaseTest.init(BaseTest.java:44)
at com.nuval.infrastructure.test.BaseTest.setUp(BaseTest.java:62)
at com.nuval.test.CloneTest.setUp(CloneTest.java:104)
at junit.framework.TestCase.runBare(TestCase.java:125)
at junit.framework.TestResult$1.protect(TestResult.java:106)
at junit.framework.TestResult.runProtected(TestResult.java:124)
at junit.framework.TestResult.run(TestResult.java:109)
at junit.framework.TestCase.run(TestCase.java:118)
at junit.framework.TestSuite.runTest(TestSuite.java:208)
at junit.framework.TestSuite.run(TestSuite.java:203)
at org.eclipse.jdt.internal.junit.runner.junit3.JUnit3TestReference.run(JUnit3TestReference.java:130)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Caused by: org.hibernate.AnnotationException: Use of the same entity name twice: MyTableName1
at org.hibernate.cfg.annotations.EntityBinder.bindEntity(EntityBinder.java:347)
at org.hibernate.cfg.AnnotationBinder.bindClass(AnnotationBinder.java:613)
at org.hibernate.cfg.AnnotationConfiguration.processArtifactsOfType(AnnotationConfiguration.java:636)
at org.hibernate.cfg.AnnotationConfiguration.secondPassCompile(AnnotationConfiguration.java:359)
at org.hibernate.cfg.Configuration.buildMappings(Configuration.java:1206)
at org.springframework.orm.hibernate3.LocalSessionFactoryBean.buildSessionFactory(LocalSessionFactoryBean.java:673)
at org.springframework.orm.hibernate3.AbstractSessionFactoryBean.afterPropertiesSet(AbstractSessionFactoryBean.java:211)
at com.zeer.onqi.spring.ExtendedAnnotationSessionFactoryBean.afterPropertiesSet(ExtendedAnnotationSessionFactoryBean.java:36)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1368)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1334)
... 30 more
Caused by: org.hibernate.DuplicateMappingException: duplicate import: MyTableName1 refers to both com.mycompany.entities1_1.MyTableName1 and com.mycompany.entities.MyTableName1 (try using auto-import="false")
at org.hibernate.cfg.Configuration$MappingsImpl.addImport(Configuration.java:2418)
at org.hibernate.cfg.annotations.EntityBinder.bindEntity(EntityBinder.java:340)
... 39 more
Your problem is not related to your bean and is caused by the fact that you have two entities with the same logical name in your
SessionFactory. It means that Hibernate won’t be able to understand which entity should it use in query such asfrom MyTableName1.If you really need to have these entities in the same
SessionFactorysimultaneously, you should specify different logical names for them, as follows:and use these names in HQL queries.
If you don’t need them simultaneously, perhaps you can put them into different
SessionFactoriesfor different schemas.Also note that, as far as I understand, you don’t need to create your own subclass of
AnnotationSessionFactoryBean, because the default one supports the same functionality as you try to achieve, seepackagesToScanproperty.