Why does the maven eclipse plugin break the maven jetty plugin? - eclipse

I would like to have the maven eclipse plugin regenerate my .classpath whenever a build is run, and I did so by using the following configuration:
<!--
Generate a new .classpath each time the build is run, but don't try
to download sources or javadocs
-->
<profile>
<id>elipse-update</id>
<activation>
<file>
<exists>.classpath</exists>
</file>
</activation>
<build>
<plugins>
<plugin>
<artifactId>maven-eclipse-plugin</artifactId>
<executions>
<execution>
<phase>generate-sources</phase>
<goals>
<goal>eclipse</goal>
</goals>
<configuration>
<downloadSources>false</downloadSources>
<downloadJavadocs>false</downloadJavadocs>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
For some reason, this causes the maven jetty plugin to fail with ClassNotFoundException errors (it complains about all sorts of Spring classes not being there). Of course, it worked without a hit when I didn't have the maven eclipse plugin installed. Here's an example of what I'm talking about:
$ mvn jetty:run
[INFO] Scanning for projects...
...
[INFO] Starting jetty 6.1.22 ...
2010-02-11 20:53:08.984:INFO::jetty-6.1.22
2010-02-11 20:53:09.109:WARN::Could not instantiate listener org.springframework.web.context.ContextLoaderListener
java.lang.ClassNotFoundException: org.springframework.web.context.ContextLoaderListener
at java.net.URLClassLoader$1.run(URLClassLoader.java:200)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:188)
at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
at org.codehaus.classworlds.RealmClassLoader.loadClassDirect(RealmClassLoader.java:195)
at org.codehaus.classworlds.DefaultClassRealm.loadClass(DefaultClassRealm.java:255)
at org.codehaus.classworlds.DefaultClassRealm.loadClass(DefaultClassRealm.java:274)
at org.codehaus.classworlds.RealmClassLoader.loadClass(RealmClassLoader.java:214)
at java.lang.ClassLoader.loadClass(ClassLoader.java:251)
Of course, if I delete that eclipse plugin section, I can run jetty as expected:
$ mvn jetty:run
[INFO] Scanning for projects...
...
Feb 11, 2010 8:55:28 PM org.springframework.web.context.ContextLoader initWebApplicationContext
INFO: Root WebApplicationContext: initialization completed in 1672 ms
2010-02-11 20:55:28.687:INFO::Started SelectChannelConnector#0.0.0.0:8080
[INFO] Started Jetty Server
[INFO] Starting scanner at interval of 5 seconds.
Some things I know:
Yes, I only activate this profile if the .classpath is present. This seems counter-intuitive, but I have a reason: I have another profile that activates when the .classpath is absent which runs the eclipse plugin with the options for downloading source code and javadocs set to true. I don't want this to happen each build, so I created a separate plugin config for when the classpath is already there.
Yes, I could simply create properties that held the values of the options I wish to change instead of specifying the entire plugin config again. In that case, I would just set a eclipse.downloadSources property to true or false depending on the presence of the classpath and have a single plugin definition in the regular build section.
Any advice? This is a strange problem.
Thanks,
LES

I suspect the Maven Eclipse Plugin to mess do some classpath woodo that affects the jetty plugin later.
But to be honest, this is not a very common way to use the Eclipse plugin, at least not to my knowledge. Most people don't include it in their build, they just run it when the POM has changed and this generally doesn't happen every build. Moreover, touching the .classpath confuses Eclipse if I remember well and forces a clean rebuild of the project which is pretty annoying.
So at the end, and I'm sorry for that, this seems to introduce more annoyances than benefits. You can try to open a Jira issue though.

You really don't want to run the maven-eclipse-plugin on every build when there's a .classpath present. I can't tell you exactly what it does to the classpaths, but this is not how it's intended to be used. The assumption is that when you run it you only run eclipse:eclipse (or some other goal).
Why do you want to keep re-running it?

Related

