need "j2ee.jar" added to classpath when hibernate

Today,I am trying Hibernate and use Hibernatesynch for eclipse2.1 plugin got some classes.

When I run this program on Tomcat5.0,the page always reports:

HTTP Status 500 -

--------------------------------------------------------------------------------

type Exception report

message

description The server encountered an internal error () that prevented it from fulfilling this request.

exception

javax.servlet.ServletException: Servlet execution threw an exception

root cause

java.lang.NoClassDefFoundError: javax/transaction/Synchronization

net.sf.hibernate.impl.SessionFactoryImpl.openSession(SessionFactoryImpl.java:314)

net.sf.hibernate.impl.SessionFactoryImpl.openSession(SessionFactoryImpl.java:327)

net.sf.hibernate.impl.SessionFactoryImpl.openSession(SessionFactoryImpl.java:335)

com.asprise.business._BaseRootDAO.createSession(_BaseRootDAO.java:116)

com.asprise.business._BaseRootDAO.createSession(_BaseRootDAO.java:107)

com.asprise.business._BaseRootDAO.getSession(_BaseRootDAO.java:99)

com.asprise.business._BaseRootDAO.find(_BaseRootDAO.java:162)

com.asprise.business.UserBean.findUsers(UserBean.java:23)

com.asprise.struts.action.OwnerAction.performViewUsers(OwnerAction.java:61)

com.asprise.struts.action.OwnerAction.execute(OwnerAction.java:51)

org.apache.struts.action.RequestProcessor.processActionPerform(RequestProcessor.java:448)

org.apache.struts.action.RequestProcessor.process(RequestProcessor.java:263)

org.apache.struts.action.ActionServlet.process(ActionServlet.java:1176)

org.apache.struts.action.ActionServlet.doGet(ActionServlet.java:454)

javax.servlet.http.HttpServlet.service(HttpServlet.java:697)

javax.servlet.http.HttpServlet.service(HttpServlet.java:810)

note The full stack trace of the root cause is available in the Apache Tomcat/5.0.25 logs.

--------------------------------------------------------------------------------

Apache Tomcat/5.0.25

I found there are two ways to resolve this problem:

1.add j2ee.jar to program's "/web-inf/lib" folder or javax.transaction.Synchronization.class to it's "/web-inf/classes" folder;

2.add the file to tomcat's "/common/lib" or "/common/classes" as above.

I don't know why this happened,I have configed the classpath environment "d:\j2ee1.3\lib\j2ee.jar",and configed the "J2EE_HOME" is "d:\j2ee1.3".

Is there anyone can answer me this question,by any chance please?

