Hadoop NoSuchMethodError apache.commons.cli - java

I'm using hadoop-2.7.2 and I did a MapReduceJob with IntelliJ. In my job, I'm using apache.commons.cli-1.3.1 and I put the lib in the jar.
When I use the MapReduceJob on my Hadoop cluster I have a NoSuchMethodError:
Exception in thread "main" java.lang.NoSuchMethodError:
org.apache.commons.cli.Option.builder(Ljava/lang/String;)Lorg/apache/commons/cli/Option$Builder;
I don't understand because the method exist in the class Option and the class Option is extracted from the commons-cli.jar to my application jar. Moreover, I don't have this issue with my others libraries.
Thank you for your time.

We were able to fix this error using maven class relocations. If you are using the shade plugin to build your jar add following to pom.xml under appropriate section:
<!-- necessary to fix NoSuchMethodError: org.apache.commons.cli.Option.builder -->
<relocations>
<relocation>
<pattern>org.apache.commons.cli</pattern>
<shadedPattern>org.shaded.commons.cli</shadedPattern>
</relocation>
</relocations>
Also an explicit reference to v1.3+ of commons-cli needs to be added at the TOP of the dependencies section before any dependency that may have a transitive reference to an older version of commons-cli.

The problem seems to be related to how the classloader is loading the classes. Because the static Builder class was in common-cli 1.4, while some of the hadoop dependencies were still referring to older version - the issue occurred.
In my case, the issue resolved by changing the sequence of jar file addition into the classpath in the shell script responsible for setting up environment before program execution. Earlier, I was adding the jar into classpath like
CLASSPATH=<Hadoop Jars>:<Common CLI jar>:$CLASSPATH
is changed to
CLASSPATH=<Common CLI jar>:<Hadoop Jars>:$CLASSPATH
and it fixed the problem.

We solved this issue with the next gradle configuration:
compile('org.apache.parquet:parquet-tools:1.9.0'){
exclude module:"commons-cli"
}

Related

Getting `NoClassDefFoundError` for classes `FutureCallback` and `LazyList` using Jetty Maven plugin 9.4.32.v20200930 on Java 11