Apache CXF using eclipse: A required class was missing while executing org.apache.cxf:cxf-codegen-plugin:3.2.:wsdl2java

When trying to build our project from within Eclipse I keep getting the following error:
Execution generate-sources of goal
org.apache.cxf:cxf-codegen-plugin:3.2.0:wsdl2java failed: A required
class was missing while executing
org.apache.cxf:cxf-codegen-plugin:3.2.0:wsdl2java:
javax/xml/bind/annotation/adapters/HexBinaryAdapter
The reason for that is that - while we still compile for a Java-8 target environment - the tool chain (i.e. Eclipse, M2E (Eclipe's Maven-plugin), Maven, and CXF) is executed using Java-11.
In Java 9+ javax/xml/bind is not part of the rt.jar anymore, hence the class is missing when the plugin tries to start up. Elsewhere I found that one can enable it by specifying an "--add-modules java.xml.bind" JVM option.
I tried adding that option to the MAVEN_OPTS environment variable but that is apparently ignored when M2E starts up Maven (and with it the CXF plugin) in a separate VM.
Next I tried to specify that option in the plugin's configuration in the pom.xml like so:
<build>
<plugins>
<plugin>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-codegen-plugin</artifactId>
<version>${cxf.version}</version>
<executions>
<execution>
<id>generate-sources</id>
<phase>generate-sources</phase>
<configuration>
<fork>true</fork>
<additionalJvmArgs>--add-modules java.xml.bind</additionalJvmArgs>
...
</configuration>
<goals>
<goal>wsdl2java</goal>
</goals>
</execution>
</executions>
...
... but that also didn't fly. :-(
Any idea anyone, how and where one can specify that option or how I can make the former standard javax-classes available to a Maven-plugin running under Java 9+ (when executed from Eclipse M2E) ?
Just in case: this is NOT an Eclipse or M2E issues! Even when I start Maven on the command line using Java 9+ I get:
...
[ERROR] Failed to execute goal org.apache.cxf:cxf-codegen-plugin:3.2.0:wsdl2java (generate-sources) on project my_project: Execution generate-sources of goal org.apache.cxf:cxf-codegen-plugin:3.2.0:wsdl2java failed: A required class was missing while executing org.apache.cxf:cxf-codegen-plugin:3.2.0:wsdl2java: javax/xml/bind/annotation/adapters/HexBinaryAdapter

Maven Jetty plugin, how to hot deploy code changs in dependent projects?

I have a war project that depends on another jar project in the same directory.
Now I want to start the war project in jetty with maven, and want it to hot swap changes in the dependent project so that the chagnes take effect immediately. My plugin config looks like this:
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>maven-jetty-plugin</artifactId>
<configuration>
<webAppSourceDirectory>${project.basedir}/src/main/resources</webAppSourceDirectory>
<classesDirectory>${project.basedir}/src/main/java</classesDirectory>
<webApp>
<contextPath>/</contextPath>
<descriptor>${basedir}/src/main/resources/WEB-INF/web.xml</descriptor>
</webApp>
</configuration>
</plugin>
How can i do it please? any pointer is appreciated.
First thing to point out...
You don't want to do this, as JAR reloading is poorly supported by Java itself, it will tend to want to cache the JAR and its contents on first use (standard behavior of the URLClassLoader). Replacing the JAR at runtime requires extra work, and sometimes even that is not possible without incurring some sort of memory leak (see the the various Leak Preventers that Jetty ships with for some hidden nasties in this area). Be prepared for OOM or other issues if you rely on this.
Now, with that out of the way ...
Hot Deployment on Jetty works by detecting/scanning for changes in the webapp and performing a webapp restart.
This works great with content, like html, js, css, etc.
Project JAR dependencies, which will wind up as part of the WEB-INF/lib structure, are part of the Jetty WebAppContext's [WebAppClassLoader].
This WebAppClassLoader is populated from information provided by Maven's artifact resolution system, which on a normal command line build resolves to content via the Maven local repository system. If you are using maven from Eclipse, the resolution of these artifacts might be other projects in your Eclipse workspace (more on this later)
To demonstrate, this is the minimal configuration for scanning for changes every 2 seconds on your webapp.
<plugin>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>9.1.0.v20131115</version>
<configuration>
<scanIntervalSeconds>2</scanIntervalSeconds>
<webAppConfig>
<contextPath>/</contextPath>
</webAppConfig>
</configuration>
</plugin>
Lets say you have a dependant project, a jar file under the maven artifact coordinates of com.company:component:jar:1.0-SNAPSHOT.
That means the WebAppContext was loaded with a WebAppClassLoader reference to a URL of file://${user.dir}/.m2/repository/com/company/component/1.0-SNAPSHOT/component-1.0-SNAPSHOT.jar and only changes to that file will cause a hot deploy / reload.
Its simple enough on a command line in your /component/ directory to just issue a mvn clean install and see your webapp reload, but under Eclipse and its m2e plugin, a code change to the component project does not automatically represent a change to the jar file in your local repository.
In fact, m2e can be configured to swap out maven artifact references via the local repository for ones in your eclipse workspace. You need to be aware of theses settings to have success with your hot deploy / reload efforts.
Tip for figuring out your active WebAppClassloader contents
Add the following file to your war project.
src/main/jetty/dump.xml
<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN"
"http://www.eclipse.org/jetty/configure_9_0.dtd">
<Configure id="Server" class="org.eclipse.jetty.server.Server">
<Set name="dumpAfterStart">true</Set>
</Configure>
And change your jetty-maven-plugin configuration to add ...
<plugin>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<configuration>
...
<jettyXml>src/main/jetty/dump.xml</jettyXml>
</configuration>
</plugin>
Now when your server starts, look for the extra output, particularly the WebAppClassLoader references.
...(snip)...
| | |
| | +> WebAppClassLoader=Web App Live#39714203
| | | +- file:/home/joakim/code/stackoverflow/samples/webapp-live/target/classes/
| | | +- file:/home/joakim/.m2/repository/org/eclipse/jetty/demo/component/1.0-SNAPSHOT/component-1.0-SNAPSHOT.jar
| | | +- ClassRealm[plugin>org.eclipse.jetty:jetty-maven-plugin:9.1.0.v20131115, parent: sun.misc.Launcher$AppClassLoader#77fe0d66]
...(/snip)...
You can see that my jetty:run has a reference to the component via the local repository.

Eclipse searching for the wrong surefire dependency

On building my workspace, my Java 6 Maven project is marked with an error (a Maven problem):
Could not calculate build plan: The repository system is offline but the artifact org.apache.maven.surefire:surefire:pom:2.7.1 is not available in the local repository.
What strikes me as odd is that it is searching for org.apache.maven.surefire:surefire while the true dependency is org.apache.maven.surefire:maven-surefire-plugin.
My effective pom is showing:
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.7.1</version>
<executions>
I'm using Eclipse Indigo with the m2eclipse plugin. And it compiles correctly when running any Maven goal. I tried cleaning the project, reimporting it, clearing the .metadata file.
Where does this behavior come from? Thanks
The mentioned dependency is the parent project for the maven-surefire-plugin and should usually not given directly only via the maven-surefire-plugin itself.
Furthermore What strikes me as odd is that it is searching for org.apache.maven.surefire:surefire while the true dependency is org.apache.maven.surefire:maven-surefire-plugin. which is simply wrong, cause the correct groupId and artifactId for the maven-surefire-plugin is:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.7.2</version>
...
</plugin>
It could be possible having problems while accessing maven central. Apart from the above you should update the maven-surefire-plugin cause the current up-to-date version is 2.15.

How to run the project after building with maven

I am new to maven. So I have a project with pom.xml file. So I ran that with maven and the build was successful. I have glassfish. Glassfish is already running separately. So now what is the next step to run the project with Glassfish? My IDE is eclipse.
You have to first tell Maven to build the WAR, check out this plugin for that: http://maven.apache.org/plugins/maven-war-plugin/.
Then you need to tell maven how to deploy to glassfish, you can either configure a Maven execution plugin to do this (see here: https://www.mojohaus.org/exec-maven-plugin/). Or you can look around for a custom plugin devoted to integrating maven with glassfish. This one looks promising, but I have not used it: http://maven-glassfish-plugin.java.net/.
Maven provides a lot of basic functionality out of the box, but most of the cooler stuff with build automation is done through plugins.
Update
Just updating to add a very simple Pom that will do a auto-deployment. Note: if you just run a "mvn clean install", with the packaging set to 'war', maven will build the .war file for you and place it in the target/ folder. You can take this and deploy it to glassfish manually if you just want to get started.
Below is part of a very simple pom that uses the Maven execution plugin to auto-deploy to glassfish as a function of the build:
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>exec</goal>
</goals>
<phase>install</phase>
</execution>
</executions>
<configuration>
<executable>${path-to-asadmin-util}</executable>
<arguments>
<argument>deploy</argument>
<argument>--user=${username}]</argument>
<argument>--passwordfile=${password-file}</argument>
<argument>--host=localhost</argument>
<argument>--port=4848</argument>
<argument>target/${project.name}</argument>
</arguments>
</configuration>
</plugin>
</plugins>
</build>
This basically just calls the deploy command on the glassfish asadmin utility[1]. You need to fill in the following variables:
${path-to-asadmin-util} --> this is the path to your asadmin utility
(normally in the glassfish_home/bin)
${username} --> glassfish admin username
${password-file} --> password file for logging into glassfish
admin[2]
${project.name} --> name of your war
If you want to get more complicated I suggest taking a look at this thread: GlassFish v3 and glassfish-maven-plugin (Mac).
[1] - http://docs.oracle.com/cd/E18930_01/html/821-2433/deploy-1.html#SJSASEEREFMANdeploy-1
[2] - http://docs.oracle.com/cd/E18930_01/html/821-2435/ghgrp.html#ghytn
Additonnaly, you should have a glance at this StackOverflow thread, dealing with maven deployement in glassifsh : https://stackoverflow.com/a/1836691/1047365.
For further understanding of Maven, you should REALLY read this (free) book : http://www.sonatype.com/books/mvnref-book/reference/. This is THE reference for Maven.
We can explain you what Maven is doing, producing, etc ... but Sonatype made a great work and you'll probably learn more reading it than we could ever do !
Regards.
I found this tutorial useful: http://tshikatshikaaa.blogspot.com/2012/05/introduction-to-maven-concepts-crash.html

GWT Maven and web.xml

I'm using the GWT Maven plugin from Codehaus with m2eclipse. Where is my web.xml file supposed to end up? Isn't the Maven build supposed to copy it to the /war directory? I can't see it there. Or does Jetty pick it up automatically from src/main/webapp/WEB-INF/?
Here's a relevant section from my pom.xml.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.0.2</version>
<configuration>
<warSourceDirectory>war</warSourceDirectory>
<webXml>src/main/webapp/WEB-INF/web.xml</webXml>
</configuration>
</plugin>
I believe web.xml (and everything else under src/main/webapp/) gets copied into target/<projectname>-<version>/ during the normal maven lifecycle (For example, when you run mvn install).
If you're running any of the gwt-maven plugin goals, then check out this link.
When running gwt:run, if you want to run the full web app just as if you have built and deployed a war, I found the best way is to add the following to the configuration for the gwt-maven plugin:
<hostedWebapp>
${project.build.directory}/${project.build.finalName}
</hostedWebapp>
This tells gwt-maven plugin to look for the web.xml (and all the other parts of the war file) under target/<projectname>-<version>/. So make sure to either run mvn install first (or mvn war:exploded), then run mvn gwt:run and you should be set.