从使用Ant构建的jar中查询Oracle DB时出现“ExceptionInInitializerError”,但在IDE中运行正常

abithluo  于 2023-04-29  发布在  Oracle
关注(0)|答案(2)|浏览(147)

当我在IDE中运行Java代码时,它成功运行。当我构建一个jar文件并从命令行运行它时,我收到一个“java。lang.ExceptionInInitializerError”。我怀疑我的ApacheAnt构建脚本有问题,但我不确定。
下面是我的极度简化的代码(是的,我知道我没有在失败时完全关闭DB连接,但这是我创建的一些小东西,只是为了获得最简单的代码版本,我仍然可以展示错误):

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();
        }
    }
}

我的非常简化的Apache 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>

我的IDE是JDeveloper 12。1.3.0.0.我的JAVA_HOME和路径设置为JDK 1。8.0_291.我的Oracle DB是19。13.0.0.0
当我从IDE运行程序时,我得到了预期的结果:

Starting
Connected
Record

当我用“java -jar测试”从命令行运行jar时。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

Java JDK18.0_291,但我在其他不同版本的Java机器上尝试过,收到同样的错误。我用的是OJDBC 7。JDeveloper附带的jar。

cidc1ykv

cidc1ykv1#

要让fat JAR使用java -jar test.jar运行,需要对Ant脚本做一个小的修改。
更改此:

<zipfileset src="${lib.dir}/ojdbc8-19.3.0.0.jar">
    <include name="**/*.class"/>
</zipfileset>

对此:

<zipfileset src="${lib.dir}/ojdbc8-19.3.0.0.jar">
    <include name="**/*.*"/>
</zipfileset>

原因是:在OracleJDBCJAR中不仅仅有.class文件。
还有(例如)属性文件,如

defaultConnectionProperties.properties

和其他文件。
我不知道哪个 * 特定 * 丢失的文件是你的异常的根本原因。我只是执行了一个包含所有内容的构建。

题外话:

您可能已经知道以下内容-但对于未来的访问者这个问题。..
还值得注意的是,JDBC文件包含一个名为java.sql.Driver的文件(在META-INF/services中),该文件包含Oracle驱动程序类的名称:

oracle.jdbc.OracleDriver

通常,这用于自动加载Oracle JDBC驱动程序-所以不需要下面的代码行:

Class.forName("oracle.jdbc.OracleDriver");

然而,这是通过扫描库JAR文件来实现的--因为您的应用程序“胖”jar中不再有Oracle JAR文件,所以您仍然需要上面的代码行。
这是目前仍然需要这行代码以避免No suitable driver found异常的相对罕见的情况之一。

m2xkgtsf

m2xkgtsf2#

一个同事可以通过手动指定classpath来让它工作:

java -cp ..\..\..\lib\ojdbc7.jar;test.jar com.company.TestApp.TestProj.Main

我不明白为什么需要这样做,但我怀疑我没有正确地在ant脚本中包含ojdbc jar文件。如果有人能向我解释解决这个问题的方法,将不胜感激!

相关问题