I started a few months ago to maintain an old Spring project using the Jetty Maven plugin. I'm currently trying to port it to Java 11 but Jetty won't start the server and (silently) fails with MultiException[java.lang.NoClassDefFoundError: org/eclipse/jetty/util/FutureCallback, java.lang.NoClassDefFoundError: org/eclipse/jetty/util/LazyList].
This seems to be an old bug of the Jetty Maven plugin that I can reproduce on various 9.x versions.
It seems fixed in versions 10 and 11 and I would gladly use these versions but both are still in alpha, configuration has radically changed and documentation is not published yet.
maven.compiler.source and maven.compiler.target are both set to 11 in POM and nothing changes if I put dependencies providing org.eclipse.jetty.util.FutureCallback and org.eclipse.jetty.util.LazyList in the POM.
[WARNING] FAILED ServletHandler#4ba402b5{FAILED}: java.lang.NoClassDefFoundError: org/eclipse/jetty/util/LazyList
java.lang.NoClassDefFoundError: org/eclipse/jetty/util/LazyList
at org.eclipse.jetty.servlet.ServletHandler.doStop (ServletHandler.java:277)
at org.eclipse.jetty.util.component.AbstractLifeCycle.stop (AbstractLifeCycle.java:93)
at org.eclipse.jetty.util.component.ContainerLifeCycle.stop (ContainerLifeCycle.java:180)
at org.eclipse.jetty.util.component.ContainerLifeCycle.doStop (ContainerLifeCycle.java:201)
at org.eclipse.jetty.server.handler.AbstractHandler.doStop (AbstractHandler.java:108)
at org.eclipse.jetty.security.SecurityHandler.doStop (SecurityHandler.java:437)
at org.eclipse.jetty.security.ConstraintSecurityHandler.doStop (ConstraintSecurityHandler.java:425)
at org.eclipse.jetty.util.component.AbstractLifeCycle.stop (AbstractLifeCycle.java:93)
at org.eclipse.jetty.util.component.ContainerLifeCycle.stop (ContainerLifeCycle.java:180)
at org.eclipse.jetty.util.component.ContainerLifeCycle.doStop (ContainerLifeCycle.java:201)
at org.eclipse.jetty.server.handler.AbstractHandler.doStop (AbstractHandler.java:108)
at org.eclipse.jetty.server.session.SessionHandler.doStop (SessionHandler.java:519)
at org.eclipse.jetty.util.component.AbstractLifeCycle.stop (AbstractLifeCycle.java:93)
at org.eclipse.jetty.util.component.ContainerLifeCycle.stop (ContainerLifeCycle.java:180)
at org.eclipse.jetty.util.component.ContainerLifeCycle.doStop (ContainerLifeCycle.java:201)
at org.eclipse.jetty.server.handler.AbstractHandler.doStop (AbstractHandler.java:108)
at org.eclipse.jetty.server.handler.ContextHandler.stopContext (ContextHandler.java:1061)
at org.eclipse.jetty.servlet.ServletContextHandler.stopContext (ServletContextHandler.java:375)
at org.eclipse.jetty.webapp.WebAppContext.stopWebapp (WebAppContext.java:1462)
at org.eclipse.jetty.maven.plugin.JettyWebAppContext.stopWebapp (JettyWebAppContext.java:342)
at org.eclipse.jetty.webapp.WebAppContext.stopContext (WebAppContext.java:1428)
at org.eclipse.jetty.server.handler.ContextHandler.doStop (ContextHandler.java:1115)
at org.eclipse.jetty.servlet.ServletContextHandler.doStop (ServletContextHandler.java:286)
at org.eclipse.jetty.webapp.WebAppContext.doStop (WebAppContext.java:547)
at org.eclipse.jetty.maven.plugin.JettyWebAppContext.doStop (JettyWebAppContext.java:433)
This is a interesting side-effect of interaction between maven and jetty.
What happens is that on jetty stop/shutdown the maven process yanks the classloader out from underneath the jetty threads leaving random errors in its wake, some even being unable to find classes that they need to perform a clean shutdown.
See https://github.com/eclipse/jetty.project/issues/4410
There is no workaround or fix for this that either Jetty or Maven has found.
If you find a solution please comment on the above issue (or file a new issue), and we'll document it.

WFLYEE0040: A component named '...' is already defined in this module

