I have troubles with importing classes from an existing Spring-Boot application into my new application after they changed the structure of the build jar file.
They changed the jar-file so that the applications own classes now are located in BOOT-INF/classes and not on the root of the jar-file.
But when I have a normal maven dependency to this Spring-boot application I can not import the existing classes from this application and into my new classes in my new application.
It worked just fine before they changed the structure...
The solution here is to refactor your code, so that the classes you're depending on in both your applications are available in a separate project.
Now you can use these classes by importing the dependency in both your projects:
<dependency>
<groupId>org.example</groupId>
<artifactId>example-shared</artifactId>
</dependency>
Make sure that you're not using the Spring boot maven plugin in this newly made shared project and you should probably not use any Spring boot starters either, since they load a lot of dependencies you may not need.
I found out that it is actually possible to use a Spring Boot application as a dependency. Even though it most likely is not recommended. But in some cases it just makes it easier.
This solution means that you can not use the executable archive.
"The executable archive cannot be used as a dependency as the executable jar format packages application classes in BOOT-INF/classes. This means that they cannot be found when the executable jar is used as a dependency."
The solution to my question is to include a configuration classifier to the spring-boot-maven-plugin. Like this for Maven:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<classifier>exec</classifier>
</configuration>
</plugin>
or like this for Gradle:
bootRepackage {
classifier = 'exec'
}
Related
I tried to compile and obfuscate 2 projects where the one depends on the other one and both are built with the Spring boot maven plugin.
Let's call them for the sake of simplicity main and util projects.
The build has two stages. In the first stage the util project is built. In the second stage the main project which depends on the util project.
My problem is that Spring boot maven plugin creates nested jars. (https://docs.spring.io/spring-boot/docs/current/reference/html/executable-jar.html)
So if I try first repackage the projects with Spring boot maven plugin and after that obfuscate the repackaged jar which contains both the util and the main projects, then first proguard extracts the repackaged jar's content where the extracted content will contain the util jar. Then proguard won't obfuscate the content of this util jar because it is a jar and not a set of class files.
If I try first obfuscate the util project with proguard and after that repackaging with Spring boot maven plugin then the obfuscation will be done but when I try to compile the main project then it won't find the necessary symbols in the jar produced from the util project.
So how to obfuscate projects repackaged with Spring boot maven project?
In your main module declare proguard-maven-plugin and spring-boot-maven-plugin (proguard package phase must be executed before spring boot plugin repackage goal). Declare it only in module which is entry point - no need to declare it in submodules or parent pom.
Then, in your proguard plugin config add modules which you would like to obfuscate besides main jar:
<configuration>
<assembly>
<inclusions>
<inclusion>
<groupId>com.yourgroupid</groupId>
<artifactId>submodule</artifactId>
</inclusion>
</inclusions>
</assembly>
...
And in spring-boot-maven-plugin add exclusion, so spring not overwrites already obfuscated jar:
<configuration>
<mainClass>
com.yourapp.App
</mainClass>
<excludeGroupIds>com.yourgroupid</excludeGroupIds>
</configuration>
Hope that it will work for you!
I've built a Java/Kotlin hybrid lib using kotlin-maven-plugin (v 1.2.21). The lib is actually a Spring Boot app (v 1.5.9)
Now, when I declare it as a dependency in another project I face strange issues :
- My IDE (Intellij) is able to find the classes I need : auto-completion proposes me the classes, and I have no error
- But when I try to build my application, I get compilation errors, saying the packages (and therefore the class) I am trying to import don't exist.
When I expand the jar in the IDE, I can see that the classes exist in the expected package, under a BOOT-INF/classes directory.
So I am a bit confused... is there a specific config to put in kotlin-maven-plugin , so that the generated jar can be used by others ?
Thanks
OK, so actually, it had nothing to do with Kotlin, but everything with Spring Boot...
Because of the change of structure in Spring Boot after 1.4.0 version as explained here, it's now required to add this config if you want to be able to import the jar
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<classifier>exec</classifier>
</configuration>
</plugin>
I have a Maven java web app (.WAR) project that includes several libraries, including the Wicket libraries (but I don't think the problem is wicket itself, but rather with maven).
Here's the problem: even tho I only include Wicket 6.20.0, the resulting .WAR contains two copies of the Wicket libraries: 6.20.0 and 6.18.0, as you can see in this screenshot:
Thinking of some conflicting imports I printed the dependency tree using the:
mvn dependency:tree
commnad... but there is no mention of Wicket 6.18.0 in the dependency tree! I also double-checked using Eclipse's "dependency hierarchy" view and I can confirm there's no trace of that import.
I even did a search for string "6.18.0" across the entire workspace with Eclipse, but it's nowhere to be found!
How can I find out what is causing the inclusion of that duplicate version of the library?
Maven doesn't work in this way.
The resolution of more than one dependency with the same artifactId and groupId but with a different version will result to a single dependency (the version used is no determinist).
The presence of two artifacts with the same artifactId and groupId but with two distinct versions in a same lib folder of the WAR is probably related to one of these :
you don't execute mvn clean package but only mvn package.
your use a bugged version of the Maven war plugin. Try to update it to check that.
you have a Maven plugin that copies Wicket jars 6.18.0 in the WEB-INF/lib folder of the target folder during the build of the component.
the maven WAR project you are building has as dependency an artifact of type WAR. In this case, the dependencies of the WAR dependency are so overlaid in the WAR project that you are building.
An interesting Maven issue about duplicated JAR because of WAR dependencies :
JARs with different versions can be in WEB-INF/lib with war as dependencies
Your answer and your comment indicate that actually you have a WAR dependency in your build.
Unfortunately, there is not really a good and long term effective solution to bypass this limitation.
As said in my comment, using the packagingExcludes property of the maven war plugin is a valid workaround for the actual issue :
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.4</version>
<configuration>
<!-- ... -->
<packagingExcludes>WEB-INF/lib/wicket-*-6.18.0.jar</packagingExcludes>
</configuration>
</plugin>
But beware, using that will do your build less robust through the time.
The day where you update the version of the WAR dependency and that in its new version, it pulls again a different version of wicket, you have still a risk to have duplicate jars with two distinct versions in your built WAR.
Using the overlay feature by specifying the overlay element of the maven-war-plugin is generally better as it focuses on the overlay applied for the war dependency. It fixes the problem early.
As a result, you could define to exclude any wicket JARs from the WAR dependency :
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<version>2.4</version>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<overlays>
<overlay>
<groupId>com.whatever.youlike</groupId>
<artifactId>myArtifact</artifactId>
<excludes>
<exclude>WEB-INF/lib/wicket-*.jar</exclude>
</excludes>
</overlay>
</overlays>
</configuration>
</plugin>
This way is better but this is still a workaround.
The day where the dependency WAR is updated and that it pulls new dependencies (other than Wicket) that are declared in your actual build but with different versions, you may finish with the same kind of issue.
I think that declaring a dependency on a WAR artifact should be done only as we don't have choice.
As poms and projects refactoring are possible, introducing a common JAR dependency which the two WARs depend on and that contains only common sources and resources for the two WARs makes really things simpler.
Well, I figured it out while poking around.
I had a dependency of type "war" in the project:
<dependency>
<groupId>com.whatever.youlike</groupId>
<artifactId>myArtifact</artifactId>
<version>1.0.7-SNAPSHOT</version>
<type>war</type>
</dependency>
Apparently (I wasn't aware of this, my fault here) these type of dependencies will include themselves in the classpath by copying all libs to the main WAR /libs folder, but these will NOT show app in the dependency tree / dependency hierarchy.
I solved by configuring an explicit exclusion in the WAR plugin:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.4</version>
<configuration>
<!-- ... -->
<packagingExcludes>WEB-INF/lib/wicket-*-6.18.0.jar</packagingExcludes>
</configuration>
</plugin>
Use clean install and the double dependency will probably be gone.
Because other libs can use same libs but different version or you tried different version and didn't make mvn clean
The command mvn dependency:tree is telling you the correct information - what you are looking at here is an eclipse / build issue.
Clear out all the target and build areas in your project. If need be, check it out from source control to a new folder.
Alternatively you can build your project in IntelliJ IDEA, and see if you get the correct dependencies (most likely you will).
I want to accomplish what I think these directions describe.
I want to use an external, maven-based project from a rcp platform application.
I've used the new Project wizard to build a new maven-based application that include a maven-based module. I've added my external dependencies to the maven-based module.
I've also added the publicPackages section to my module's pom.
When I right-click on the module and go to ProjectProperties->PublicPackages I can see the correct packages listed with check marks.
My maven module builds just fine.
However, when I try to add the maven-module as a dependency of another module the packages listed in PublicPackages are not found.
If I peek inside the nbm I can see the jars I wanted exposed are under netbeans\modules\ext
Is there some way to build a maven-module that wraps another maven project?
The nbm-maven-plugin docs include an example which sounds alot like what I want to do:
Public packages declaration
By default all your module's packages (and classes) and private to the given module. If you want to expose any API to other modules, you will need to declare those public packages in your pom.xml. This includes not only your own classes but also any other 3rd party library classes that are packaged with your module and are to be exposed for reuse by other modules.
For example:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>nbm-maven-plugin</artifactId>
<version>3.8.1</version>
<extensions>true</extensions>
<configuration>
<publicPackages>
<publicPackage>org.foo.api</publicPackage>
<publicPackage>org.apache.commons.*</publicPackage>
</publicPackages>
</configuration>
</plugin>
there is a package org.foo.api made public (but not org.foo.api.impl package) and any package starting with org.apache.commons, so both org.apache.commons.io and org.apache.commons.exec packages are exposed to the outside
I am clearly not interpreting those doc correctly because this behavior is not what I'm seeing.
I have a war dependency:
<dependency>
<groupId>my.package</groupId>
<artifactId>myservices</artifactId>
<version>0.3</version>
<type>war</type>
</dependency>
Now, this exists in my local repository, and the class exists at WEB-INF/classes/my/package/myservices. When I go to use myservices, however, I get package my.package does not exist. Intelli-J knows to change myservices into my.package.myservices, but trying to import seems to not work at all.
Is there something special I need to do with this war dependency?
As pointed out in the other answers:
In Maven, you cannot just load classes from a WAR artifact the way you can from a JAR artifact.
Therefore, the recommendation is to split off a separate Maven JAR project with the classes you want to reuse, and depend on this project in both the original WAR and the new project.
However, if for some reason you cannot / do not want to split the WAR project, you can also tell Maven that you need a JAR artifact in addition to the WAR. Put this into the POM of your WAR project:
<build>
...
<plugins>
...
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>2.3</version>
<configuration>
<attachClasses>true</attachClasses>
</configuration>
</plugin>
</plugins>
</build>
Then, when building the WAR project Maven will create a WAR and a JAR from it.
Source: Maven War plugin FAQ
Adapted from doc_180's comment, so it does not get overlooked.
It just doesn't work that way. war files are not supposed to be put on the classpath, but deployed to application servers (or servlet containers) that can deal with their special structure.
Of course you can probably find a custom classloader somewhere that can deal with java war files, but it's just not the way to do it.
Keep your code in a jar, include the jar in your war and in this application. But don't use a war as a dependency, unless you are building an EAR file.
WAR dependencies are handled VERY differently by Maven from JAR dependencies. They are treated as overlays.
http://maven.apache.org/plugins/maven-war-plugin/overlays.html
I think what you are looking for is something a bit different from a WAR overlay. WAR overlays merge the file structures with a "closest wins" model, but that means that things like web.xml are replaced by closest wins, not merged.
If you want merging (which is closer to what most people think of when they start talking about WAR dependencies) you should look at the Cargo uberwar plugin.
http://cargo.codehaus.org/Merging+WAR+files
If your goal is simply to share some classes between two WARs, you should probably just put those classes into a JAR project. Maven in particular is really designed to work on a pom.xml -> a single artifact model (JAR/WAR/etc). Trying to take a single pom.xml and have it emit, say, a JAR for some stuff and a WAR for other stuff is going to be very painful.
Incidentally, if you are working on a team larger than one person, you are going to want an artifact management server pretty fast (e.g. Artifactory, Nexus or Archiva) or you will go crazy dealing with this stuff. ;)
In a WAR, the classes must be located at WEB-INF/classes/... not at classes/....
Anyway I never have tried to reference other classes from a WAR (not JAR), and I do not know if this is possible.
Make sure the dependency is installed in your local repository.
The local repo should look like:
.m2/my/package/myservices/0.3/myservices-0.3.war
If this is not the case, then install the war into the local repository before using it in the dependency:
mvn install:install-file -Dfile="[path-to-war]" -DgroupId=my.package -DartifactId=myservices -Dversion=0.3 -Dpackaging=war -DcreateChecksum=true -DgeneratePom=true