Netbeans: Allow external build participant during Maven project loading (Maven Tiles) - java

In the process of migrating dozens of individual Maven projects to use Maven Tiles, I've hit a challenge in the Netbeans IDE 12.0 -- with all common definitions, like the maven-compiler-plugin including the desired JDK version (11), being centralised in reusable tiles.
The pom.xml looks like this:
<?xml version="1.0"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>my.example</groupId>
<artifactId>failing-project</artifactId>
<version>1.0-SNAPSHOT</version>
<name>failing-project</name>
<build>
<plugins>
<plugin>
<groupId>io.repaint.maven</groupId>
<artifactId>tiles-maven-plugin</artifactId>
<version>2.23</version>
<extensions>true</extensions>
<configuration>
<tiles>
<tile>my.example.maven-tile:jar-tile:1.0</tile>
</tiles>
</configuration>
</plugin>
</plugins>
</build>
</project>
Running the mvn clean build command directly works fine, and starts out as expected with something like this:
--- tiles-maven-plugin: Injecting 3 tiles as intermediary parent artifacts for my.example:failing-project...
Mixed 'my.example:failing-project:1.0-SNAPSHOT' with tile 'my.example.maven-tile:jar-tile:1.0' as its new parent.
Mixed 'my.example.maven-tile:jar-tile:1.0' with tile 'my.example.maven-tile:build-tile:1.0' as its new parent.
Mixed 'my.example.maven-tile:build-tile:1.0' with tile 'my.example.maven-tile:nexus-tile:1.0' as its new parent.
Mixed 'my.example.maven-tile:nexus-tile:1.0' with original parent '(no parent)' as its new top level parent.
The rest of the build is then behaving as before, like all the common definitions are part of my project's pom.xml.
Unfortunately, Netbeans indicates "Project Problems". Selecting the "Resolve Project Problems" option, brings up a dialog with the following entry:
Custom build participant(s) found
The IDE will not execute any 3rd party extension code during Maven project loading.
These can have significant influence on performance of the Maven model (re)loading or interfere with IDE's own codebase. On the other hand the model loaded can be incomplete without their participation. In this project we have discovered the following external build participants:
io.repaint.maven.tiles.TilesMavenLifecycleParticipant
In the absence of an explicit maven-compiler-plugin configuration, Netbeans has to pick some JDK version and choses poorly (JDK 5). That results in all "newer" constructs (e.g. every single lambda expression) to be highlighted as compilation error, making the IDE pretty much unusable.
lambda expressions are not supported in -source 5
(use -source 8 or higher to enable lambda expressions)
Other IDEs do not appear to have such limitations, but I'd rather find a solution for Netbeans to not force all developers who are used to it, to change.
This challenge was already identified in the Maven Tiles project, but no solution was presented until it got closed with the comment "closing as no one cares about netbeans anymore.", which I disagree with.
https://github.com/repaint-io/maven-tiles/issues/10
Question is: Is there a way to do one of the following things?
Allow such an "external build participant" to be included in the Maven project loading.
Globally enforce a default maven-compiler-plugin <source> and <target> (and I don't mean the build environment via something like <netbeans.hint.jdkPlatform>JDK_11</netbeans.hint.jdkPlatform>).
Suppress the automatic Maven project loading and rather rely on the explicit "Build" action to be triggered, while still highlighting the actual errors in my code.
EDIT:
Via right-click on the project, one can go to "Properties" > "Sources" > "Source/Binary Format" and select "11" there, which solves the false negatives on the compilation errors but only by inserting the following properties into my pom.xml, which I wanted to avoid, since that may contradict my Tile definition and is unnecessary for other IDEs:
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>

Related

How is default Maven plugin version decided?

I wonder when I did not specify a plugin version in some module's pom.xml like in:
<build>
...
<plugin>
<groudId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
</plugin>
...
</build>
What is the default plugin version used when I run "mvn compile"?
I have tried it and see actually it is using maven-compiler-plugin version 3.1 with above plugin element commented, my Maven version is 3.6.3.
I have spent 1 hour to google through Maven's documentation and related posts, but not find exact answer. I really like to know how that version is being decided?
The magic is not happening in the super pom, but in the so called bindings descriptor as available at https://github.com/apache/maven/blob/master/maven-core/src/main/resources/META-INF/plexus/default-bindings.xml.
However, they are moving to the matching packaging plugin, for example for the maven-jar-plugin it is located at https://github.com/apache/maven-jar-plugin/blob/master/src/main/filtered-resources/META-INF/plexus/components.xml
These versions haven't been updated, because it would be weird if 2 users with different Maven versions have different results (e.g. one has a broken build, the other not). Hence it is better to specify the plugin versions in the pom, don't rely of the defaults provided by Maven.
In the end it is all described at https://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html
It is impossible for maven to work without defining versions of the
artifacts , so somewhere it must be mentioned, lets dig in part by
part.
All pom.xmls are logically inherit from the super POM. You can always see what your "real" pom.xml looks like by typing:
mvn help:effective-pom
The resulting pom.xml that is printed is a combination of the super POM, your pom.xml, and any parent POMs in the mix as well.
Note from Maven 3 the super POM does not contain any of the (default lifecycle) plugins versions but earlier till Maven 2 it used to have.
The Maven 3 super POM is provided by the org.apache.maven.model.superpom.DefaultSuperPomProvider class https://github.com/apache/maven/blob/bce33aa2662a51d18cb00347cf2fb174dc195fb1/maven-model-builder/src/main/java/org/apache/maven/model/superpom/DefaultSuperPomProvider.java#L56-L85
The resource it loads can be found here: https://github.com/apache/maven/blob/bce33aa2662a51d18cb00347cf2fb174dc195fb1/maven-model-builder/src/main/resources/org/apache/maven/model/pom-4.0.0.xml#L23-L149
Edit:
As per Maven Coordinates
groupId:artifactId:version are all required fields (although,
groupId and version need not be explicitly defined if they are
inherited from a parent - more on inheritance later). The three fields
act much like an address and timestamp in one. This marks a specific
place in a repository, acting like a coordinate system for Maven
projects:
version: This is the last piece of the naming puzzle. groupId:artifactId denotes a single project but they cannot delineate which incarnation of that project we are talking about. Do we want the junit:junit of 2018 (version 4.12), or of 2007 (version 3.8.2)? In short: code changes, those changes should be versioned, and this element keeps those versions in line. It is also used within an artifact's repository to separate versions from each other. my-project version 1.0 files live in the directory structure $M2_REPO/org/codehaus/mojo/my-project/1.0.

How to avoid Java dependency hell when using Maven multi-module projects

I have been battling dependencies on a Java Maven multi-module project for a couple of days.
With too little oversight developers managed to create a situation where modules each can be compiled on their own but not as a single whole together. This results in all kinds of errors. Classes that cannot be found, casting errors etc etc. The cause of these problems seems impossible to determine.
My suspicion is that Maven puts conflicting dependencies on the class path. I think we made a mess of the Maven dependencies but regardless I don't understand how Maven can be such a poor performing framework for multi-module projects.
Now I can understand that Maven tries to do very smart useful things when compiling multiple modules as a whole but shouldn't there be an option in Maven to just configure a module to be isolated from other modules? Is there such an option? To avoid this dependency hell?
Or is the Maven best practice to create other scripts, bash scripts for example to be able to compile multiple modules in isolation, with one command?
But that is also poort workaround some tools for example SonarQube require ability to run Maven on the whole code base in order to create a single project in SonarQube.
This results in all kinds of errors. Classes that cannot be found, casting errors etc etc. The cause of these problems seems impossible to determine.
Could you post the error messages? it would make analyzing your issues easier. This may be caused by dependency conflicts, but it is hard to say without more information.
Now I can understand that Maven tries to do very smart useful things when compiling multiple modules as a whole but shouldn't there be an option in Maven to just configure a module to be isolated from other modules? Is there such an option? To avoid this dependency hell?
I do not get this. If two modules do not depend on each other, their builds will be independent. If one module depends on another module and its build fails because of version conflicts, this build will fail regardless of whether it is built together with the other modules or in isolation.
Or is the Maven best practice to create other scripts, bash scripts for example to be able to compile multiple modules in isolation, with one command?
Maven follows the philosophy "convention over configuration", meaning the more you follow the convention, the less configuration you will have and the less maintenance work. Creating all kinds of scripts goes against this philosophy and is not Maven's best practice.
To manage dependency conflicts in a multi module project, you would typically have a parent module with a pom.xml that looks like
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>...</groupId>
<artifactId>...</artifactId>
<version>...</version>
<packaging>pom</packaging>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-web-api</artifactId>
<version>6.0</version>
<scope>provided</scope>
</dependency>
...
</dependencies>
</dependencyManagement>
<modules>
...
</modules>
</project>
In the dependendencyManagement element you define the version of libraries used. This way you force each module to use the same version of libraries.
For Maven, I often recommend the Java EE NetBeans IDE, because among other things it has a good visualisation tool for dependencies, which is useful in detecting and removing version conflicts. (I am not aware of a similar tool in Eclipse or IntelliJ). If you open a Maven project in NetBeans, click on the pom.xml (in the Projects window) and then select Graph > Show Graph.
I use this tool for 2 things:
remove the transitive dependencies in Maven, otherwise you have to manage more dependencies than required. To remove transitive dependencies, right click in the graph and select the Hierarchical layout. Every dependency that is not on the first line is a transitive dependency and can be removed from the pom.xml.
identifying conflicts between transitive dependencies. (Conflicts are coloured red in the graph.) I resolve these conflicts by explicitly setting the version for the dependencies in the dependencyManagement element in the root pom.xml

Update version of Maven modules in one place only

I have a Maven project with 2 modules. I want the modules to inherit the version of that project, without defining it as a parent in the POM file of any submodules (the reason behind that is that the modules already have parents). What would be the best way to achieve that?
Importing the version from a properties file doesn't work because maven expects a constant value as a project version, not an expression. Maven plugins such as the version maven plugin or the maven release plugin are not solutions to my problem because I need something that would work in an IDE (I have to use Eclipse for packaging the projects, not my call).
Edit
To clarify things (apologies if my original post was not clear enough)
Main Project POM file
...
<groupId>org.mygroup</groupId>
<artifactId>parentproject</artifactId>
<version>1.1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<modules>
<module>module1</module>
<module>module2</module>
</modules>
...
Module POM file example
...
<groupId>org.mygroup</groupId>
<artifactId>module1</artifactId>
<version>1.1.0-SNAPSHOT</version>
<packaging>war</packaging>
<parent>
<!-- Some parent that's NOT the main project, e.g. Spring Boot -->
</parent>
...
What I want is a solution that would allow me to set the version only ONCE (e.g. in the main project POM file) and having every module of that project to "inherit" that version.
You should probably set the parent back to your actual parent project. Version numbers between modules can be simultanuously updated using mvn versions:set. If you need the version number for cross-module dependencies, use ${project.version}. If you want to embed another Maven configuration file for its dependencies, consider using a Bill-of-material (BOM): https://stackoverflow.com/a/14876651 . Hope things brings you to your answer!
I really can't think of any Maven facility that fit 100% your necessities. Event if you could set the parentproject as an actual parent on each submodule, you'd need to specify its version in the parent declaration, so...
But I think of a trick to do the job through an authomatism, so that every time the parent version is changed, it will be automatically propagated to each submodule. It can be done like this:
Program a plugin in the parent project that writes the version id on each of its modules' pom files (for example, through an XSL transformation with the xml-maven-plugin).
Then, link this plugin to the package phase, so that every time the parent is build, the versions gets propagated to the submodules.
You only will have to refresh the submodules projects in Eclipse to make Eclipse be aware of the changes.
But if you don't want to refresh manually, there is still another alternative - fully based on Eclipse:
Make an Ant script to perform the copy-version-to-all-module-poms task. And, instead of calling it from a Maven phase, program an Eclipse builder to call it and, within this builder, program also a refresh of the specific modules. So, every time you execute a build of your project, it will copy its version to the submodules and make Eclipse be aware of this change.

#Override is not allowed when implementing interface method

I have the problem mentioned in the title. You could say that this thread duplicates another one: How do I turn off error validation for annotations in IntelliJ IDEA?
But the solution given there doesn't work. They say that I need to take the following action:
In the Project Structure | Project dialog, change the Project language Level to 6.0 - #Override in interfaces.
However, the Project language Level is 6.0 at the moment, but I still see the error.
Vic, here is the window and there is no JVM version right under Language level (unfortunately I can't post images because I have 10 reputation)
If your project has multiple modules, also check that every module uses language level 6 or above, or use the project's language level (see Project Settings > Modules > xxx > Language level).
You may need to reload your project once it is modified.
At your module/project, Right click to see context menu:
Choose Open Module Settings or press F4. In setting windows:
Set value for Choose Language level section.
You also should check Project language level by this way: press Ctrl+Alt+Shift+S
A simpler solution - inline
Put the caret on the #Override word and move the caret on the left side until the red bulb icon will appear. Then click on it.
Click on Set language level to 6 - Override in interfaces
The method above is an alternative to the following approach:
Go to File > Project Structure... or press Ctrl+Alt+Shift+S
Go to Project Settings > Modules > Sources > Language level and choose any level that is 6 or greater than 6.
If you are using maven, add maven compiler plugin to the project's pom.xml file.
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
</plugins>
</build>
This solved the issue for me.
There's also a language level for every module. Please check your module settings in the Project Structure.
I ran into this problem for the first time while using a multi module maven project. As other answers / IDE suggested, we need to set the language level.
Rather than changing the setting of IDE, to make the project IDE agnostic, I update the parent pom with below properties, which solved the issue.
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
In JIdea 2020.1.2 and above,
Go to Project Structure [ Ctrl+Alt+Shift+S
]
Select Modules sub section
Select each module
Under sources-section, check Language Level
Change the Language Level as required
NOTE:
If you get below error after this change,
Error:java: Compilation failed: internal java compiler error
You have to change the target bytecode version as well.
Go to Settings [ Ctrl+Alt+S
]
Select Java Compiler
Select module in the table
Change the byte-code version to map what you selected in the previous step for language-level

Get started with maven

I have experience in Ant, how to get started with maven. Any advantage with maven over ant?
There's a quite large difference, where ant forces you to create your own targets you will get a default set of targets for maven, e.g., clean, install, package etc without scripting them.
Maven promotes that you use a common directory structure for java classes, resources etc. If you do, maven is just on xml file where you specify some project metadata such as name, package and most importantly depenencies. It provides similar dependency lookup to what ivy does for ant.
Based on the standard maven promotes, it becomes very easy for developers to approach and build your projects. With an IDE such as Netbeans it's enough to select open project, and then hit the install button to compile and install the project in your local repository.
I recommend working with maven the maven way. Doing things differently will often cause more pain than it's worth. Maven offers a plugin structure where you can perform various tasks, such as invoke the ant-library should you need to. If you're actively working with multiple projects (and want project switching to be as easy as possible) maven is a huge leap forward, especially if combined with repository server such as Nexus or Archiva.
To get started
Either you can generate your project structure using the archetype goal of maven, or you could do it the way I do by copy-pasing an empty template project every time. Then you need the maven binary and the project definition file pom.xml which I typically also copy paste between projects.
A sample is included below. With this sample you'll get the external library log4j, and you automatically get all nececcities to build and package your own project (in this case to a jar file).
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.company</groupId>
<artifactId>projectname</artifactId>
<packaging>jar</packaging>
<version>0.1.0-SNAPSHOT</version>
<name>${project.artifactId}</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.16</version>
</dependency>
<!-- add more dependencies here ... -->
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
Around two weeks ago, I was in the same situation. In my opinion, Maven is a lot more powerful as compared to Ant.
It has a generate command which makes it very easy to start new projects of various kinds (artifacts) and will also build a standard directory structure along with the pom.xml file,
thereby taking care of a lot of things that are needed to be written in the build.xml file of Ant.
Managing dependencies is also a lot better. Maven will download dependencies from repos and will store them in a central repo on your system. If a dependency is already present in the local repository, it will take it from there instead of downloading it again.
I use eclipse and maven has a command (mvn eclipse:eclipse) which creates the .classpath file in the project directory. So no need to add the libraries again in eclipse.
The Getting started guide on the maven website is a good resource and covers quite a lot of stuff -
In comparison to Ant what Maven does well is dependency management and standardisation of the build lifecycle.
As for learning a bit more about it, the Maven documentation is pretty readable and thorough.
I'd start by looking at the introductory piece that explains some of the core principles about the difference between Maven and other build tools.
http://maven.apache.org/what-is-maven.html
Then downlod and install maven, open your terminal and type...
mvn archetype:generate
Select all defaults and you'll end up with a simple build-able project with one runnable class and a matching test file. Use that as a test project to familiarise yourself with the build lifecycle and dependency resolution process.

Categories

Resources