How can I handle split packages in automatic modules? - maven

I am currently testing to migrate an existing application to Jigsaw Modules. One of my modules uses ElasticSearch along with its Groovy Plugin.
org.elasticsearch:elasticsearch
org.elasticsearch.module:lang-groovy
Unfortunately, they share a split package, so mvn install gives me:
x reads package org.elasticsearch.script.groovy from both lang.groovy and elasticsearch
once for each required module in the descriptor, where x is the name of each module.
I assume that a newer elasticsearch version will have eliminated the split package by the time Java 9 is final, but is there generally a way to handle split packages in legacy dependencies?
I was hoping to be able to have those on the the classpath instead of the module path, but after reading this conversation on the mailing list it seems that there is no way to tell the Maven compiler to do so.
maven 3.3.9 -
maven-compiler-plugin 3.6.0 -
jdk9-ea+149 -
elasticsearch 2.3.3

After some more testing, I think there are a few options which should tackle many (but definitely not all) 3rd party split package situations.
Clean up dependencies - maybe a dependency isn't actually needed or can be replaced by a newer (or more distinct) JAR
Restructure your own module into two modules, each reading the package from one of both 3rd party modules (if possible/reasonable)
wrap one of the 3rd party modules (or both) in a simple module, which does nothing but explicitly export only the package(s) that are actually needed by your module.
Depending on the situation, one of these options might be a good fit to resolve the split package problem. But none of them can handle situations in which a coherent piece of code actually needs to access classes from both parts of the split package.

Related

Best practices for external benchmarks when using Go Modules

I have a Go repository, and within it I have some benchmarks (in a _test suffixed package). These benchmarks compare it to, among other things, some third party libraries. I am not using these libraries in my non-benchmark code.
I am now migrating my repo to go modules. I do not want those third party libraries in my go.mod since my library doesn't need them for normal usage, and I don't want to tie my module to those unnecessarily.
What is the recommended go-mod way to do this? My ideas:
build tag on the benchmarks
benchmarks to another repo
module within my module
If someone wants to run your benchmark (for example, to check whether its stated results hold for their machine configuration), then they need to know what versions of dependencies those benchmarks were originally run with. The information needed to reproduce your test and benchmark results belongs in your go.mod file.
But note that “having a minimum version” is not the same as “importing”.
If a user builds your package but does not build and run its test, or if they build some other package within your module, then they will not need to download the source code for the benchmark dependency even if that dependency is included in your go.mod file.
(And the proposal in https://golang.org/issue/36460 doubles-down on that property: if implemented, that proposal would avoid loading dependencies of packages that are never imported, potentially pruning out large chunks of the dependency graph.)
So if you really don't want users to have to build the dependencies of your benchmark, put the benchmark in a separate package from the one that you expect your users to import.

JHipster Spring Boot modularization split package

I am trying to modularize a JHipster 5 (Spring Boot 2) application and I ran into a split package problem.
In module-info.java I have the following conflicting automatic modules:
requires problem.spring.web;
requires problem;
requires jackson.datatype.problem;
When I build the project with Maven, I get several errors due to conflicting package name org.zalando.problem like this:
error: the unnamed module reads package org.zalando.problem from both problem and jackson.datatype.problem
error: module problem.spring.web reads package org.zalando.problem from both jackson.datatype.problem and problem
I would like to know how can I solve this issue. Would I have to wait for the third party library to be modularized too? What would be a nice way to solve this conflict?
This article explains a bit on how to solve Split Packages problems. I applied it to solve the split package between jsr305 and java.xml.ws.annotation by using --patch-module argument when building, as explained here. However the project did not compile when I tried the same for these packages.
The source for this project is available on GitHub
If you want to use JARs that split a package as modules, --patch-module is the only way, but it's an arduous one. Beyond patching, you also need to craft the rest of the module graph. Say you're patching module megacorp with the content of start.up, then:
you have to make megacorp read all of start.up's dependencies with --add-reads
you have to make all modules that use start.up read megacorp with --add-reads
you have to ensure that start.up is not on the module path
This can be quite complicated, particularly if you're fighting Maven along the way. Are you sure, there is no way to simply merge the two artifacts?
If not, I'd say this project might not be ready for modularization.

How can I instruct a build to use their dependency version if they have one, else use the one in my artifact

I am creating a Java library in Maven that has a dependency on a third party library.
In case any consumer applications already use that third party library, I want their build to use theirs. However in case they don't already have it, I want them to use the one I packaged in my archive.
Is there a Maven way to have your cake and eat it too, so that I can tell consumer applications to use theirs if they have one, else use mine?
When multiple versions of an artifact are found maven will attempt to select the version. It uses the nearest definition from the dependency tree.
https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html
http://techidiocy.com/maven-dependency-version-conflict-problem-and-resolution/
This means that if the project consuming your library specifies a different version that will be used. If the common dependency is specified by a transitive dependency the version closest to the root of the tree will be used.
You can also use version ranges to specify many versions that work for you library.
https://docs.oracle.com/middleware/1212/core/MAVEN/maven_version.htm#MAVEN402

Install 3rd Party Libraries with Transitive Dependencies / Dependency Tree? Automated?

I have encountered similar problem as stated in following question: Install 3rd Party Libraries with Transitive Dependencies / Dependency Tree?
I will quote most important part from it below:
I know mvn install:install-file does install a single JAR. But how
to install locally in the repsoitory something like this:
+ Parent.jar
+ ChildA.jar (Requuired by Parent)
+ ChildB.jar (Required by Child A)
To make it more complcated and real life: Parent.jar and ChildA.jar
are legacy/commercial Jars not available in the public maven
Repository but the Child B is a jar that is found in the public
repository (for example like a logging jar).
UPDATE: I do not only want to install them locally (with a system
dependency) but to also "correctly" integregrate them with maven so i
can redistribute this dependency tree to other developers or the
public (and I assume this is important for maven), so that maven knows
and understands the dependecytree (to avoid version conflicts,
unnecessary downloads etc...)
I have similar case jars are legacy and commercial I will deploy them to internal company repository.
Solution is simple which I figured before finding a question, to write pom for every jar and import them using syntax mvn install:install-file -Dfile=<path-to-file> -DpomFile=<path-to-pomfile>. But in my case there is over 200 jars with more than 10.000 class files in total. That's why I was wondering wether there is software which could provide me with easy parse-able and/or process-able output telling which jars depend on which. Otherwise it could take insane amount of time do it manually. Open every jar, decompile every class, find which classes it referenced, are they from other jars (which?) or not.
I think this should be possible to automate since classloaders do something similar. If it need to load a certain class it have to load class that are used by this certain class, so there is a way to know which classes are referenced. And you can tell which classes belongs to which archives.
I'm also aware that I might not be not able to import them because of some circular dependencies between classes from different jars. I'm fine with that if software says - NO if it's not possible. That's actually another reason why I don't want to do it manually and acknowledge after 2 weeks that I just waste my time.
So any idea if such software exists?

Make sure bundles use same dependencies versions

I am looking for a way to ensure that all the features I deploy in Karaf require dependencies that are of the same version. The project is composed of more than 40 bundles which makes it difficult to verify manually.
I am thinking of developping a Maven plug-in that would make the check, but before I would like to be sure that such a solution do not exist yet.
If you want to be sure you use the same versions then create a parent project and define versions of dependencies only there. So you can be sure all your modules have the same dependencies. Of course this only makes sense if all these modules are very closely related (e.g. belong to the same application / release unit).
Why would you even want to do this? Each bundle should depend on the versions of the package it needs, and that dependency should be a range. So if you compile against and API package version 1.0.0, and you are a consumer of that API, then you should import with the range [1.0.0, 2.0.0). Refer to the OSGi Core Release 5 specification, section 3.7.3 ("Semantic Versioning") for details.
At runtime the OSGi Framework will ensure that your bundle is wired to a package version that is within its permitted range. Obviously if you have non-overlapping version ranges from different importers then the Framework will not be able to satisfy them with a single exporter.

Resources