jar 中的 class 可以在不同的 jar 中使用 class

can a class in a jar use a class in a different jar

我是 java 的新手,所以不确定我是否完全理解 jar 文件。

我想将一些通用代码放在一个库 jar 中,然后我从不同 jar 中的应用程序中使用它们。我已经对此进行了搜索,但只是想出人们说是,然后在 class 文件中显示 classes 的示例调用 jars 中的 classes,这与 classes 在一个 jar 中调用 classes 在另一个 jar 中。

我曾尝试这样做并认为我可以正常工作,直到我尝试在命令行上 运行 应用程序,此时我收到 class 未找到错误。然而代码在 eclipse 中工作,从我所看到的情况来看,这似乎是一个常见问题,其中代码 运行s 在 ide 正在开发中,但是当有人试图 运行 他们的代码时ide 日食失败。

那么作为 jar 构建的应用程序是否有可能 call/use classes 在不同的 jar 文件中,如果是的话如何?

这是我尝试测试的问题

FoobarInterface.java

package org.myorg.mylibrary;

public interface FoobarInterface
{
    String echo(final String val);
}

Foobar.java

package org.myorg.mylibrary;

public class Foobar implements FoobarInterface
{

    public String echo(final String val)
    {
        StringBuilder sb = new StringBuilder("echoed: ");
        sb.append(val);
        return(sb.toString());
    }

}

pom.xml 库 jar

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>org.myorg</groupId>
  <artifactId>mylibrary</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <name>mylibraryname</name>

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-jar-plugin</artifactId>
        <configuration>
          <archive>
            <index>true</index>
            <manifest>
            </manifest>
          </archive>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

产生 mylibrary-0.0.1-SNAPSHOT.jar

客户端代码为

Main.java

package org.myorg.myapp;

import org.myorg.mylibrary.Foobar;

public class Main
{

    public Main(String[] args)
    {
        Foobar foobar = new Foobar();
        StringBuilder sb = new StringBuilder("RESULT: ");
        sb.append(foobar.echo(args[0]));
        System.out.println(sb.toString());
    }

    public static void main(String[] args)
    {
        Main foo = new Main(args);
    }

}

pom.xml 用于应用程序 jar

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
      <modelVersion>4.0.0</modelVersion>
      <groupId>org.myorg</groupId>
      <artifactId>myapp</artifactId>
      <version>0.0.1-SNAPSHOT</version>
      <name>myappname</name>
      <dependencies>
        <dependency>
            <groupId>org.myorg</groupId>
            <artifactId>mylibrary</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>
      </dependencies>

      <build>
        <plugins>
          <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <configuration>
              <archive>
                <index>true</index>
                <manifest>
                  <mainClass>org.myorg.myapp.Main</mainClass>
                </manifest>
                <manifestEntries>
                 <Class-Path>.</Class-Path>
                </manifestEntries>
              </archive>
            </configuration>
          </plugin>
        </plugins>
      </build>
    </project>

我还尝试了 Class-Path 元素的所有这些设置

. ./mylibrary-0.0.1-SNAPSHOT.jar mylibrary-0.0.1-SNAPSHOT.jar

所以理论上,我可以 运行 使用此命令的应用程序

java -jar myapp-0.0.1-SNAPSHOT.jar

但我总是遇到这个错误

Exception in thread "main" java.lang.NoClassDefFoundError: org/myorg/mylibrary/Foobar

无论我如何在应用程序中指定 Class-Path 元素 pom.xml,无论我是否将 classpath 添加到命令行,例如

java -classpath mylibrary-0.0.1-SNAPSHOT.jar -jar myapp-0.0.1-SNAPSHOT.jar

是的,两个 jar 都在同一个目录中,我 运行 在 linux.

上安装它

编辑:

JB Nizet 请求 运行ning 命令的结果为 java -jar 但不幸的是,自从他让我过去后,我已经删除了测试代码问题。但是,如果它有任何好处,这里是源的输出,它首先为我提出了问题并且仍然表现出相同的异常但现在也在使用他建议的第二个命令工作。

