I have a maven multimodule project that has one parent pom-project and a bunch modules. One of these modules is the "main module" that has all the libraries shaded into it. All other modules depend on that module and use the provided libraries.
The main module is a Bukkit plugin that loads the other modules as extensions. These extensions are loaded all with their own classloader, but the loaded classes are shared between the loaders to be able to depend on each other. They are also able to depend on other Bukkit plugins, as their parent classloader is Bukkit's PluginClassLoader that also shares the loaded classes between plugins to allow interaction.
That's where the problems start: Different plugins may use the same library, but the classes of that library might get loaded by different classloaders which causes LinkageErrors and other problems.
My idea to solve that problem was to relocate the libraries in the main module via maven-shade-plugin. That works as expected with libraries that are only used by the main module. However relocating libraries used by the other modules causes runtime ClassNotFoundExceptions, because the modules still search for the normal package name instead of the relocated one.
Then I tried to change the imports to the relocated packages, but my IDE (IntelliJ) doesn't find the classes.
Has anyone an idea on how to solve this relocation problem? Or maybe different approaches on the classloading issue?
5 years later in a very similar context (Bukkit -> SpongeApi) I encountered this problem again, but this time I found the (probably only satisfying) solution:
The main module had its shaded version as the main artifact, so dependents could only see relocated classes and were unaware of the original classnames. This made no difference in our case, as the main module is a provided dependency anyway, but it also prevents consumers from accidentally using relocated classes directly. IntelliJ does not care for the relocations, so it was unaware of the new relocated classes. Attaching the shaded version as a secondary artifact (shadedArtifactAttached option set to true) makes the dependencies visible to the dependents again.
The dependent modules have to apply the same relocation rule as the main module, so the plugin corrects the classnames to the ones available at runtime.
This way IntelliJ is not aware of the relocations but it also doesn't need to be aware. If necessary, the relocations can be configured in a parent pom for consistant rules across all projects.
I had almost exactly the same problem you have/had (judging from the age of this question). Although I don't have a cleaner solution for the libraries overriding other plugins' versions, I do have a workaround for IntelliJ not recognizing relocated classes.
To stop it from complaining, I added the shaded jar (with the relocations) as IntelliJ library to the target module.
You can do this like so:
Go to File > Project Structure... > Modules > (target module) > Dependencies
Select the shaded jar using Add (green +) > 1. Jars or directories....
You should now see the shaded jar in the libaries list
Although it seems to work at first glance, this solution workaround has a few caveats:
Non-relocated classes are still visible to code through Maven's module dependency and if you happen to use them, you'll only see that upon compiling with Maven. (You could remove the module dependency, but it gets readded every time you reimport your pom)
You'd have to update the jar path every time you change your project's version if you include a version number in your jar file name (Workaround: Specify a static project.build.finalName)
When you add new methods or change signatures, you need to compile the library module again. (This can be worked around by creating a separate module for shading dependencies - That would actually also resolve the file name issue)
Related
I've got this dependency in my pom.xml
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext7-core</artifactId>
<version>7.1.18</version>
<type>pom</type>
</dependency>
And in my module-info.java file I have the following
requires transitive kernel;
which produces the following warning, "Name of automatic module 'kernel' is unstable, it is derived from the module's file name."
What can I do to get rid of this warning?
I tried changing it to
requires transitive com.itextpdf.kernel;
but then I get the following error, "com.itextpdf.kernel cannot be resolved to a module"
I tried a bunch of other similar lines of code but nothing worked. What can I change the code to in order to remove the error/warning?
itext7 currently isn't modular.
You can contact the developers and ask them to make it modular.
In the meantime, complex, non-modular systems like this are difficult to use from a modular project. Even if you get that to work via the automatic module system or hacking in module info via something like moditect, it pretty much destroys any potential benefit of the project being modular, and it runs the software in a way it was never designed to work.
So, make your project non-modular:
remove the module-info.java from your project.
source the javafx modules using either:
VM arguments pointing adding them to the module path OR
from a JRE/JDK distribution that includes them, e.g. BellSoft Liberica "Full JDK" or Azul Zulu "JDK FX".
For further instructions on working with non-modular JavaFX projects, see the getting started documentation at: openjfx.io.
I am not sure what "not modular" means but how can that be true if the itext7 website gives maven dependencies to incorporate into your pom.xml?
Non-modular means that you don't define a module-info.java in your project.
Read understanding modules and the documentation I linked at openjfx.io to understand the basics of the JavaFX module system and how it can be used in a JavaFX application.
Maven modules and Java Platform modules are different things, they have the same name "module" but one is a build-time definition and the other is a runtime definition. Also, a maven dependency is just a dependency, it is not a Maven module or a Java Platform module. Though you can depend on artifacts built by a maven module and you can execute those artifacts through the Java Platform module system (if they are compatible with it).
itext7 is not built as a Java Platform module. The software has no module-info.java and it does not define an automatic module name for itself either. Given that your software is depending on non-modular software, your software should not be modular either (in my opinion).
My project inherits it's compile dependencies from parent and I have no control over it - can't change them to provided. Additionally, I have added another dependency 'a:b:1.0.0' to my project's pom. I want to include only 'a:b:1.0.0' with it's own dependencies (recursively ) to my uber jar.
Seems like neither assembly nor shade plugin doesn't support such case.
How this could be done ?
Thanks
Shading recursively has some significant disadvantages. Especially, the problem of duplicate files from multiple dependencies being overwritten with only a single version of the file. This can cause some pretty annoying problems to troubleshoot at runtime. You'd be better off using something like spring boot to build a standalone jar where instead of shading files into a single hierarchy, will embed dependent libraries into itself as a subdirectory and include on the classpath for you.
http://docs.spring.io/spring-boot/docs/current/maven-plugin/repackage-mojo.html
I am in my project reusing an open source maven-based component that includes a bunch of shaded (e.g, using the maven-shade plugin) direct and transitive dependencies in the component uber-jar. Unfortunately some of those dependencies clash with dependencies that my own project has. Specifically, the component's dependencies transitively include servlet-api 2.x whereas I need 3.x in my project - and they appear to be in the same namespace. The component's top-level dependency that pulls in servlet-api (lucene-demo) is actually not needed for the functionality of the component, so I'd be happy to remove it if possible. My project is built with Gradle.
What is the recommended way of dealing with this type of situation? Is there any way of removing the offending dependencies from the reused uber-jar when I build my own project? Or should I rebuild the reused component myself, excluding the troublesome dependency? If so, can this be done in an automatic manner, such that I don't need to maintain my own fork of the open source component? The component is presently hosted in GitHub and published via Maven Central.
(As you might understand, I'm a bit of a beginner to both Maven and Gradle, so don't worry about dumbing things down).
I've searched for hours but no artifactId and version information for "libopencv_java.so" and "libnative_camera_r2.2.2.so".. I know how to add dependency into pom.xml to be included in lib/armeabi in .apk, but I just cannot find the correct information.. The pox.xml keeps complaining
"Missing artifact org.opencv:libnative_camera_r2.2.2:so:2.2.2
Missing artifact org.opencv:libopencv_java:so:1.0"
Thank you so much~!!
These are native non-Java libraries. They aren't normally handled by Maven. If you would like to use static objects in your module, I suggest you have something like ${basedir}/lib and place your static libraries in there. Add the directory as a <resource/> as well and have it included in you jar. I think it should be possible to load the .so from within the jar. This is one option.
Another option would be, (if you really, really must re-use the .so-s across modules), to extract them to a separate module and have your module depend on that one.
Either way, you'll need to do quite a bit of magic, which isn't covered by Maven by default.
I have an Intellij Project with several Java modules, including different branches of the same projects, such that a particular class may be defined in more than one IntelliJ module. When I debug one of the modules (using for instance Maven Jetty plugin) IntelliJ will open source files from other modules (apparently the first one from its index).
Is it possible to restrict the source lookup context or classpath to the current module?
You should specify the correct module in the Run/Debug configuration, IDEA will use classpath of this module for debugging. However, if multiple copies of a same class are present in this module via its dependencies, there is nothing you can do except re-configuring your project so that one module doesn't have multiple class copies in its dependencies.