使用Ant构建Jar查询Oracle DB时出现ExceptionInInitializerError,但IDE运行正常
问题:Jar包运行Oracle查询抛出ExceptionInInitializerError,IDE运行正常
我的Java代码在JDeveloper 12.1.3.0.0中能正常查询Oracle 19.13.0.0.0数据库,但通过Apache Ant构建Jar包后,命令行运行时执行查询的代码抛出java.lang.ExceptionInInitializerError。
简化代码
package com.company.TestApp.TestProj; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.Statement; public class Main { public Main() { super(); } public static void main(String[] args) { Main main = new Main(); main.run(); } public void run() { System.out.println("Starting"); try { Class.forName("oracle.jdbc.OracleDriver"); Connection db = DriverManager.getConnection(connectionString, schema, password); if (db.isValid(10)) { System.out.println("Connected"); } else { System.out.println("Not connected"); throw new Exception("Not connected"); } String sql = "SELECT * FROM dual"; Statement statement = db.createStatement(); ResultSet rs = statement.executeQuery(sql); while (rs.next()) { System.out.println("Record"); } rs.close(); statement.close(); db.close(); } catch (Exception e) { e.printStackTrace(); } } }
Ant构建脚本
<project name="test" basedir="." default="main"> <property name="src.dir" value="src"/> <property name="build.dir" value="build"/> <property name="classes.dir" value="${build.dir}/classes"/> <property name="jar.dir" value="${build.dir}/jar"/> <property name="main-class" value="com.company.TestApp.TestProj.Main"/> <property name="lib.dir" value="../lib"/> <path id="classpath"> <fileset dir="${lib.dir}" includes="**/*.jar"/> </path> <target name="clean"> <delete dir="${build.dir}"/> </target> <target name="compile"> <mkdir dir="${classes.dir}"/> <javac srcdir="${src.dir}" destdir="${classes.dir}" classpathref="classpath"/> </target> <target name="jar" depends="compile"> <mkdir dir="${jar.dir}"/> <jar destfile="${jar.dir}/${ant.project.name}.jar" basedir="${classes.dir}"> <fileset dir="${jar.dir}"> <include name="**/*.class"/> </fileset> <zipfileset src="${lib.dir}/ojdbc7.jar"> <include name="**/*.class"/> </zipfileset> <manifest> <attribute name="Main-Class" value="${main-class}"/> </manifest> </jar> </target> <target name="run" depends="jar"> <java fork="true" classname="${main-class}"> <classpath> <path refid="classpath"/> <path location="${jar.dir}/${ant.project.name}.jar"/> </classpath> </java> </target> <target name="clean-build" depends="clean,jar"/> <target name="main" depends="clean,run"/> </project>
环境信息
- JDK版本:1.8.0_291(JAVA_HOME及PATH已配置)
- Oracle驱动:ojdbc7.jar(来自JDeveloper)
IDE运行结果
Starting Connected Record
Jar运行报错信息
Starting Connected Exception in thread "main" java.lang.ExceptionInInitializerError at oracle.jdbc.driver.OracleStatement.configureRowData(OracleStatement.java:760) at oracle.jdbc.driver.OracleStatement.<init>(OracleStatement.java:696) at oracle.jdbc.driver.T4CStatement.<init>(T4CStatement.java:1152) at oracle.jdbc.driver.T4CDriverExtension.allocateStatement(T4CDriverExtension.java:46) at oracle.jdbc.driver.PhysicalConnection.createStatement(PhysicalConnection.java:3914) at oracle.jdbc.driver.PhysicalConnection.createStatement(PhysicalConnection.java:3874) at com.company.TestApp.TestProj.Main.run(Main.java:34) at com.company.TestApp.TestProj.Main.main(Main.java:15) Caused by: java.lang.NullPointerException at oracle.jdbc.driver.DynamicByteArray$1.run(DynamicByteArray.java:540) at java.security.AccessController.doPrivileged(Native Method) at oracle.jdbc.driver.DynamicByteArray.<clinit>(DynamicByteArray.java:535) ... 8 more
解决方案
问题出在Ant构建脚本的Jar打包步骤:你仅将ojdbc7.jar的class文件打包进了自己的Jar,但Oracle驱动Jar里除了class文件,还有必要的配置文件和资源文件(比如oracle/jdbc/driver/OracleDriver.properties、本地化资源等),这些文件缺失导致初始化失败。
修复步骤
修改Ant的Jar打包目标,两种可选方案:
- 方案一:分离依赖,通过Manifest声明类路径
调整后的jar目标:<target name="jar" depends="compile"> <mkdir dir="${jar.dir}"/> <jar destfile="${jar.dir}/${ant.project.name}.jar" basedir="${classes.dir}"> <manifest> <attribute name="Main-Class" value="${main-class}"/> <!-- 声明依赖的ojdbc7.jar路径,需与运行时实际位置匹配 --> <attribute name="Class-Path" value="../lib/ojdbc7.jar"/> </manifest> </jar> </target> - 方案二:构建包含所有依赖的可执行Jar
打包ojdbc7.jar的所有内容(包括资源文件),而不是仅class:<target name="jar" depends="compile"> <mkdir dir="${jar.dir}"/> <jar destfile="${jar.dir}/${ant.project.name}.jar" basedir="${classes.dir}"> <!-- 打包ojdbc7.jar的全部内容 --> <zipfileset src="${lib.dir}/ojdbc7.jar"/> <manifest> <attribute name="Main-Class" value="${main-class}"/> </manifest> </jar> </target>
- 方案一:分离依赖,通过Manifest声明类路径
运行时确保依赖可用
- 若用分离依赖方案,运行时需保证ojdbc7.jar在Manifest声明的路径下,或通过命令指定完整类路径:
java -cp your.jar:../lib/ojdbc7.jar com.company.TestApp.TestProj.Main - Ant的
run目标无需修改,它已引用完整classpath,包含lib目录下的Jar。
- 若用分离依赖方案,运行时需保证ojdbc7.jar在Manifest声明的路径下,或通过命令指定完整类路径:
内容的提问来源于stack exchange,提问作者TooManyCooks
相关产品推荐
相关产品推荐

