I've been seeing odd behaviour from my Maven 2.2.1 installation whilst doing war installs.
Occasionally, I will update a class but the updated version is not packaged up in the artifact produced by mvn install.
So far, I have determined that an updated .class file is produced in the target directory, and that the class of the same name in the produced .war is not the same (different date modified, different size)
Running Maven from the command line with the -X flag produced debug output for the class like:
[DEBUG] *
WEB-INF/classes/mypackage/MyClass.class
is up to date.
I think I've also had the same problem before where the file that was cached(?) was an incomplete compile from Eclipse, causing 'Unresolved Compilation Problem' errors from the Maven build, but a working artifact from an Eclipse export.
How does Maven determine whether a
file 'is up to date' during the
install process?
Where are the files Maven is comparing to?
Can I force Maven to build a package from scratch?
Any other ideas would be appreciated!
So far, I have determined that an
updated .class file is produced in the
target directory, and that the class
of the same name in the produced .war
is not the same (different date
modified, different size)
Just to be sure, the classes should be built under target\classes, not target.
Can I force Maven to build a package from scratch?
You can force a full build by running
mvn clean install
This performs a clean (essentially removes the target directory) before running the install phase.
Also - check for copies of your classes outside of the Maven build directory. In this case as it is a webapp, check src/main/webapp/WEB-INF/classes
Related
What are the possible causes of a "java.lang.Error: Unresolved compilation problem"?
Additional information:
I have seen this after copying a set of updated JAR files from a build on top of the existing JARs and restarting the application. The JARs are built using a Maven build process.
I would expect to see LinkageErrors or ClassNotFound errors if interfaces changed. The above error hints at some lower level problem.
A clean rebuild and redeployment fixed the problem. Could this error indicate a corrupted JAR?
(rewritten 2015-07-28)
Summary: Eclipse had compiled some or all of the classes, and its compiler is more tolerant of errors.
Long explanation:
The default behavior of Eclipse when compiling code with errors in it, is to generate byte code throwing the exception you see, allowing the program to be run. This is possible as Eclipse uses its own built-in compiler, instead of javac from the JDK which Apache Maven uses, and which fails the compilation completely for errors. If you use Eclipse on a Maven project which you are also working with using the command line mvn command, this may happen.
The cure is to fix the errors and recompile, before running again.
The setting is marked with a red box in this screendump:
try to clean the eclipse project
you just try to clean maven by command
mvn clean
and after that following command
mvn eclipse:clean eclipse:eclipse
and rebuild your project....
Your compiled classes may need to be recompiled from the source with the new jars.
Try running "mvn clean" and then rebuild
The major part is correctly answered by Thorbjørn Ravn Andersen.
This answer tries to shed light on the remaining question: how could the class file with errors end up in the jar?
Each build (Maven & javac or Eclipse) signals in its specific way when it hits a compile error, and will refuse to create a Jar file from it (or at least prominently alert you). The most likely cause for silently getting class files with errors into a jar is by concurrent operation of Maven and Eclipse.
If you have Eclipse open while running a mvn build, you should disable Project > Build Automatically until mvn completes.
EDIT:
Let's try to split the riddle into three parts:
(1) What is the meaning of "java.lang.Error: Unresolved compilation
problem"
This has been explained by Thorbjørn Ravn Andersen. There is no doubt that Eclipse found an error at compile time.
(2) How can an eclipse-compiled class file end up in jar file created
by maven (assuming maven is not configured to used ecj for
compilation)?
This could happen either by invoking Maven with no or incomplete cleaning. Or, an automatic Eclipse build could react to changes in the filesystem (done by Maven) and re-compile a class, before Maven proceeds to collect class files into the jar (this is what I meant by "concurrent operation" in my original answer).
(3) How come there is a compile error, but mvn clean succeeds?
Again several possibilities: (a) compilers don't agree whether or not the source code is legal, or (b) Eclipse compiles with broken settings like incomplete classpath, wrong Java compliance etc. Either way a sequence of refresh and clean build in Eclipse should surface the problem.
I had this error when I used a launch configuration that had an invalid classpath. In my case, I had a project that initially used Maven and thus a launch configuration had a Maven classpath element in it. I had later changed the project to use Gradle and removed the Maven classpath from the project's classpath, but the launch configuration still used it. I got this error trying to run it. Cleaning and rebuilding the project did not resolve this error. Instead, edit the launch configuration, remove the project classpath element, then add the project back to the User Entries in the classpath.
I got this error multiple times and struggled to work out. Finally, I removed the run configuration and re-added the default entries. It worked beautifully.
Just try to include package name in eclipse in case if you forgot it
Import all packages before using it, EX: import java.util.Scanner before using Scanner class.
These improvements might work and it will not give Java: Unresolved compilation problem anymore.
Also make sure to check compiler compliance level and selected jdk version is same
As a weird case, I encountered such an exception where the exception message (unresolved compilation bla bla) was hardcoded inside of generated class' itself. Decompiling the class revealed this.
I had the same issue using the visual studio Code. The root cause was backup java file was left in the same directory.
Removed the backup java file
When the build failed, selected the Fix it, it cleaned up the cache and restarted the workSpace.
I am distributing a Java package via git for other people to use. I am currently supplying a jar file to go with the source. This way, the user only needs to clone the project once into Intellij IDEA. Projects using the package can then follow this procedure
Correct way to add external jars (lib/*.jar) to an IntelliJ IDEA project
to use the package.
This works, but distributing a jar does not feel nice security-wise. On the other hand, this discussion
IntelliJ IDEA - adding .java file to project dependencies
suggests that to use the source code, you need to copy it into your src folder.
Is there a way to distribute source code (java files) only so that if multiple projects use the same package
the package only needs to be downloaded once
the package can be kept up to date with git pull?
I would really recommend not include jar or any binaries in a Git repo and the best approach to keep these dependencies in a local Nexus repository and use maven or Gradle as your dependency management tool.
I found a working solution:
Supply an Ant build file with the package. The build file compiles classes and packages them into a jar file. The default target is building the jar, which depends on compiling the classes.
Provide users with instructions on how to set the given Ant build file as a build file in Intellij IDEA and build the default target.
Then instruct them to follow the steps in the first link above to add the jar as a dependency.
How does mvn clean install works
mvn install should execute all the phases before install phase, that means it will first run the surefire test and then later update m2 respository with the dependency
Yes, this is how it works.
The phases are executed in order and the installation into the local repository is the last one.
With external dependencies it's simple: before compiling anything Maven downloads them.
With inter-module dependencies it's more complicated. It's important to understand that Maven first runs all phases for the 1st module, then runs all phases for the 2nd module, and so on. So depending on which phase you call there either will be a JAR file or there won't be.
Maven will try to give you as "high-quality" dependency as possible, meaning:
if you run mvn install - this will put 1st module's jar into ~/.m2, then by the time 2nd module starts - it already has a JAR dependency waiting in the local repo.
if you run mvn package the JAR doesn't go to local repo, it stays in target/. Thus this target/xxx.jar will be used as a dependency.
if you run mvn test there won't even be a JAR. There will only be target/classes. So 2nd module's compilation & runtime will have directory with classes & resources in its classpath (no JAR).
PS: this may actually lead to real implications. When you run tests in module2 you may be reading resources of module1 and working with their file paths. And everything will work fine in case of mvn test. But once you start running at least mvn package there won't be files anymore - all resources of module2 will be in JAR and thus can be accessed only with getResourceAsStream().
We have moved from Archiva to Nexus and are still using Maven 2.
We execute eclipse:eclipse locally so that Eclipse .project and .classpath files are generated, based on the dependencies in the POMs, and then we import the projects into Eclipse to do our development. We don't use M2Eclipse for a variety of reasons.
Since using Nexus, we have the problem that projects don't always reference each other in the workspace, rather they reference the respective JAR.
I have noticed that Nexus is appending a timestamp to the JAR name, and the MVN output states, e.g.:
[INFO] Artifact myapp-bom:jar:7.3.0.2.1-SNAPSHOT already available as a workspace project, but with different version. Expected: 7.3.0.2.1-20120508.115037-68, found: 7.3.0.2.1-SNAPSHOT
I get the feeling that is the reason why eclipse:eclipse generates .classpath files which contains JAR references (based on local maven repo) rather than project references. When we used Archiva (and there were no timestamps) then we used to get project references, and that is exactly what we want.
Has anyone else had this problem and how is it solved? I read that maven 3 forces timestamps to always be generated. Again, how do you get eclipse:eclipse to generate sensible .classpath files?
Cheers,
Ant
PS - some of our projects come from different SVN repositories. It seems that if the Eclipse Projects are refernced in the parent pom, eclipse:eclipse creates a project reference, but if the Eclipse Projects are from a different parent pom, but still in the workspace, then it can only generate JAR references.
The problem was resolved by using maven-eclipse-plugin (eclipse:eclipse) version 2.9, rather than 2.8! Doh...
on my Windows machine I do have several proeject that I build with maven. At the moment they are all in SNAPSHOT-State. When I build a project that relies on one of the other projects maven always adds the class files of the other projects to the jar.
If I build the project on my CI-Server this problem does not occur. Does anyone have an idea why maven adds the class files to my jar?
I'm using maven 2.2.1
When I build a project that relies on one of the other projects maven always adds the class files of the other projects to the jar.
This is not a default behavior and, if it happens, you're somehow telling Maven to do so. If you want to hunt potential discrepancies, check the effective-pom, the effective-settings, the active-profiles using the following goals on both machines:
help:effective-pom
help:effective-settings
help:active-profiles
Also double check how Maven is invoked on the CI machine (extra command line parameter, etc).