6 thoughts on “need "j2ee.jar" added to classpath when hibernate”

  1. 可以仔细查看%CATALINA_HOME%\bin\startup.bat,其中调用setclasspath.bat来设定tomcat使用的classpath。这么做的用意是每个版本的tomcat可能需要不同版本的j2ee,于是在%CATALINA_HOME%\common\lib\下自带了部分j2ee的包。所以即使不下j2ee sdk包,tomcat或者其他服务器也是可以运行的,但是java_home还是需要的。

    另外,在Hibernate的lib里有jta.jar,此文件需要拷到服务器的lib路径下,还有log4j、dom4j、common-collections等等,Hibernate的lib目录下也有一些并不需要的,也可以不拷,像ant,tomcat里就已经带了。

  2. I know why the error happened.I haven't copy "jta.jar" to "WEB-INF/lib".The class "javax.transaction.Synchronization" is included in this package.

    But,why I can't see this step in document of Hibernate2(D:\hibernate-2.1.8\hibernate-2.1\doc\reference\en\html\quickstart.html)?It introduces all the other jar file except this.So,that's not my error:)

  3. first, in <<quickstart.html>>

    Table 1.1.  Hibernate 3rd party libraries

    Required or not? 

    Have a look at the file lib/README.txt in the Hibernate distribution. This is an up-to-date list of 3rd party libraries distributed with Hibernate. You will find all required and optional libraries listed there. 

    so in <<lib/README.txt>>

    ……

    jta.jar

    - Standard JTA API

    - runtime, required for standalone operation (outside application server)

    ……

    and i think that tomcat is a web container but not app-server, so jta.jar need be added.

    查了一下我用的JBoss,它的JbossTA就是JTA的另一个实现,因为事务处理是app-server的一个基本功能,而tomcat的文档中,如数据库操作是必然用到事务的,jakarta上的在线文档中,提到数据源的建立时,如果需要系统提供事务处理,也是要把jta.jar拷到common/lib下的,否则只能编程实现事务了。

  4. I don't think "服务器的classpath是与系统的classpath无关的".

    I have read some *.bat file in tomcat's bin directory.

    The set classpath process is so:

    start.bat->catalina.bat->setclasspath.bat->

    this is a snippet in catalina.bat:

    ...

    :okSetclasspath

    set BASEDIR=%CATALINA_HOME%

    call "%CATALINA_HOME%\bin\setclasspath.bat"

    rem Add on extra jar files to CLASSPATH

    if "%JSSE_HOME%" == "" goto noJsse

    set CLASSPATH=%CLASSPATH%;%JSSE_HOME%\lib\jcert.jar;%JSSE_HOME%\lib\jnet.jar;%JSSE_HOME%\lib\jsse.jar

    :noJsse

    set CLASSPATH=%CLASSPATH%;%CATALINA_HOME%\bin\bootstrap.jar

    ...

    "set CLASSPATH=%CLASSPATH%;",isn't it calling the classpath environment variable?

    If it does call the environment variable,why the program can't find the class "javax.transaction.Synchronization" which's jar file "j2ee.jar" had been seted into classpath environment variables yet?

  5. “第一代 Java 只有一个由类路径命令行参数或者 CLASSPATH环境变量定义的类加载器。出于安全和其他方面的原因,在 Java 虚拟机(Java Virtual Machine,JVM)中用一个类加载器来加载所有的类肯定是不合适的,因此 Java 2 改进了类装载机制,将其从平面结构更改为类加载器层次。该层次包含 3 个专门的类加载器,也就是引导类加载器(bootstrap ClassLoader)、扩展类加载器(extensions ClassLoader)和应用程序类加载器(application ClassLoader);每种加载器在 JVM 中都有不同的作用。这虽然改进了类装载,但同时也显著地增加了类加载器的复杂性。随着 J2EE 应用程序服务器的出现,类加载器的复杂性进一步增加了,因为 JVM 中的每个应用程序都可能有自己的类加载器层次,这将导致一个单独的 JVM 可能包含许多的类加载器。”

    使用层次结构的ClassLoader的作用是显而易见的,譬如应用A和应用B都要使用同一个包,但是调用的版本却不一样,那么应用A和应用B就必须有各自不同的ClassPath才行,而且应用A如果崩溃或者关闭都不会影响应用B的运行。各个版本的Tomcat app的类载入策略都有所不同,5.0版的类载入时查询的顺序是:

    1 Bootstrap classes of your JVM

    2 System class loader classses (described above)

    3 /WEB-INF/classes of your web application

    4 /WEB-INF/lib/*.jar of your web application

    5 $CATALINA_HOME/common/classes

    6 $CATALINA_HOME/common/endorsed/*.jar

    7 $CATALINA_HOME/common/lib/*.jar

    8 $CATALINA_BASE/shared/classes

    9 $CATALINA_BASE/shared/lib/*.jar

    如果在前面的路径下找到了,就会中止查询过程,即越前面的优先级越高

    而对于第二项System class loader classses,文档里特别提到

    System - This class loader is normally initialized from the contents of the CLASSPATH environment variable. All such classes are visible to both Tomcat internal classes, and to web applications. However, the standard Tomcat 5 startup scripts ($CATALINA_HOME/bin/catalina.sh or %CATALINA_HOME%\bin\catalina.bat) totally ignore the contents of the CLASSPATH environment variable itself, and instead build the System class loader from the following repositories:

    $CATALINA_HOME/bin/bootstrap.jar - Contains the main() method that is used to initialize the Tomcat 5 server, and the class loader implementation classes it depends on.

    $JAVA_HOME/lib/tools.jar - Contains the "javac" compiler used to convert JSP pages into servlet classes.

    $CATALINA_HOME/bin/commons-logging-api.jar - Jakarta commons logging API.

    $CATALINA_HOME/bin/commons-daemon.jar - Jakarta commons daemon API.

    jmx.jar - The JMX 1.2 implementation.

    也就是说除了上面提单的5个jar,其他是不考虑的。

    对于你在catalina.bat里找到的那行

    set CLASSPATH=%CLASSPATH%;%JSSE_HOME%\lib\jcert.jar;%JSSE_HOME%\lib\jnet.jar;%JSSE_HOME%\lib\jsse.jar

    如果你仔细看前面的调用过程,会发现在前面已经call了setclasspath.bat,而在setclasspath.bat里42行:

    set CLASSPATH=%JAVA_HOME%\lib\tools.jar

    这是CLASSPATH的初始设置,已经把系统的classpath里的内容都去掉了,此后在陆续添加了bootstrap.jar等等。

    java的类载入路径是很混乱的,在WebSphere这样的应用服务器中会有专门的工具来查看每个类的载入路径,但我不知道tomcat有没有类似的工具。最安全的方式还是将所有用到的包都放到/WEB-INF/lib/下吧。

Comments are closed.