Should lombok have a provided scope in spring-boot-dependencies? - spring-boot

Based on the Project Lombok documentation the lombok dependency should be a provided scope (https://projectlombok.org/setup/maven). Should that scope be defined within the <dependencyManagement> of the spring-boot-dependencies pom.xml?

The spring-boot-dependencies pom.xml is just a description of libraries versions that work well together. They are defined in dependencyManagement.
If you have a Spring Boot application and you want to use lombok, you have to explicitly say that in a 'dependency' section in your project pom, but you can exclude the version as this is already defined in spring-boot-dependencies. And you can also declare that the dependency is 'provided' or better yet 'optional'.
<scope>provided</scope> means that the library is needed for compilation and
test classpath, however it is provided by some sort of container
<optional>true</optional> means that a library is needed for compilation, but it is not necessary at runtime
Edit: it seems that Spring Boot maven plugin always packages your dependencies, even if you declare them as optional or provided, at least when you package your app as a jar, I didn't test this with a war.
The reason is that a jar contains an embedded servlet container and Spring Boot packaging needs to provide this container with the provided libraries, makes sense! (thank you #Peter Wippermann).
I guess the conclusion is that it doesn't really matter if you provide a scope for lombok when packaging a jar with Spring Boot maven plugin, as the library will always get packaged, unless you want to use the scope for semantic reasons...
For lombok not be included in the package you just need to configure the Spring Boot maven plugin with the exclusion configuration.
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>

Related

How to prevent lombok from being packaged into Spring Boot jar?

If you visit official Lombok Maven guide, you will see that it's scope should be provided.
When I create a new project from scratch using start.spring.io and add Lombok, it gets only <optional>true</optional> in resulting pom.
Then I package Spring boot app like this and out of curiosity decide to see what gets packaged inside of jar:
mvn clean package -DskipTests=true && unzip target/demo-0.0.1-SNAPSHOT.jar -d exploded
Lombok is packaged, does not matter if I set scope to provided or only have optional=true.
How to prevent Lombok from being included to Spring Boot jar?
My last thought was to try another goal which comes with Spring Boot plugin:
mvn spring-boot:repackage
But unfortunately it produces the following error:
repackage failed: Source file must be provided
Lombok will only be available in a seperate folder lib-provided instead of the usual lib folder if you are packaging war file.
In order to exclude lombok completely from the final jar/war file, you have to do this:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.3.1.RELEASE</version>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
Please refer to Exclude a dependancy section of Spring Boot Maven Plugin https://docs.spring.io/spring-boot/docs/2.3.x/maven-plugin/reference/html/#repackage-example-exclude-dependency for more details.
Looks like it's a transitive dependency of one of your dependency. If you confirm it, you know what to do.

How create JAR from upstream Web App as Dependency for downstream Web App

I have (amongst other modules) a NetBeans8.1 Maven web app project CoreWeb that (with other module dependencies resolved) runs standalone fine, and is supposed to under any circumstances at least build its default WAR and run standalone.
I have a 2nd NetBeans8.1 Maven web app project SpecWeb that depends on CoreWeb; it is to reuse both JSF managed beans from CoreWeb and also leverage XHTML composite component JSF resources from CoreWeb.
But on building SpecWeb it does not resolve the CoreWeb dependency, because CoreWeb does not (by default) also build a JAR:
Failed to execute goal on project SpecWeb: Could not resolve dependencies
for project com.example.multi:SpecWeb:war:1.0-SNAPSHOT: Could not find
artifact com.example.multi:CoreWeb:jar:1.0-SNAPSHOT -> [Help 1]
(I had this problem with an Ant version of my project with multiple modules and solved it using a small piece of Ant task script to build the extra JAR from CoreWeb for use in SpecWeb, worked perfectly.)
Q: How can I generate a JAR (as well as the WAR) from CoreWeb for use in SpecWeb ?
Under Project > Actions: Build Project I've tried adding various additional goals to install for the Build Project action (using the NetBeans prompting feature).
Using install jar:jar did not work. It indeed created a JAR (as well as the WAR), but that JAR only included the managed bean classes, not the resources, and on build from the "downstream" SpecWeb it still failed to find it:
$ jar tf target/CoreWeb-1.0-SNAPSHOT.jar
META-INF/
META-INF/MANIFEST.MF
com/
com/example/
com/example/multi/
.. Java managed bean classes ..
META-INF/maven/
META-INF/maven/com.example.multi/
META-INF/maven/com.example.multi/CoreWeb/
META-INF/maven/com.example.multi/CoreWeb/pom.xml
META-INF/maven/com.example.multi/CoreWeb/pom.properties
I get the same JAR structure built (without JSF XHTML composite component web resources) if I manually change the packaging in the pom.xml to jar:
<groupId>com.example.multi</groupId>
<artifactId>CoreWeb</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<!--
<packaging>war</packaging>
-->
EDIT: Overlays also not working (in NetBeans)
I have also tried using Overlays, but it's not working as expected. As soon
as I turn the dependency into type war NetBeans can't resolve classes from CoreWeb imported into classes from SpecWeb, and it won't even compile (and the class files have NetBeans Java warnings because of the failed import):
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>CoreWeb</artifactId>
<version>${project.version}</version>
<type>war</type>
</dependency>
Also, as soon I enter <type>war</type> the CoreWeb project vanishes from the list under the project navigator node SpecWeb > Dependencies.
Also tried Warpath plugin
NetBeans still does not see classes in CoreWeb imported into classes in SpecWeb, so SpecWeb won't compile.
After lot of research (mostly on the main Maven site) and trial and error, I have found a robust solution compatible with NetBeans.
A general description of the strategy. The trick is to create an additional "client" JAR version of the CoreWeb project for temporary use by the SpecWeb project (enabling NetBeans editor to "see" the classes of CoreWeb), and declare it as an additional dependency of only 'provided' scope (so it does not make it into the final SpecWeb WAR). Then also use overlays to combine both the composite components of CoreWeb and the managed beans of CoreWeb with the SpecWeb project into the final WAR, being careful to exclude the index.xhtml from CoreWeb.
Steps
In the pom.xml from CoreWeb include this:
<!-- Also make JAR form using classifier during package phase -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.0.2</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>jar</goal>
</goals>
<configuration>
<classifier>client</classifier>
</configuration>
</execution>
</executions>
</plugin>
On build this will create:
$ ls -1 CoreWeb/target/CoreW*
CoreWeb/target/CoreWeb-1.0-SNAPSHOT-client.jar
CoreWeb/target/CoreWeb-1.0-SNAPSHOT.war
CoreWeb/target/CoreWeb-1.0-SNAPSHOT:
META-INF/
WEB-INF/
index.xhtml
resources/
(Note NetBeans can run CoreWeb independently directly over CoreWeb/target/CoreWeb-1.0-SNAPSHOT with its own index.xhtml.)
SpecWeb can then use CoreWeb-1.0-SNAPSHOT-client.jar thus in its pom.xml:
<dependencies>
...
<!-- This is needed for the editor and for the compilation only (not at runtime) -->
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>CoreWeb</artifactId>
<version>${project.version}</version>
<type>jar</type>
<classifier>client</classifier>
<scope>provided</scope> <!-- To prevent being written even to target folder -->
</dependency>
<!-- This is needed for the overlay -->
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>CoreWeb</artifactId>
<version>${project.version}</version>
<type>war</type>
<scope>runtime</scope>
</dependency>
Note how there are 2 separate types of dependency of SpecWeb on CoreWeb:
A dependency on the CoreWeb-1.0-SNAPSHOT-client.jar using the classifier client and with scope runtime (so it won't be included under /target at all). This will appear in the NetBeans project window under a special node Non-Path Dependencies, with a clear indication that it is for [runtime] only.
A dependency on the CoreWeb-1.0-SNAPSHOT.war for the overlay to use. This will appear in the NetBeans project window under the node Dependencies.
Then also in the pom.xml for SpecWeb specify the overlays (excluding the CoreWeb's index.html) and packaging (to be sure also excluding any "client" jars):
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.0.0</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
<packagingExcludes>WEB-INF/lib/*-client.jar</packagingExcludes>
<overlays>
<overlay>
<groupId>${project.groupId}</groupId>
<artifactId>CoreWeb</artifactId>
<excludes>
<exclude>index.xhtml</exclude>
</excludes>
</overlay>
<overlay>
<!-- empty groupId/artifactId represents the current build -->
</overlay>
</overlays>
</configuration>
</plugin>
The SpecWeb project behaves correctly in the NetBeans editor (classes from CoreWeb are seen), compiles ok, and can be run over SpecWeb/target/SpecWeb-1.0-SNAPSHOT with its own index.html, with access to both the JSF managed beans and JSF composite components of CoreWeb.
CAVEAT: NetBeans XHTML editor will complain when editing JSF pages from SpecWeb that the composite components provided by CoreWeb don't exist because of this known NetBeans Bug 257684 - JSF 2 composite components in JAR are not recognized , but the project will still run ok.

Maven Jetty plugin configure repository

We use jetty plugin for local deployment of our application. Recently i added a repository in the pom and added dependencies both in the plugin section and the dependencies section outside as well, when i build the war and deploy it on standalone app server everything works ok, however the same application when i try to run through the jetty application it throws me error for that particular dependency.
Is there any way that we can configure the external repositories to be used by the plugins in order to resolve the dependencies.
Thanks,
- Vaibhav
If I understand your issue right, you can add a dependency to the jetty-maven-plugin itself and have it available to your application. Something like this:
<plugin>
<groupId>org.eclipse.jetty.maven</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>9.3.14.v20161028</version>
<dependencies>
<dependency>
<groupId>foo</groupId>
<artifactId>bar</artifactId>
<version>0.1</version>
</dependency>
</dependencies>
</plugin>

Jetty plugin only maven dependency

I'm developing CXF web services with JDK 7 + Eclipse Juno + Maven 3 and deploying on a WebSphere 7 Application Server.
I've spent hours to fiund the right configuration of dependencies (a complex mix of runtime, system, compile and provided scopes) that the WAS accepts without conflicts, but with this configuration my jetty plug in does not work anymore.
How can I specify a classpath specific only for the Jetty plugin (hopefully a maven configuration)?
AFAIK, the only way to make the jetty plugin working properly regarding all those dependency issues is to specify all dependencies that are <provided> in your webapp as direct dependencies of the jetty plugin (and unfortunately, this brings kind of redundancy):
<plugin>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>9.0.0.v20130308</version>
...
<dependencies>
<!-- put here all your dependencies with scope provided in your webapp -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>3.0</version>
</dependency>
...
</dependencies>
</plugin>

Maven WAR dependency

I am writing a project for acceptance testing and for various reasons this is dependent on another project which is packaged as a WAR. I have managed to unpack the WAR using the maven-dependency-plugin, but I cannot get my project to include the unpacked WEB-INF/lib/*.jar and WEB-INF/classes/* to be included on the classpath so the build fails. Is there a way to include these files into the classpath, or is there a better way of depending on a WAR?
Many thanks.
There's another option since maven-war-plugin 2.1-alpha-2. In your WAR project:
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>2.1.1</version>
<configuration>
<attachClasses>true</attachClasses>
</configuration>
</plugin>
This creates a classes artifact which you can use in the acceptance tests project with:
<dependency>
<groupId>your-group-id</groupId>
<artifactId>your-artifact-id</artifactId>
<version>your-version</version>
<classifier>classes</classifier>
</dependency>
Indeed, by design, Maven doesn't resolve transitive dependencies of a war declared as dependency of a project. There is actually an issue about that, MNG-1991, but it won't be solved in Maven 2.x and I'm not sure that I don't know if overlays allow to workaround this issue. My understanding of the suggested solution is to duplicate the dependencies, for example in a project of type pom.
(EDIT: After some more digging, I found something interesting in this thread that I'm quoting below:
I have been helping out with the development of the AppFuse project over
the last month where we make heavy use of the war overlay feature in the
Maven war plugin. It is a really nifty feature!
To get max power with war overlays I have developed the Warpath plugin
that allows projects to use war artifacts as fully fledged dependencies.
In brief:
1) The contents of the /WEB-INF/classes directory in the war dependency
artifacts can be included in the project's classpath for normal compile,
etc tasks.
2) Transitive dependencies from the war dependency artifacts become
available for use by other plugins, e.g. compile and ear - so no more
having to include all the dependencies when creating skinny wars!
The plugin has now been actively used in the AppFuse project for the
last few months, and I feel it is at a point where it is both usable and
stable.
Would the war plugin team be interested in including the warpath
functionality inside the war plugin? It would seem to be the most
natural place to host it.
So, I don't have any experience with it, but the maven warpath plugin actually looks nice and simple and is available in the central repo. To use it,include the following plugin configuration element in your pom.xml file:
[...]
<build>
<plugins>
<plugin>
<groupId>org.appfuse</groupId>
<artifactId>maven-warpath-plugin</artifactId>
<version>1.0-SNAPSHOT</version>
<extensions>true</extensions>
<executions>
<execution>
<goals>
<goal>add-classes</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
[...]
And add the war dependencies you want included in the classpath as warpath type dependencies:
[...]
<dependencies>
<dependency>
<groupId>org.appfuse</groupId>
<artifactId>appfuse-web</artifactId>
<version>2.0</version>
<type>war</type>
</dependency>
<dependency>
<groupId>org.appfuse</groupId>
<artifactId>appfuse-web</artifactId>
<version>2.0</version>
<type>warpath</type>
</dependency>
</dependencies>
[...]
Both the war and warpath dependency types are needed: the war type is used by the Maven war plugin to do the war overlay, the warpath type is used by the Warpath plugin to determine the correct list of artifacts for inclusion in the project classpath.
I'd give it a try.)
Use overlays. First, your test project need to have also packaging war.
Declare dependency of war project you want to test:
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>your-project-arftifactId</artifactId>
<version>${project.version}</version>
<type>war</type>
<scope>test</scope>
</dependency>
then configure maven-war-plugin overlay:
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<webResources>
<resource>
<directory>${basedir}/src/main/webresources</directory>
<filtering>true</filtering>
</resource>
</webResources>
<overlays>
<overlay/>
<overlay>
<groupId>your.group</groupId>
<artifactId>your-project-artifactId</artifactId>
</overlay>
</overlays>
</configuration>
</plugin>
In the above example in test project I overwrite webresources configuration files (like conxtext etc.).
EDIT: This solution wasn't tested with Maven 3.
Good point, Justin. That got me actually solving my problem, namely: including a war into an assembly AND including all its transitive dependencies.
I could not duplicate the war-dependency as 'jar' as you suggested since the assembly plugin would not find a jar referenced by that groupId/artefactId, but
duplicating the war-dependency as type pom
works!
The war and its transitive dependencies are not included in the assembly.
To exclude the (now also appearing) pom file I had to add an exclude element like this:
<excludes>
<exclude>*:pom</exclude>
</excludes>
into my assembly.xml file.
I think this could also be a workaround for the original question of this thread.
If you list the dependency on the war project as a jar dependency it seems to pickup the required jars/resources. I'm using Maven 2.2 + m2eclipse.

Resources