【问题标题】:Program runs fine when I run in VSCode, but the package the maven extension builds doesn't run当我在 VSCode 中运行时程序运行良好,但是 maven 扩展构建的包没有运行
【发布时间】:2020-06-25 20:49:31
【问题描述】:

背景:我正在使用 VS Code 和 VS Code Java 扩展包(其中包括一个 maven 扩展)来编写一个使用 htmlunit 的项目。目前,我只是在使用别人的代码来看看我是否能让我的环境正常工作。我是 maven 和 VS Code 的菜鸟,Java 的半菜鸟。

当我使用 VS Code 运行选项卡运行程序时,它按预期运行*。当我使用 maven package 命令构建可执行 jar 时,jar 构建良好,但是当我使用 java -jar ___.jar 运行它时,出现错误:

Exception in thread "main" java.lang.NoClassDefFoundError: com/gargoylesoftware/htmlunit/FailingHttpStatusCodeException
        at reliant.Main.main(Main.java:44)
Caused by: java.lang.ClassNotFoundException: com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException
        at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:581)
        at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
        at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522)
        ... 1 more 

这里是使用 htmlunit 的代码:

package reliant; //I know now this is not how package naming conventions work, but I don't think it causes a problem
import java.io.IOException;

import com.gargoylesoftware.htmlunit.BrowserVersion;
import com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException; //the import that seems to be buggy
import com.gargoylesoftware.htmlunit.WebClient;
import com.gargoylesoftware.htmlunit.html.HtmlForm;
import com.gargoylesoftware.htmlunit.html.HtmlPage;

public class RedditClient {
    
    private final WebClient CLIENT = new WebClient(BrowserVersion.CHROME);
    private final String username;
    private char[] password;

    public RedditClient(String username, char[] password) {
        this.username = username;
        this.password = password;
     
        CLIENT.getCookieManager().setCookiesEnabled(true);
    }

    public void checkLogin() {
        System.out.println(username + ", " + new String(password));
    }

    public void login() {
        String loginURL = "https://www.reddit.com/login";

        try {
            HtmlPage loginPage = CLIENT.getPage(loginURL);

            HtmlForm loginForm = loginPage.getFirstByXPath("//form[@id='login-form']");
            //System.out.println(loginPage.getWebResponse().getContentAsString());
            loginForm.getInputByName("user").setValueAttribute(username);
            loginForm.getInputByName("passwd").setValueAttribute(new String(password));

            loginForm.getElementsByTagName("button").get(0).click();

        } catch (FailingHttpStatusCodeException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } 
    }

    public String getHTML(String url) {
        try {
            return CLIENT.getPage(url).getWebResponse().getContentAsString();
        } catch (FailingHttpStatusCodeException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return null;
    }

    public void close() {
        CLIENT.close();
    }
}

这里是 Main.java 的第 44 行:

RedditClient c = new RedditClient(username, password);

这对我来说似乎是正确的,我将 htmlunit 添加到我的 maven 依赖项中。如果您愿意,我可以向您展示 maven 依赖项的屏幕截图,但我暂时省略了它,因为它有点长/难以阅读。

这是 pom 文件:

<?xml version="1.0" encoding="UTF-8"?>

<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>reliant</groupId>
  <artifactId>redditlogin</artifactId>
  <version>2.0</version>

  <name>redditlogin</name>
  <!-- FIXME change it to the project's website -->
  <url>http://www.example.com</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>11</maven.compiler.source>
    <maven.compiler.target>11</maven.compiler.target>
  </properties>

  <dependencies>

    <dependency>
      <groupId>htmlunit</groupId>
      <artifactId>htmlunit</artifactId>
      <version>1.14</version>
    </dependency>


   <dependency>
     <groupId>org.jsoup</groupId>
     <artifactId>jsoup</artifactId>
     <version>1.13.1</version>
   </dependency>


    <dependency>
      <groupId>net.sourceforge.htmlunit</groupId>
      <artifactId>htmlunit</artifactId>
      <version>2.41.0</version>
    </dependency>

    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
  </dependencies>

