I try to be quick.
In fact, one of my jUnit test is failing when running the Maven command of my project (mvn install, so with the Surefire plugin) while it's successful when I run it in Eclipse.
I tried many things and the only difference I managed to see is that : - With Maven/Surefire in debug-mode, in the Hibernate-SessionFactory I have only 3 EntityPersister instances - With Eclipse in debug perspective, I could see 6 EntityPersister instances (in fact the number of annotatedClasses I have in my project)
Here is my Spring configuration file ("dataSource" is defined in another project, I don't put the DAO classes) :
<beans ...>
<!-- le gestionnaire de BLOB / CLOB de chez Spring -->
<bean id="lobHandler" class="org.springframework.jdbc.support.lob.DefaultLobHandler" />
<!-- Hibernate SessionFactory Definition -->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">create</prop>
</props>
</property>
<property name="dataSource">
<ref bean="datasource" />
</property>
<property name="packagesToScan">
<list>
<value>com.wft.model</value>
<value>com.wft.model.user</value>
</list>
</property>
<!--
<property name="annotatedClasses">
<list>
<value>com.wft.model.Project</value>
<value>com.wft.model.Authors</value&g开发者_JS百科t;
<value>com.wft.model.user.User</value>
<value>com.wft.model.user.Administrator</value>
<value>com.wft.model.user.Gamer</value>
<value>com.wft.model.user.Organizer</value>
</list>
</property>
-->
</bean>
<!-- Hibernate Transaction Manager Definition -->
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<!-- TODO: Switch to annotations for transactions
<tx:annotation-driven/>
-->
<bean id="transactionInterceptor"
class="org.springframework.transaction.interceptor.TransactionInterceptor">
<property name="transactionManager" ref="transactionManager" />
<property name="transactionAttributes">
<props>
<prop key="*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
<!-- -->
<bean id="autoProxyCreator"
class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="interceptorNames">
<list>
<idref local="transactionInterceptor" />
</list>
</property>
<property name="beanNames">
<list>
<value>*DAO</value>
</list>
</property>
</bean>
<bean id="projectDAO" class="com.wft.service.dao.impl.ProjectDAO">
<constructor-arg>
<value>com.wft.model.Project</value>
</constructor-arg>
<property name="sessionFactory">
<ref bean="sessionFactory" />
</property>
</bean>
<bean id="userDAO" class="com.wft.service.dao.impl.UserDAO">
<constructor-arg>
<value>com.wft.model.user.User</value>
</constructor-arg>
<property name="sessionFactory">
<ref bean="sessionFactory" />
</property>
</bean>
</beans>
And the test class :
public class TestDAO extends
AbstractTransactionalDataSourceSpringContextTests {
private IUserDAO userDAO;
private IProjectDAO projectDAO;
private SessionFactory sessionFactory;
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
protected String[] getConfigLocations() {
return new String[] { "classpath*:myapp-persistence-tech.xml",
"classpath*:datasource_mysql.xml" };
}
@Override
protected boolean isDefaultRollback() {
return false;
}
@Override
protected boolean isRollback() {
return false;
}
/**
* Spring will automatically inject userDAO object on startup
*
* @param userDAO
*/
public void setUserDAO(IUserDAO userDAO) {
this.userDAO = userDAO;
}
/**
* Spring will automatically inject projectDAO object on startup
*
* @param projectDAO
*/
public void setProjectDAO(IProjectDAO projectDAO) {
this.projectDAO = projectDAO;
}
public void test1() {
System.out.println("Session Factory : "+sessionFactory);
@SuppressWarnings("unused")
SessionFactoryImpl sfImpl = (SessionFactoryImpl)sessionFactory;
Administrator admin = new Administrator("admin", "admin");
User user1 = new User("user1", "user1");
User user2 = new User("user2", "user2");
for (User user : userDAO.findAll()) {
if (user instanceof Administrator) {
System.out.println("Deleting administrator");
} else {
System.out.println("Deleting user");
}
userDAO.delete(user);
}
userDAO.add(user1);
userDAO.add(admin);
// dao.add(user2);
System.out.println();
assertTrue(true);
}
}
When I debug the jUnit in Eclipse, I can see all the EntityPersisters :
entityPersisters HashMap<K,V> (id=75)
entrySet HashMap$EntrySet (id=87)
keySet null
loadFactor 0.75
modCount 6
size 6
table HashMap$Entry<K,V>[16] (id=95)
threshold 12
values HashMap$Values (id=136)
but when remote-debugging Surefire on the port 5005, I only got 3 …
and it ends with :
test1(com.wft.service.services.TestDAO) Time elapsed: 2.139 sec <<< ERROR!
org.hibernate.MappingException: Unknown entity: com.wft.model.user.Administrator
at org.hibernate.impl.SessionFactoryImpl.getEntityPersister(SessionFactoryImpl.java:580)
One important thing maybe (is that Administrator is a subclass of User) :
@Entity
@Table(name = "USER")
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name="DTYPE", discriminatorType=DiscriminatorType.STRING, columnDefinition="VARCHAR(32) DEFAULT \"ROLE_USER\"", length=32)
@DiscriminatorValue(value="ROLE_USER")
@ForceDiscriminator
public class User extends LightEntity implements Serializable {}
@Entity
@DiscriminatorValue(value="ROLE_ADMINISTRATOR")
@ForceDiscriminator
public class Administrator extends User {}
but the inheritance does not seem to be the root cause.
Is someone aware of such a discrepancy between the 2 environments (Maven+Surefire vs Eclipse+jUnit launcher) ? Does it look like a bug in surefire (or somewhere else) or a wrong usage of one of the frameworks involved ?
I believe the tools you use are OK. You probably get your error because there is different classpaths involved when you run it from command line and when you run it from Eclipse. Check your file structure at first place. Based on what you have described you have your entities spread in different projects - try to run mvn test -X
to see what exact classpaths maven uses
I already read somewhere that most of the time a discrepancy between command-line and Eclipse is due to classpath. In fact, I did not take time to check the classpath values but it can't be the reason since the Spring config file is well loaded in both cases and, since User is well loaded, Administrator (same package) should be as well.
I'm stuck with this problem since several days and by chance, I fix it just few hours after posting here ... ! I can't believe it.
This problem was due to the fact that Administrator had not public constructor. I know that having it is one of the Hibernate/JPA best-practices but usually an explicit error is raised ("no public ctor" or something like that) and my remaining question will be :
Why the behavior is different with mvn command and within Eclipse ?
Not sure if this is relevant here, but something to be aware of when you see a difference between your IDE and Maven is that Maven will, by default, reference dependencies that are in your local repository (M2_REPO) whereas your IDE might be looking in the /target of other modules. This is particularly true if you have a multi module maven project.
Again, -X will help you identify the classpath that Maven is using. Compare the contents of the classpath and the ordering of the classpath with what your IDE is launching with.
精彩评论