I get this error in a Java maven project. The weird thing is, it doesn't appear on every machine so I assume it has something to do with a configuration issue.
The class RoleKeyCacheImpl is a #Startup #Singleton:
#Startup
#Singleton
public class RoleKeyCacheImpl implements RoleKeyCache { ... }
That's the error Wildfly triggers when deploying the service.
Caused by: java.lang.IllegalArgumentException: WFLYEE0040: A component
named 'RoleKeyCacheImpl' is already defined in this module at
org.jboss.as.ee.component.EEModuleDescription.addComponent(EEModuleDescription.java:167)
at
org.jboss.as.ejb3.deployment.processors.EJBComponentDescriptionFactory.addComponent(EJBComponentDescriptionFactory.java:58)
I've tried:
installing a new Wildfly (V10, V13) on the same machine -> doesn't help
installing a completely new Eclipse on this machine -> doesn't help
cleaning & rebuilding all related projects
making sure the deployments-folder is empty and doesn't contain old versions of the same WAR
read the related question here which also didn't help (they use Spring): A component named 'XXX' is already defined in this module in JBoss 7.1.1
read and tried this q&a: Wrong dependencies with EJB in JBoss Wildfly (server-clean) -> doesn't help
deleted and rebuilt the local maven rep (".m2") -> no effect
checking out the same source on another computer -> does work on one machine, on another it gives the same error
I have absolutely no clue what the issue is or even could be. On one machine, we check it out and it runs without errors. On others, the exact same error happens.
Does anybody have an idea?
I had this same issue multiple times with EAP 7.1 and now again with WildFly 21.0.0. I know by experience this is an issue caused by Eclipse who tries to deploy automatically to a configured WildFly instance. During the deployment (or undeployment) some concurrent file issue arises and files who should be removed, are still on the filesystem, causing this error that a component is already defined.
In fact it is not already defined, it is just WildFly that is confused because it finds in his temporary directories some old files which shouldn't be there and reference your exact same component.
Solution: remove in the WildFly standalone directory the content in the 'deployments' directory and the 'tmp' directory. Rest assured, all what is there is okay to remove safely. Reboot and the error message will be gone ;-)
You should pay attention to not have two #Stateless EJB annotations on top of two classes with the same name - in the same module.
You may differentiate them by using the name attribute in the annotation and put different values in each class
Looks like the class already exists. Check if it does...you may have to rewrite that part of EEModuleDescription to use its own private methods (which would be what you would write) rather than overriding methods in RoleKeyCacheImpl. If the class actually does not exist then right-click on the project -> Maven 2 Tools -> Generate Eclipse Artifacts (Check for Updates). That will regenerate all of the dependencies that the project uses. Also please be sure that you have not added any new projects to the classpath by mistake as that may also cause this error.
I just ran into this today when a colleague added a maven dependency.
Turns out this dependency was a jar with a nasty classpath entry or "../" in the manifest.
I edited the jar's manifest.mf that was cached in my local maven repository using 7-zip and removed the "../" classpath entry.
Then re-packaged my war file (maven clean install) and bingo, it works!
In my case it was caused by org.libreoffice jurt version 5.4.2 (but other versions I checked also have the classpath nastiness).
Unfortunately I was lucky we pinpointed it to a dependency, YMMV!

Error: No class Def found error while setting up Java as a Windows Service

Following is the error log I'm getting:
I'm using
wrapper-windows-x86-32-3.5.25-pro
in order to make my already developed application in Spring-boot. I wanted to execute this application as a windows service but I'm not.
This problem is specific to Tanukisoftware as I'm unable to configure it.
PFB the configuration I'm using for setting up the class path here:
wrapper.java.classpath.1=../lib/wrappertest.jar
wrapper.java.classpath.2=../lib/wrapper.jar
wrapper.java.classpath.3=../lib/slf4j-api-1.7.5
wrapper.java.classpath.4=../lib/myApp.jar
even if myApp.jar contains the slf4j classpath already and its running already. I think this is library specific problem and its not finding up the classpath even if I explicitly set it like did above.
Can you please let me know how it can be solved?
Did you try building a fat jar of your application ? You can add following lines to your Spring Boot project's pom.xml to repackage jar file:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
Besides, your following property line seems invalid:
wrapper.java.classpath.3=../lib/slf4j-api-1.7.5
Is it pointing a jar file actually ?
slf4j-api-1.7.5 should have a .jar extension. That is possibly confusing things.
Also, even just as a debugging step, try running your Windows service using Apache ProcRun to see if your results are any different.

Caused By: java.lang.NoClassDefFoundError: org/apache/log4j/Logger