  <build>
    <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
      <plugins>
        <!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
        <plugin>
          <artifactId>maven-clean-plugin</artifactId>
          <version>3.1.0</version>
        </plugin>
        <!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
        <plugin>
          <artifactId>maven-resources-plugin</artifactId>
          <version>3.0.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-compiler-plugin</artifactId>
          <version>3.8.0</version>
        </plugin>
        <plugin>
          <artifactId>maven-surefire-plugin</artifactId>
          <version>2.22.1</version>
        </plugin>
        <plugin>
          <artifactId>maven-jar-plugin</artifactId>
          <version>3.0.2</version>
          <configuration>
            <archive>
              <manifest>
                <addClasspath>true</addClasspath>
                  <mainClass>reliant.Main</mainClass>
              </manifest>
            </archive>
          </configuration>
        </plugin>
        <plugin>
          <artifactId>maven-install-plugin</artifactId>
          <version>2.5.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-deploy-plugin</artifactId>
          <version>2.8.2</version>
        </plugin>
        <!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->
        <plugin>
          <artifactId>maven-site-plugin</artifactId>
          <version>3.7.1</version>
        </plugin>
        <plugin>
          <artifactId>maven-project-info-reports-plugin</artifactId>
          <version>3.0.0</version>
        </plugin>
      </plugins>
    </pluginManagement>
  </build>
</project>

jar 文件出错但在 VS Code 中按预期运行的事实对我来说毫无意义。

另外,在不相关的说明中,为什么“找不到类”错误是运行时错误?为什么maven能够成功构建包?

*我说“如预期”是因为我正在使用的代码中有一个错误,但这是一个非常具体的运行时错误。基本上,我使用的代码旨在在 reddit 获得 OAuth 之前登录到 reddit,所以现在尝试获取登录表单的行返回 null 并且破坏了其余部分。关键是,我看不出为什么在 VS Code 中运行与在 jar 中运行应该有任何不同的结果。我什至不知道从哪里开始这样的事情。

感谢您的帮助,如果我可以添加任何内容以使这个问题更容易回答,请告诉我。

【问题讨论】:

  • 我相信这个问题可能与我没有生成一个胖罐有关。有谁知道如何在 vscode 中做到这一点?

标签: java maven visual-studio-code executable-jar htmlunit


【解决方案1】:

好吧,事实证明这很愚蠢。基本上,类路径列出了我的依赖项(因为我如何设置 pom),但这并不意味着它指定了这些依赖项的路径。事实上,它根本没有指定路径,所以每当 java 试图运行 jar 时,它都会在当前目录中查找依赖项。我知道这是因为当我将依赖项与 jar 放在同一目录中时,它起作用了。这里更好的解决方案是修改 pom 以向类路径添加前缀,以便 java 知道在哪里可以找到依赖项。不幸的是,我的依赖项在不同的地方,所以这对我来说不是一个真正的选择;相反,我将尝试找出如何制作一个胖/超级罐子。

【讨论】:

  • 这不是一个更好的解决方案,因为完整路径是特定于您的计算机的,而 Java 程序是可移植的。你的胖罐解决方案要好得多。
  • 我明白了。只是出于好奇,您可以不指定相对路径吗?我见过的一些示例(onetwo)似乎使用了相对路径前缀,例如“dependency-jars/”或“lib/”。
  • 是的,但是该路径是相对于主 jar 的(即您正在执行的),如果您的最终结果是一个程序集,则应该使用它 - 一个包含您的 jar 的存档以及所有依赖项。您可以指示 maven 为您创建一个,并指定必须将这些依赖项放置在相对于您的 jar 的某个文件夹中。更多关于使用 Maven 创建程序集的信息在这里:maven.apache.org/guides/mini/guide-assemblies.html
猜你喜欢
  • 2016-05-26
  • 2013-07-27
  • 2016-06-03
  • 2020-03-05
  • 1970-01-01
  • 1970-01-01
  • 2017-11-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多