简体   繁体   中英

Maven AppAssembler not finding class

Attempting to modify an existing Java/Tomcat app for deployment on Heroku following their tutorial and running into some issues with AppAssembler not finding the entry class. Running target/bin/webapp (or deploying to Heroku) results in Error: Could not find or load main class org.stopbadware.dsp.Main

Executing java -cp target/classes:target/dependency/* org.stopbadware.dsp.Main runs properly however. Here's the relevant portion of pom.xml:

  <plugin>
      <groupId>org.codehaus.mojo</groupId>
      <artifactId>appassembler-maven-plugin</artifactId>
      <version>1.1.1</version>
      <configuration>
          <assembleDirectory>target</assembleDirectory>
          <programs>
              <program>
                  <mainClass>org.stopbadware.dsp.Main</mainClass>
                  <name>webapp</name>
              </program>
          </programs>
      </configuration>
      <executions>
          <execution>
              <phase>package</phase>
              <goals>
                  <goal>assemble</goal>
              </goals>
          </execution>
      </executions>
    </plugin>

My guess is mvn package is causing AppAssembler to not use the correct classpath, any suggestions?

Your artifact's packaging must be set to jar , otherwise the main class is not found.

<pom>
  ...
  <packaging>jar</packaging>
  ...
</pom>

The artifact itself is added at the end of the classpath, so nothing other than a JAR file will have any effect.

尝试:

mvn clean package jar:jar appassembler:assemble

The first thing is that you are using an old version of appassembler-maven-plugin the current version is 1.3.

What i don't understand why are you defining the

<assembleDirectory>target</assembleDirectory>

folder. There exists a good default value for that. So usually you don't need it. Apart from that you don't need to define an explicit execution which bounds to the package phase, cause the appassembler-maven-plugin is by default bound to the package phase .

Furthermore you can use the useWildcardClassPath configuration option to make your classpath shorter.

   <configuration>
     <useWildcardClassPath>true</useWildcardClassPath>
     <repositoryLayout>flat</repositoryLayout>
     ...
   </configruation>

And that the calling of the generated script shows the error is depending on the thing that the location of the repository where all the dependencies are located in the folder is different than in the generated script defined.

Was able to solve this by adding "$BASEDIR"/classes to the CLASSPATH line in the generated script. Since the script gets rewritten on each call of mvn package I wrote a short script that calls mvn package and then adds the needed classpath entry.

Obviously a bit of a hack but after a 8+ hours of attempting a more "proper" solution this will have to do for now. Will certainly entertain any more elegant ways of correcting the classpath suggested here.

You can set the CLASSPATH_PREFIX environment variable:

export CLASSPATH_PREFIX=target/classes

which will get prepended to the classpath of the generated script.

I was going through that tutorial some time ago and had very similar issue. I came with a bit different approach which works for me very nicely.

First of all, as it was mentioned before, you need to keep your POM's type as jar ( <packaging>jar</packaging> ) - thanks to that, appassembler plugin will generate a JAR file from your classes and add it to the classpath. So thanks to that your error will go away.

Please note that this tutorial Tomcat is instantiated from application source directory. In many cases that is enough, but please note that using that approach, you will not be able to utilize Servlet @WebServlet annotations as /WEB-INF/classes in sources is empty and Tomcat will not be able to scan your servlet classes. So HelloServlet servlet from that tutorial will not work, unless you add some additional Tomcat initialization (resource configuration) as described here (BTW, you will find more SO questions talking about that resource configuration).

I did a bit different approach:

I run a org.apache.maven.plugins:maven-war-plugin plugin ( exploded goal) during package and use that generated directory as my source directory of application. With that approach my web application directory will have /WEB-INF/classes "populated" with classes. That in turn will allow Tomcat to perform scanning job correctly (ie Servlet @WebServlet annotations will work).

I also had to change a source of my application in the launcher class:

public static void main(String[] args) throws Exception {
    // Web application is generated in directory name as specified in build/finalName
    // in maven pom.xml
    String webappDirLocation = "target/embeddedTomcatSample/";
    Tomcat tomcat = new Tomcat();

    // ... remaining code does not change

Changes to POM which I added - included maven-war-plugin just before appassembler plugin:

...
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-war-plugin</artifactId>
    <version>2.5</version>
    <executions>
        <execution>
            <phase>package</phase>
            <goals>
                <goal>exploded</goal>
            </goals>
        </execution>
    </executions>
</plugin>
...

Please note that exploded goal is called.

I hope that small change will help you.


One more comment on that tutorial and maven build: note that the tutorial was written to show how simple is to build an application and run it in Heroku. However, that is not the best approach to maven build.

Maven recommendation is that you should adhere to producing one artifact per POM. In your case there are should two artifacts:

  • Tomcat launcher
  • Tomcat web application

Both should be build as separate POMs and referenced as modules from your parent POM. If you look at the complexity of that tutorial, it does not make much sense to split that into two modules. But if your applications gets more and more complex (and the launcher gets some additional configurations etc.) it will makes a lot of sense to make that "split". As a matter of fact, there are some "Tomcat launcher" libraries already created so alternatively you could use of one them.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM