Clean jar conflicts - java

In our project I want to remove all the potential jar conflicts that might arise during runtime. Our stack is so big, we have same jar brought in by different dependencies. Here is the problem, each dependency is bringing in different version of the same jar and causing issues, after fresh deployment.
Where do I start from ? Are there any maven plugins to resolve this ?
Any help or pointers on this is much appricieated.

You can use the maven-enforcer-plugin as follows:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId>
<version>1.3.1</version>
<configuration>
<fail>true</fail>
<rules>
<dependencyConvergence/>
</rules>
</configuration>
<executions>
<execution>
<id>enforce-dependencies</id>
<goals>
<goal>enforce</goal>
</goals>
</execution>
</executions>
</plugin>
This will stop the build when there are conflicting dependencies.

A handy tool: JHades. In a nutshell, it is a tool that helps with Jar dependency Hell. In itself, it is a Jar with no dependencies, except for the JDK. It can be used to spot easy conflicts and to debug more severe issues. Example:
new JHades()
.printClassLoaders()
.printClasspath()
.overlappingJarsReport()
.multipleClassVersionsReport()
.findClassByName("org.jhades.SomeServiceImpl")
Prints the class loader chain, jars, duplicate classes, ...

Related

Shade all dependencies of another dependency (hibernate) into jar

I'd like to automatically shade all the dependencies of Hibernate core into my main jar, without defining them explicitly (As this just seems to become a goose chase).
I can't just shade everything into my jar, as other dependencies are not needed and it would make my jar unnecessarily huge.
Is it possible to get maven to automatically shade all of the dependencies of one of your top-level dependencies?
You can set the scope of the dependencies you don't want shaded to 'provided' and that'll flag to maven that the library is provided/assumed available at runtime.
The rest of your dependencies, which either don't a specified scope or have the 'compile' scope, should be those that your jar needs to have shaded.
Then just use something similar to this in your pom:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.3</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
The Shade plugin supports selective inclusion, exclusion, filtering and minimization of a jar. This should do the trick.

How can I get a maven build to fail on duplicate dependencies?

If I have two dependencies which are the same in the same pom, I want the build to fail. Currently I can detect it happening with the Maven Dependency Plugin's "analyze-duplicate". However, there's no option to failOnWarning like some of the others (plus, it prints at Info level, not Warning). Is there an alternative to extending this?
Generally, when you want the build to fail for some reason, the good plugin to look into the Maven Enforcer Plugin. This plugin can be configured with a set of rules that, when verified, will fail the build.
In this case, it would need to be a rule that checks for duplicate dependencies, and there is a built-in rule just for that: <banDuplicatePomDependencyVersions>. As such, you could have
<plugin>
<artifactId>maven-enforcer-plugin</artifactId>
<version>1.4.1</version>
<executions>
<execution>
<id>enforce-no-duplicate-dependencies</id>
<goals>
<goal>enforce</goal>
</goals>
<configuration>
<rules>
<banDuplicatePomDependencyVersions/>
</rules>
</configuration>
</execution>
</executions>
</plugin>
This rule is unfortunately not documented (yet, it will be in the next version, see MENFORCER-259), but it exists since version 1.3 of the plugin (MENFORCER-152).
What this rule does is checking that there are no 2 duplicate declaration with the same 'dependencies.dependency.(groupId:artifactId:type:classifier)'; which is to say that two declared dependencies with the same group id and artifact id declared in the POM will have to have a different type and/or classifier.

appassembler-maven-plugin add custom entry to classpath

I'm writing a Java-Application which is using some libaries from anonther thirdparty-Application which is running on my server. At the moment im building my App with the appassembler-maven-plugin. This plugin copy my jars (app and dependencies) into the lib folder an generates a shellscript in the bin dir.
The classpath is generated in this shellscirpt. This solution works but i dublicate the dependency-jars (on time in my app and in the thirdparty-Application write the app for). The classpath of my thirdparty-application is set in a systemvariable like $THIRDPARTYAPP_CLASSPATH.
I want to set the dependencies in my pom.xml to provided, so that the appassembler don't add them to lib and classpath and want to add the systemvar $THIRDPARTYAPP_CLASSPATH in my shellscript, so that my app uses the jars from the installed thirdparty-application.
At the moment i'm doing this manually (editing the shellscript after the build) and it works. Is there any method in the appassembler-maven-plugin to add thid systemvar to the classpath automatically?
I couldn't find anything in the documentation and other questions here regarding a similar problem are not well answerd.
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>appassembler-maven-plugin</artifactId>
<version>1.8.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>assemble</goal>
</goals>
</execution>
</executions>
<configuration>
<assembleDirectory>${project.build.directory}/appassembler</assembleDirectory>
<extraJvmArguments>-Xms512m -Xmx1024m</extraJvmArguments>
<generateRepository>true</generateRepository>
<repositoryName>lib</repositoryName>
<repositoryLayout>flat</repositoryLayout>
<includeConfigurationDirectoryInClasspath>true</includeConfigurationDirectoryInClasspath>
<platforms>
<platform>unix</platform>
</platforms>
<programs>
<program>
<mainClass>${mainClass}</mainClass>
<id>app</id>
</program>
</programs>
</configuration>
</plugin>
You can configure to create an <environmentSetupFileName>setup-env</environmentSetupFileName> which can define a new classpath part via CLASSPATH_PREFIX which should solve your problem.

Why do I get a not exposed to the weaver warnings when making my Spring project?

I seem to get a bunch of warnings like this when I make my Spring project. The project uses Compile Time Weaving and various Spring annotations like Transactional, Autowired, and Configurable.
I have three questions: What are they (What's the effect)? Should I be concerned about them? and "What can I do to remove them?"
ajc: this affected type is not exposed to the weaver: com.myapp.domain.UserEntity [Xlint:typeNotExposedToWeaver]
Let me know what you need to help me solve this issue. I can post relevant parts of the POM file, parts of my Java Spring Configuration files, or whatever. I dont' really know what is required so let me know.
I saw it on the spring forum but that place is a ghost town. Several people have asked this question but there are no answers.
I am using Java Configuration for Spring and CTW.
What are they (What's the effect)?
It (ajc) is saying that it has found some class that it thinks ought to be or to have been "woven", but that can't be done / hasn't been done.
Should I be concerned about them?
Yes. It would mean that the AspectJ compile time weaving won't happen properly; i.e. the annotations on some classes won't take effect.
What can I do to remove them?
Change your build configs so that the weaver can find all of the code it needs to weave.
I'm guessing that your application involves multiple Maven modules. If so, then this Answer has some links to the relevant Eclipse/AspectJ and Maven documentation: https://stackoverflow.com/a/13120709/139985. It seems that the AspectJ Maven plugin needs to be explicitly told where to look for stuff.
I had a similar problem. On closer inspection, I realized that the warnings were happening during the test-compile phase only, where aspectj was not smart enough to automatically look in the main java source directory as well as in the test source directory. I solved it by splitting the two goals into separate executions, with different configurations. The relevant part of the POM is given below:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.10</version>
<configuration>
<complianceLevel>1.8</complianceLevel>
<aspectLibraries>
<aspectLibrary>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</aspectLibrary>
</aspectLibraries>
<source>1.8</source>
<target>1.8</target>
</configuration>
<executions>
<execution>
<id>compile</id>
<goals>
<goal>compile</goal>
</goals>
</execution>
<!-- add explicit instructions for test compile or it can't weave main src classes -->
<execution>
<id>test-compile</id>
<configuration>
<goals>
<goal>test-compile</goal>
<sources>
<basedir>${project.basedir}</basedir>
<includes>
<include>src/main/java/**/*.java</include>
<include>src/test/java/**/*.java</include>
</includes>
</sources>
</goals>
</configuration>
</execution>
</executions>
</plugin>

Managing JAXB-generated classes in a Maven project

I have a Maven-based project, in which I trying to add some JAXB classes automatically generated by the "jaxb2-maven-plugin" Maven plugin. However, my first cut has me in a circular dependency loop:
Because these JAXB classes aren't generated yet, my other sources which reference them have compilation errors.
Because those other sources have compilation errors, these JAXB classes don't get generated.
It seems like there are two obvious possibilities for solving this:
Comment-out the broken references, so that the project builds and the JAXB classes are automatically generated. Then copy those generated sources from /target into /src/main/java, so that references to them won't cause compilation errors.
Create an entirely separate project, consisting of nothing but the JAXB stuff. Include it as a dependency in my main project.
Am I missing something here? Option #1 seems flat-out ridiculous... that just can't be the manner in which people use JAXB. Option #2 seems more rational, but still rather inefficient and cumbersome. I really have to take on the overhead of an entirely separate project just to use JAXB?
Are there any more elegant approaches that developers use to reference JAXB-generated classes in the same project where the Maven plugin generates them?
UPDATE: By request, here is the relevant portion of my POM:
<build>
<plugins>
<plugin>
<!-- configure the compiler to compile to Java 1.6 -->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>jaxb2-maven-plugin</artifactId>
<version>1.4</version>
<executions>
<execution>
<phase>generate-sources</phase>
<goals>
<goal>xjc</goal>
</goals>
</execution>
</executions>
<configuration>
<!-- The name of your generated source package -->
<packageName>com.mypackage</packageName>
</configuration>
</plugin>
</plugins>
</build>
When I run mvn clean package, I DO see my JAXB sources being generated beneath the /target subdirectory. However, those generated sources are not being automatically added to the classpath for the compile phase.
POST-RESOLUTION UPDATE: It turns out that my compilation issues had more to do with the fact that I was running in Eclipse, and its Maven integration has some issues with "jaxb2-maven-plugin". See this StackOverflow question for more detail on that issue and its resolution.
How did you configure your jaxb maven plugin? Normally it runs in the generate-sources lifecycle, which comes before the compile lifecycle. So your JAXB generated classes should already be there when your own code gets compiled, Maven puts them in target/generated-source and puts that folder on the classpath.
Edit:
This is my code we use at work (and which works as expected):
<plugin>
<groupId>com.sun.tools.xjc.maven2</groupId>
<artifactId>maven-jaxb-plugin</artifactId>
<executions>
<execution>
<phase>generate-sources</phase>
<goals>
<goal>generate</goal>
</goals>
</execution>
</executions>
<configuration>
<schemaDirectory>src/main/resources/<companyname>/xsd</schemaDirectory>
<includeSchemas>
<includeSchema>retrieval.xsd</includeSchema>
<includeSchema>storage.xsd</includeSchema>
</includeSchemas>
</configuration>
</plugin>
Apparently we use yet another jaxb plugin... (see also this thread: Difference of Maven JAXB plugins).
i would suggest you to split jaxb-generated classes (api) and your BL classes (implementation) to 2 maven projects with separate pom.xml for each, and the main root pom.xml with the compilation order. that way, you will be able to build api.jar, then maven will install it inside the local repo, and after that you can use it as the dependency of your implementation. so it will looks like:
-API\
--pom.xml - for api, jaxb generation
-IMPL\
--pom.xml - for impl, api dependency is here
pom.xml - main pom.xml with references to the projects above
Maybe try using the maven-jaxb2-plugin instead:
<plugin>
<groupId>org.jvnet.jaxb2.maven2</groupId>
<artifactId>maven-jaxb2-plugin</artifactId>
<version>0.8.2</version>
<executions>
<execution>
<goals>
<goal>generate</goal>
</goals>
</execution>
</executions>
</plugin>
The answer from dfuse is correct, though. Either plugin should generate sources before compiling, and the result of the source generation will be on the classpath. I tested this with both plugins. Is it possible for you to post your schema, or at least the schema for the type that your code is failing to pick up on the classpath?

Categories