With javac, it is possible to implicitly compile java files to class files from a particular source tree. In other words, it's possible to point at a given source tree and only compile the java files that are required by the explicitly mentioned java files. Is it possible to get this same functionality when building with maven. And, if so, how would I go about doing this?
Edit: I am not speaking of defining a specific list of java source files. The standard java compiler allows for a switch which causes the compiler itself to determine the dependencies based upon the imports. If the imported classes cannot be found in the classpath, then the source path is examined to see if there is a java file for the given class. If there is, then that java file is added to the compilation.
You will have to configure the maven compiler to set which files to include/exclude:
<project>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugi ns</groupId>
<artifactId>maven-compiler-plug in</artifactId>
<configuration>
<!-- put your configurations here -->
</configuration>
</plugin>
</plugins>
</build>
</project>
You could also do this for different maven profiles if you wanted to include/exclude different sets of files.
For the maven-compiler-plugin you can use includes and excludes sets, where you can specify patters for file names for exclusion and inclusion to the compilation. You can also use Ant scripts.
For details see http://maven.apache.org/plugins/maven-compiler-plugin/compile-mojo.html.
Related
I have a maven project called A, and it depends on another jar file called B.jar, both A and B.jar has same class but with different version. During maven build that classes in B.jar always overlap in A. What's the way to let maven only takes the classes in A not B?
I think that you have a real problem of conception about your Maven modules.
A JAR is not designed to exclude some classes when it is used by another JAR.
Why in B JAR, don't you provide a way to choose at runtime the implementation class to use ?
You can allow it by multiple ways : a property, an interface to implement ,etc....
In this way, you could specify the class to use in the client application.
You should think in terms of API to implement by client classes, not in terms of overwriting classes.
It doesn't mean that you cannot do it with Maven but it seems intricate, not natural, error prone and not good designed.
Here's some ideas to solve it with Maven.
You could configure the maven-jar-plugin to specify the class to exclude in the packaged jar :
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.0.2</version>
<configuration>
<excludes>
<exclude>a.b.c.MyclassToExclude.java</exclude>
</excludes>
</configuration>
</plugin>
Here is the reference documentation.
But by doing it, the class will not be available in the JAR in any case.
It makes the B JAR not working alone if the class to replace is required in B.
You could package the JAR with a specific classifier to avoid this problem.
You would have so the classic jar that contains everything and the jar-for-a that contains everything but this famous duplicate class.
But really, I think that you should really think about your design.
First off, I'm a long time user (and beneficiary) of StackOverflow, but this is my first question. I've done plenty of searching on this topic, but most of the articles I've turned up talk about generating JAR files, not working with 3rd party JARs from the Maven Central repo which I don't really have the power to fix. The few solutions I've seen floating around aren't really acceptable.
The problem is that most of the jaxb JARs found in the Maven Central repository contain classpath entries (in the MANIFEST.MF file) that point to dependencies, and those dependencies are specified with relative paths -- typically assuming that dependency bar.jar exists in the same directory as foo.jar.
This is fine if you have all your JAR dependencies in a single lib directory, for example. But:
Maven wants to maintain its own local repository, so every single packaged JAR lives in its own directory (with each version in a separate subdirectory).
Maven JARs are typically named with the version info embedded in the filename, whereas the classpath entry in MANIFEST.MF specifies the dependency with just the base filename (no version).
The net result is an error message like this:
[ERROR] bad path element
"C:\Users\rpoole\.m2\repository\com\sun\xml\bind\jaxb-impl\2.2.11\jaxb-core.jar":
no such file or directory
One solution is to write a script or small app to go through all the JARs and strip out the classpath info from the embedded MANIFEST.MF file. But that is not very clean, and requires an extra step before doing the actual build.
Another potential solution is that some newer published versions of the JARs in question have supposedly fixed this classpath problem, so therefore use the latest and greatest. Unfortunately, this app I'm working on is legacy, and is being developed for a 3rd party, so I can't update the dependencies beyond a certain version. So far, all the jaxb JARs that I have poked into seem to have issues.
Is there a way to tell Maven to ignore the embedded classpath in the JAR and only rely on Maven's own dependency resolution? I've tried things like reordering dependencies, but that doesn't work (or moves the build problem from one subproject to another).
One additional annoyance: There is a "blessed" Maven repo we have that seems to let the build complete with no problem, but so far I've been unable to figure out why this particular set of JARs builds OK. I suspect someone may have gone in and tweaked some JARs or POMs manually, but there's scant information, and diff tools aren't really helping much.
Regardless, the project should build from scratch.
What would be nice is if I could specify something like an exclusion block in the pom.xml for the subproject that's breaking, but for dealing with a JAR's embedded classpath instead of Maven's own transitive dependencies (specified by groupId/artifactId).
Edit: Apparently, some people believe that this is impossible, and that Maven ignores the Class-Path entry in Manifest.MF. However, this is a known issue, as discussed in this StackOverflow article. There's also another good article which explains some of the history of this a bit better.
The problem is that I can't go through the JARs and edit the MANIFEST.MF files on each as part of the build process. That's just not a practical approach, even if automated by script. I need a solution that actually will work for code that is already in production. These issues were supposedly fixed in later versions of the JARs in question, but I may not be able to use newer versions of those.
Additionally, one of the proposed fixes is to add -Xlint:-path to the compiler args, which suppresses the error message. However, the build simply fails at another point for me, so at first blush this does not appear to be a good solution either. I'll be trying this again because according to this, the syntax for compiler arguments inside POM files is a bit wonky.
I hate answering my own question, but I finally did manage to get past this problem. For those who keep insisting that Maven builds can't possibly be affected by the Class-Path entry in a jar's MANIFEST.MF, please read this article by Michael Bayne. It summarizes the problem and the solution rather nicely. Hint: javac certainly does care about the embedded classpath in jars.
The trick is to add -Xlint:-path to the compiler arguments, although I was dubious of this solution initially. Doing this will suppress the bad path element warnings/errors, and therefore Maven won't prematurely halt the build. The problem I had was figuring out the correct syntax for embedding these arguments in the pom.xml. That's where this article comes in handy. Therefore, the compiler plugin's configuration has to look like this to be understood properly:
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${java-version}</source>
<target>${java-version}</target>
<compilerArguments>
<Xlint/>
<Xlint:-path/>
</compilerArguments>
<showWarnings>true</showWarnings>
<showDeprecation>true</showDeprecation>
</configuration>
</plugin>
</plugins>
Note that this syntax is not very good XML (as Bayne points out), and most IDEs will flag the second Xlint line as an error, but it will work with Maven. Using the syntax given in some Maven tutorials may result in the arguments not being passed to the compiler at all, or only the last argument being passed.
Once this problem is taken care of, you may discover other build problems (I certainly did), but at least those problems won't be hidden from you any longer.
The problem is that you are referencing a post which is seven years old..and don't use more recent versions of the maven-compiler-plugin:
The arguments to the javac compiler can better done like this:
<project>
[...]
<build>
[...]
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.6.1</version>
<configuration>
<compilerArgs>
<arg>-Xlint</arg>
<arg>-Xlint:-path</arg>
</compilerArgs>
</configuration>
</plugin>
</plugins>
[...]
</build>
[...]
</project>
What are pros and cons of configuring Maven plugins through properties as oppose to configuration?
For example, maven-compiler-plugin documentation explicitly shows configuring source and target as
shown below, presumably going even further with pluginManagement.
https://maven.apache.org/plugins/maven-compiler-plugin/examples/set-compiler-source-and-target.html
<project>
[...]
<build>
[...]
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
<configuration>
<source>1.4</source>
<target>1.4</target>
</configuration>
</plugin>
</plugins>
[...]
</build>
[...]
</project>
Wouldn't it be more succinct to use user properties instead, with no dependency on specific version?
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
First of all, many parameters of many goals do not have any associated user property, so can only be set via <configuration>.
For those which do have a user property (such as these examples), it depends. A few user properties are specifically coördinated between multiple goals or even plugins, as #khmarbaise points out.
User properties can be overridden from the command line, as #kdoteu points out, which is useful in certain cases—though very likely not for Java source/target level which would normally be intrinsic to the project (something you would change in a versioned commit alongside source file changes). User properties can also be overridden from external profiles such as in settings.xml, which is occasionally important.
On the other hand, plugin configuration is more explicit: it is expressly associated with a particular goal (or all goals in a plugin using the same parameter name). Some IDEs can offer code completion. You need not worry about accidentally having some other unrelated plugin interpret a property name (though plugin authors try to use unique-looking prefixes for most user property names). Surprisingly, Maven (3.8.1) will not fail the build if you mistype the parameter name, however—it will just quietly ignore the extra element.
You can influence the properties druing build time with commandline parameters. And you can use them in multimodule projects.
So wie are using them to configure findbugs or some urls for deploying.
There are some properties which are automatically taken by plugins. One for example are the given target/source information. An other is the project.build.sourceEncoding which is taken into account of several plugins like maven-compiler-plugin, maven-resources-plugin etc. So it makes sense to use properties which reduces the size and number of your configurations for plugins.
I'm wanting to use the slf4j-gwt library https://github.com/FinamTrade/slf4j-gwt
But I only want to include it in my gwt compile, not in the war that is built as I'm having issues with tomcat startup calling GWT.create...
Is there a simple way to do this? I would expect the maven gwt compiler plugin to support this but I can't see that it does.
<scope>provided</scope> or <optional>true</optional>.
Neither one is semantically satisfying but that's what Maven gives us.
That being said, there are many reasons why you should rather split your project into several modules, with one module containing only client-side code and producing JavaScript and associated resources (through the GWT compiler) and one with only server-side dependencies; that way you never risk putting client-side classes or dependencies into your WAR.
See http://blog.ltgt.net/announcing-gwt-maven-archetypes-project/ for more about it, and sample projects (in the form of Maven archetypes).
If I understand you correctly, you could exclude the artifact when building the WAR. Something like
<build>
...
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>2.5</version>
...
<configuration>
<packagingExcludes>
WEB-INF/lib/slf4j-gwt-*.jar
</packagingExcludes>
</configuration>
</plugin>
...
</build>
should work.
Cheers,
I've been a long time user of the Make build system, but I have decided to begin learning the Maven build system. While I've read through most of the online docs, none seem to give me the analogies I'm looking for. I understand the system's lifecycle, but I have not see one reference to compile step dependencies. For example, I want to generate a JFlex grammar as part of the compile lifecycle step. Currently, I see no way of making that step a pre-compile phase step. Documentation seems to be limited on this. In general, the concept of step dependencies seem to be baked into Maven and require a plugin for any alteration. Is this the case? What am I missing, because currently the Maven build system seems very limited in how you can setup compilation steps.
You can do anything in Maven. It generally has a default way to do each thing, and then you can hook in and override if you want to do something special. Sometimes it takes a lot of Stack Overflowing and head scratching to figure it out.
There is even an official JFlex Maven plugin.
Whenever possible, find someone who has made a Maven plugin do what you want. Even if it isn't 100% right, it may at least give you an idea on how to make maven do something.
Minimal configuration
This configuration generates java code of a parser for all grammar files (.jflex , *.jlex , *.lex , .flex ) found in src/main/jflex/ and its sub-directories. The name and package of the generated Java source code are the ones defined in the grammar. The generated Java source code is placed in target/generated-source/jflex , in sub-directories following the Java convention on package names.
pom.xml
<project>
<!-- ... -->
<build>
<plugins>
<plugin>
<groupId>de.jflex</groupId>
<artifactId>jflex-maven-plugin</artifactId>
<version>1.6.0</version>
<executions>
<execution>
<goals>
<goal>generate</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
<!-- ... -->
</build>
<!-- ... -->
</project>
This feels like the maven way to do things. Put your stuff in the right folders (src/main/flex), and this plugin will automatically build it into your project. If you want to do fancier custom stuff, there are some options. but Maven is all about favoring convention over configuration.
To be frank I think that your current mindset maps much better to ant than to maven, and I would suggest starting with that.