I've got an interesting problem in which the org.apache.log4j.Logger class is not found during runtime. I'm trying to get authorized and that is where it's failing:
OAuthAuthorizer oauthAuthorizer = new OAuthAuthorizer(OAUTH_CONSUMER_KEY, OAUTH_CONSUMER_SECRET, SAML_PROVIDER_ID, userId);
I'm using JDeveloper 11.1.1.6. Here is what I know:
I've looked in my UI.war/WEB-INF/lib directory and I see the log4j-1.2.17.jar there.
The class complaining about it is org.opensaml.xml.XMLConfigurator
Caused by: java.lang.NoClassDefFoundError: org/apache/log4j/Logger
at org.opensaml.xml.XMLConfigurator.<clinit>(XMLConfigurator.java:60)
at org.opensaml.DefaultBootstrap.initializeXMLTooling(DefaultBootstrap.java:195)
at org.opensaml.DefaultBootstrap.bootstrap(DefaultBootstrap.java:91)
at com.intuit.ipp.aggcat.util.SAML2AssertionGenerator.getSAMLBuilder(SAML2AssertionGenerator.java:156)
at com.intuit.ipp.aggcat.util.SAML2AssertionGenerator.createSubject(SAML2AssertionGenerator.java:187)
at com.intuit.ipp.aggcat.util.SAML2AssertionGenerator.buildAssertion(SAML2AssertionGenerator.java:114)
at com.intuit.ipp.aggcat.util.SAML2AssertionGenerator.generateSignedAssertion(SAML2AssertionGenerator.java:83)
at com.intuit.ipp.aggcat.util.SamlUtil.createSignedSAMLPayload(SamlUtil.java:156)
at com.intuit.ipp.aggcat.util.OAuthUtil.getOAuthTokens(OAuthUtil.java:60)
at com.intuit.ipp.aggcat.core.OAuthAuthorizer.<init>(OAuthAuthorizer.java:85)
at com.incomemax.view.intuit.WebUtil.getAggCatService(WebUtil.java:91)
Caused by: java.lang.ClassNotFoundException: org.apache.log4j.Logger
at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at java.lang.ClassLoader.loadClass(ClassLoader.java:305)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
at java.lang.ClassLoader.loadClass(ClassLoader.java:246)
... 64 more
I decomplied XMLConfigurator and oddly it doesn't import org.apache.log4j.Logger It uses org.slf4j.Logger which is also in my jars directory (slf4j-api-1.7.5.jar). Also interesting is that line 60 (see stack trace) is a blank line in my decompile.
Of course if I add Logger.xxxxx during design time, it finds it just fine.
I'm using the code/jars directly from the sample java code, but imported into my existing application.
I've been scouring the web for answers and I believe I've checked all the areas I can think of. I also referenced this very good page: http://myarch.com/classnotfound/
Given authorization is step 1 in using the Intuit Developer API, I'm kinda stuck.
Adding output from #jhadesdev suggestion:
All versions of log4j Logger:
zip:C:/Users/Chris/AppData/Roaming/JDeveloper/system11.1.1.6.38.61.92/DefaultDomain/servers/DefaultServer/tmp/_WL_user/j2ee-app/lt5l71/war/WEB-INF/lib/log4j-1.2.17.jar!/org/apache/log4j/Logger.class
All versions of log4j visible from the classloader of the OAuthAuthorizer class:
zip:C:/Users/Chris/AppData/Roaming/JDeveloper/system11.1.1.6.38.61.92/DefaultDomain/servers/DefaultServer/tmp/_WL_user/j2ee-app/lt5l71/war/WEB-INF/lib/log4j-1.2.17.jar!/org/apache/log4j/Logger.class
All versions of XMLConfigurator:
jar:file:/C:/Oracle/Middleware11116/modules/com.bea.core.bea.opensaml2_1.0.0.0_6-1-0-0.jar!/org/opensaml/xml/XMLConfigurator.class
zip:C:/Users/Chris/AppData/Roaming/JDeveloper/system11.1.1.6.38.61.92/DefaultDomain/servers/DefaultServer/tmp/_WL_user/j2ee-app/lt5l71/war/WEB-INF/lib/ipp-java-aggcat-v1-devkit-1.0.2.jar!/org/opensaml/xml/XMLConfigurator.class
zip:C:/Users/Chris/AppData/Roaming/JDeveloper/system11.1.1.6.38.61.92/DefaultDomain/servers/DefaultServer/tmp/_WL_user/j2ee-app/lt5l71/war/WEB-INF/lib/xmltooling-1.3.1.jar!/org/opensaml/xml/XMLConfigurator.class
All versions of XMLConfigurator visible from the class loader of the OAuthAuthorizer class:
jar:file:/C:/Oracle/Middleware11116/modules/com.bea.core.bea.opensaml2_1.0.0.0_6-1-0-0.jar!/org/opensaml/xml/XMLConfigurator.class
zip:C:/Users/Chris/AppData/Roaming/JDeveloper/system11.1.1.6.38.61.92/DefaultDomain/servers/DefaultServer/tmp/_WL_user/j2ee-app/lt5l71/war/WEB-INF/lib/ipp-java-aggcat-v1-devkit-1.0.2.jar!/org/opensaml/xml/XMLConfigurator.class
zip:C:/Users/Chris/AppData/Roaming/JDeveloper/system11.1.1.6.38.61.92/DefaultDomain/servers/DefaultServer/tmp/_WL_user/j2ee-app/lt5l71/war/WEB-INF/lib/xmltooling-1.3.1.jar!/org/opensaml/xml/XMLConfigurator.class
I'm still working on interpreting the results.
During runtime your application is unable to find the jar.
Taken from this answer by Jared:
It is important to keep two different exceptions straight in our head
in this case:
java.lang.ClassNotFoundException This an Exception, it indicates that the
class was not found on the classpath. This indicates that we were
trying to load the class definition, and the class did not exist on
the classpath.
java.lang.NoClassDefFoundError This is Error, it indicates that the JVM
looked in its internal class definition data structure for the
definition of a class and did not find it. This is different than
saying that it could not be loaded from the classpath. Usually this
indicates that we previously attempted to load a class from the
classpath, but it failed for some reason - now we're trying again,
but we're not even going to try to load it, because we failed
loading it earlier. The earlier failure could be a
ClassNotFoundException or an ExceptionInInitializerError (indicating
a failure in the static initialization block) or any number of other
problems. The point is, a NoClassDefFoundError is not necessarily a
classpath problem.
for similarities and differences
You can use the following maven dependency in your pom file. Otherwise, you can download the following two jars from net and add it to your build path.
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.6.4</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.6.4</version>
</dependency>
This is copied from my working project. First make sure it is working in your project. Then you can change the versions to use any other(versions) compatible jars.
For AggCat, you can refer the POM file of the sample java application.
https://github.com/IntuitDeveloperRelations/IPP_Sample_Code/blob/master/CustomerAccountData/Java/AggCatSampleApplication/pom.xml
Thanks
Check in Deployment Assembly,
I have the same error, when i generate the war file with the "maven clean install" way and deploy manualy, it works fine, but when i use the runtime enviroment (eclipse) the problems come.
The solution for me (for eclipse IDE) go to: "proyect properties" --> "Deployment Assembly" --> "Add" --> "the jar you need", in my case java "build path entries".
Maybe can help a litle!
With the suggestions #jhadesdev and the explanations from others, I've found the issue here.
After adding the code to see what was visible to the various class loaders I found this:
All versions of log4j Logger:
zip:<snip>war/WEB-INF/lib/log4j-1.2.17.jar!/org/apache/log4j/Logger.class
All versions of log4j visible from the classloader of the OAuthAuthorizer class:
zip:<snip>war/WEB-INF/lib/log4j-1.2.17.jar!/org/apache/log4j/Logger.class
All versions of XMLConfigurator:
jar:<snip>com.bea.core.bea.opensaml2_1.0.0.0_6-1-0-0.jar!/org/opensaml/xml/XMLConfigurator.class
zip:<snip>war/WEB-INF/lib/ipp-java-aggcat-v1-devkit-1.0.2.jar!/org/opensaml/xml/XMLConfigurator.class
zip:<snip>war/WEB-INF/lib/xmltooling-1.3.1.jar!/org/opensaml/xml/XMLConfigurator.class
All versions of XMLConfigurator visible from the classloader of the OAuthAuthorizer class:
jar:<snip>com.bea.core.bea.opensaml2_1.0.0.0_6-1-0-0.jar!/org/opensaml/xml/XMLConfigurator.class
zip:<snip>war/WEB-INF/lib/ipp-java-aggcat-v1-devkit-1.0.2.jar!/org/opensaml/xml/XMLConfigurator.class
zip:<snip>war/WEB-INF/lib/xmltooling-1.3.1.jar!/org/opensaml/xml/XMLConfigurator.class
I noticed that another version of XMLConfigurator was possibly getting picked up.
I decompiled that class and found this at line 60 (where the error was in the original stack trace) private static final Logger log = Logger.getLogger(XMLConfigurator.class); and that class was importing from org.apache.log4j.Logger!
So it was this class that was being loaded and used. My fix was to rename the jar file that contained this file as I can't find where I explicitly or indirectly load it. Which may pose a problem when I actually deploy.
Thanks for all help and the much needed lesson on class loading.
Based on the stacktrace, an intuit class com.intuit.ipp.aggcat.util.SAML2AssertionGenerator needs a saml jar on the classpath.
A saml class org.opensaml.xml.XMLConfigurator needs on it's turn log4j, which is inside the WAR but cannot find it.
One explanation for this is that the class XMLConfigurator that needs log4j was found not inside the WAR but on a downstream classloader. could a saml jar be missing from the WAR?
The class XMLConfigurator that needs log4j cannot find it at the level of the classloader that loaded it, and the log4j version on the WAR is not visible on that particular classloader.
In order to troubleshoot this, a way is to add this before the oauth call:
System.out.println("all versions of log4j Logger: " + getClass().getClassLoader().getResources("org/apache/log4j/Logger.class") );
System.out.println("all versions of XMLConfigurator: " + getClass().getClassLoader().getResources("org/opensaml/xml/XMLConfigurator.class") );
System.out.println("all versions of XMLConfigurator visible from the classloader of the OAuthAuthorizer class: " + OAuthAuthorizer.class.getClassLoader().getResources("org/opensaml/xml/XMLConfigurator.class") );
System.out.println("all versions of log4j visible from the classloader of the OAuthAuthorizer class: " + OAuthAuthorizer.class.getClassloader().getResources("org/apache/log4j/Logger.class") );
Also if you are using Java 7, have a look at jHades, it's a tool I made to help troubleshooting these type of problems.
In order to see what is going on, could you post the results of the classpath queries above, for which container is this happening, tomcat, jetty? It would be better to put the full stacktrace with all the caused by's in pastebin, just in case.
Had the same problem, it was indeed caused by weblogic stupidly using its own opensaml implementation. To solve it, you have to tell it to load classes from WEB-INF/lib for this package in weblogic.xml:
<prefer-application-packages>
<package-name>org.opensaml.*</package-name>
</prefer-application-packages>
maybe <prefer-web-inf-classes>true</prefer-web-inf-classes> would work too.
java.lang.ClassNotFoundException is indicate that class is not found in class path.
it could be the version of log4j is not compatible.
check for different log4j version.
I had the same issue, for me this fixed the issue:
right click on the project ->maven -> update project
Add compile 'org.apache.logging.log4j:log4j-1.2-api:2.17.1' and then it will automatically work
In my case, the error was due to some dependencies using log4j v 1.x that I removed from the classpath. So I introduced the log4j-1.2-api to bridge v 1.x to 2.x as recommended in the Apache Migration guide:
After introducing this dependency in my build.gradle, the error disappeared :
implementation 'org.apache.logging.log4j:log4j-1.2-api:2.17.+!!'
Following works for me everytime I face the problem
rightclick on project(say abc-war)-> properties -> Deployment assembly->add->java build path entries->Maven dependencies.

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.
Try:
mvn clean package jar:jar appassembler:assemble
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.
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 (i.e. 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.
You can set the CLASSPATH_PREFIX environment variable:
export CLASSPATH_PREFIX=target/classes
which will get prepended to the classpath of the generated script.
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.

Categories