java -jar FoobarGUI-0.0.1-SNAPSHOT.jar org.myorg.foobar.gui.Main
Exception in thread "JavaFX Application Thread" java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
        at javafx.fxml.FXMLLoader$MethodHandler.invoke(FXMLLoader.java:1770)
        at javafx.fxml.FXMLLoader$ControllerMethodEventHandler.handle(FXMLLoader.java:1653)
        at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86)
        at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
        at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
        at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
        at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
        at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
        at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
        at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
        at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
        at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
        at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
        at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:49)
        at javafx.event.Event.fireEvent(Event.java:198)
        at javafx.scene.Node.fireEvent(Node.java:8390)
        at javafx.scene.control.Button.fire(Button.java:185)
        at com.sun.javafx.scene.control.behavior.ButtonBehavior.mouseReleased(ButtonBehavior.java:182)
        at com.sun.javafx.scene.control.skin.BehaviorSkinBase.handle(BehaviorSkinBase.java:96)
        at com.sun.javafx.scene.control.skin.BehaviorSkinBase.handle(BehaviorSkinBase.java:89)
        at com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(CompositeEventHandler.java:218)
        at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:80)
        at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
        at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
        at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
        at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
        at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
        at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
        at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)                                        
        at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)                                             
        at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)                                        
        at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)                                                                   
        at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54)                                                                       
        at javafx.event.Event.fireEvent(Event.java:198)                                                                                      
        at javafx.scene.Scene$MouseHandler.process(Scene.java:3758)                                                                          
        at javafx.scene.Scene$MouseHandler.access00(Scene.java:3486)                                                                      
        at javafx.scene.Scene.impl_processMouseEvent(Scene.java:1762)                                                                        
        at javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2495)                                                                  
        at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:350)                        
        at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:275)                        
        at java.security.AccessController.doPrivileged(Native Method)                                                                        
        at com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent0(GlassViewEventHandler.java:385)                       
        at com.sun.javafx.tk.quantum.GlassViewEventHandler$$Lambda1/45156577.get(Unknown Source)                                          
        at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:404)                                            
        at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:384)                                  
        at com.sun.glass.ui.View.handleMouseEvent(View.java:555)                                                                             
        at com.sun.glass.ui.View.notifyMouse(View.java:927)                                                                                  
        at com.sun.glass.ui.gtk.GtkApplication._runLoop(Native Method)                                                                       
        at com.sun.glass.ui.gtk.GtkApplication.lambda$null(GtkApplication.java:139)                                                       
        at com.sun.glass.ui.gtk.GtkApplication$$Lambda/1364335809.run(Unknown Source)
        at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.reflect.InvocationTargetException
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:497)
        at sun.reflect.misc.Trampoline.invoke(MethodUtil.java:71)
        at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:497)
        at sun.reflect.misc.MethodUtil.invoke(MethodUtil.java:275)
        at javafx.fxml.FXMLLoader$MethodHandler.invoke(FXMLLoader.java:1767)
        ... 50 more
Caused by: java.lang.NoClassDefFoundError: org/myorg/foobar/processor/ProcessorException
        at org.myorg.foobar.gui.Main.initCenterSection(Main.java:244)
        at org.myorg.foobar.gui.Main.initApplicationScene(Main.java:195)
        at org.myorg.foobar.gui.Main.actionLogin(Main.java:413)
        at org.myorg.foobar.gui.controller.ControllerLogin.actionLogin(ControllerLogin.java:97)
        ... 60 more
Caused by: java.lang.ClassNotFoundException: org.myorg.foobar.processor.ProcessorException
        at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
        at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
        ... 64 more

META-INF/MANIFEST.MF 来自展开的应用程序 jar

Manifest-Version: 1.0
Archiver-Version: Plexus Archiver
Built-By: myorg
Class-Path: FoobarProcessor-0.0.1-SNAPSHOT.jar
Created-By: Apache Maven 3.3.3
Build-Jdk: 1.8.0_45
Main-Class: org.myorg.foobar.gui.Main

这是处理器库 jar 的清单

META-INF/
META-INF/MANIFEST.MF
org/
org/myorg/
org/myorg/foobar/
org/myorg/foobar/processor/
org/myorg/foobar/processor/ProcessorException.class
org/myorg/foobar/processor/Processor.class
META-INF/maven/
META-INF/maven/org.myorg.foobar/
META-INF/maven/org.myorg.foobar/FoobarProcessor/
META-INF/maven/org.myorg.foobar/FoobarProcessor/pom.xml
META-INF/maven/org.myorg.foobar/FoobarProcessor/pom.properties
META-INF/INDEX.LIST

这是库 jar

中的 META-INF/MANIFEST.MF
Manifest-Version: 1.0
Archiver-Version: Plexus Archiver
Built-By: myorg
Created-By: Apache Maven 3.3.3
Build-Jdk: 1.8.0_45

如果应用jar文件manifest的Class-Path属性为

mylibrary-0.0.1-SNAPSHOT.jar

并且两个jar文件在同一个目录下,那么运行

java -jar myapp-0.0.1-SNAPSHOT.jar should work.

你也可以显式设置class路径,显式设置主class,这样更容易,而且不依赖清单中的相对路径。

java -cp myapp-0.0.1-SNAPSHOT.jar:mylibrary-0.0.1-SNAPSHOT.jar org.myorg.myapp.Main

您不应在同一命令中使用 -classpath 和 -jar 选项。非此即彼。

尝试在 pom.xml

中进行一些修改
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-jar-plugin</artifactId>
    <configuration>
        <archive>
            <manifest>
                <mainClass>org.myorg.myapp.Main</mainClass>
                <addClasspath>true</addClasspath>
            </manifest>
        </archive>
    </configuration>
</plugin>

在此之后,如果您仍然遇到问题,只需使用任何解压缩工具解压缩您的 myapp-0.0.1-SNAPSHOT.jar。解压缩后,检查 META-INF 文件夹中 MANIFEST 文件中 mylibrary-0.0.1-SNAPSHOT.jar 的路径。

This should be marked as a duplicate of this question I just came across

这是确切的问题和解决方案,我之前的所有搜索都找不到,直到我确切地知道我在搜索什么,即 可执行 JAR 忽略它自己的 Class-路径属性

所以根本不是 java 问题,而是一个 maven 问题,通常稀疏的 maven 文档根本没有说明这个问题。不幸的是,我复制的示例配置包含默认情况下关闭的设置。最终解决方案,不要使用 maven 插件的索引。