JHipster Spring Boot modularization split package - maven

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.

Related

NoClassDefFoundError on com.sun.org.apache.xalan.internal.xsltc.trax package in my OSGi maven plugin

I'm trying to parse WSDL files using the EasyWSDL library on my (atlassian) maven plugin project. I keep getting this error when I try to parse the file and it fails when the project tries to reach the TransformerFactoryImpl class from said "xalan" package. The package is located inside the JDK, so it's supposed to be available to runtime, yet for some reason it can't reach it.
I've tried importing the package through
<import-package>com.sun.org.apache.xalan.internal.*,</import-package>
section of the pom.xml, but that gives me the following error:
Unresolved requirements: [[my.plugin.package [304](R 304.0)] osgi.wiring.package; (osgi.wiring.package=com.sun.org.apache.xalan.internal.xsltc.trax)]
Which makes it seem like the other packages of xalan are found, except for the xsltc.trax one.
I've tried creating a bundle extension for OSGi that exports this one package and exposes it to the classpath but due to lack of experience and pretty poor documentation on that matter I can't get that working either. Adding Xalan as a dependency and using <scope>provided</scope> does nothing as well.
I need to find a way to put this specific package on the classpath when the program is running. When I run unit-tests on my implementations they work just fine, so it seems to purely be a runtime classpath problem.
Is there anyone with experience on this matter? I've little experience with OSGi, and my experience with maven isn't huge either. So I'm hoping it's something I did wrong myself instead of this being an impossible problem to solve.

Split package "okhttp3" errors out build if okhttp-urlconnection dependency added

I'm using OkHttp3 to build up a simple connection API for a pure Java app, and I've run into a build problem that seems triggered by the fact that Square uses the same package name for multiple dependency artefacts.
I've seen some previous Q&A that discusses Maven dependencies and messaging from Eclipse, but all of those indicate that a Maven or Gradle build still works even if Eclipse annotates imports with module errors. In this case the Gradle build fails as soon as I simply add a dependency and make no other changes.
The app is a pure Java 11 module build. I'm using a very recent Eclipse with Gradle nature as an IDE, but I don't think this is strictly relevant. I'm using OkHttp3 to turn private endpoints into API, and one of those endpoints requires a CookieJar. Hoping to just use the default implementation, I add 'com.squareup.okhttp3:okhttp-urlconnection:3.14.9' as a dependency in a project that has already pulled in 'com.squareup.okhttp3:okhttp:3.14.9' as a transitive dependency. Both of these technically offer classes using the same package name: "okhttp3".
e.g., all I do is uncomment the dependency line seen in this snippet and save the build.gradle:
dependencies {
implementation ('com.squareup.retrofit2:retrofit:2.9.0')
implementation ('com.squareup.retrofit2:converter-gson:2.9.0')
implementation ('com.squareup.okhttp3:logging-interceptor:3.14.9')
// implementation ('com.squareup.okhttp3:okhttp-urlconnection:3.14.9')
As soon as the project refreshes I get annotations in Eclipse for all "okhttp3" imports:
The package okhttp3 is accessible from more than one module: okhttp3, okhttp3.logging, okhttp3.urlconnection
A clean build results in:
$ ./gradlew clean build
[...]
> Task :compileJava FAILED
error: the unnamed module reads package okhttp3 from both okhttp3.urlconnection and okhttp3
error: module retrofit2.converter.gson reads package okhttp3 from both okhttp3 and okhttp3.urlconnection
error: module retrofit2 reads package okhttp3 from both okhttp3 and okhttp3.urlconnection
error: module org.apache.commons.io reads package okhttp3 from both okhttp3 and okhttp3.urlconnection
error: module httpcore5 reads package okhttp3 from both okhttp3 and okhttp3.urlconnection
[...]
I don't think it matters, but I'm using Gradle wrapper 5.6.4.
All OkHttp3 libraries, as far as I know, have set module info enough to satisfy Java 9+. The module stuff in Eclipse seems satisfied by that. It looks like neither Eclipse or Gradle like the fact that two different dependencies advertise their Java package as "okhttp3". It seems to me that any Gradle or Maven based project using Java 9 or higher will fail with split-package dependencies.
Based on some advice I read elsewhere, I've tried excluding 'com.squareup.okhttp3:okhttp' from all the dependencies that include it transitively and then pull it in separately, but this did not help (not that I thought it would, but I'm trying any hail-mary at this point).
Workarounds include hacks like simply dropping the two Kotlin classes I want into the project directly and renaming the package that way. This is an egregious hack, and is probably contrary to the library license. I can also implement the cookie stuff I need directly, but I'm lazy (though, apparently, I want to spend my energy solving this problem instead of implementing a cookie class using the interface I already have).
I feel like this is a bug on the part of Square and how they package these libraries/modules. Since their focus is so much on Android maybe I'm the only one who has wanted okhttp-urlconnection on Java 9 or higher? So, this Question is more about seeing if I should raise this as a defect, and also maybe I've overlooked something obvious.
It's OkHttp’s fault and we can fix it for you. Please open a tracking bug with a link to this issue.
We'll move those two classes to a new package. For backwards compatible we'll also need to leave delegating implementations behind. Hopefully the tools permit this!
It's too bad that JPMS has this constraint. We already fixed some of our other open source projects but didn't fix this one.

Gradle library dependency in sub-depending module

Having hard time to describe this and I bet this is something very simple, but I just can't google sollution.
I am using many modules in my project. For simple argument let's say I have modules A and B.
B depends on A.
When I add dependency to external library (using implementation keyword) in module A to use some of it's code in the module, I cannot access library's code in project B. How can I achieve that? I would like A to be my "base" project with all dependencies in that place rather than having to repeat myself in other modules, that depend on it.
The implementation configuration means the dependencies are internal (implementation specific) for the project and should not be exposed on the compilation classpath of other dependent projects. This helps encapsulate dependencies and speeds up the build as you don't need to recompile dependent projects if you only change internal dependencies.
If you want to expose them, you need to use the api configuration instead, along with the java-library plugin.

removing extra jars dependencies from java project

I am working on migrating multi module java project into maven. Now for most of them i migrated to maven.
Finally i am aware my project have lot of unnecessary jars included, and i want to clean them up.
I know maven has plugin command, mvn dependency:analyze. Which works very well.
dependency:analyze analyzes the dependencies of this project and determines which are: used and declared; used and undeclared; unused and declared. based on static code analysis.
Now my question is that, how can i remove reported unused and declared dependency for cleanup purpose. It could be possible those jars were getting used at runtime and my code will compile perfectly fine after removing but blow up at runtime.
An example: mycode compile with one of opensource library antisamy.jar but it require batik.jar at runtime. And mvn dependency:analyze reports me to remove batik.jar.
IS my understanding correct or i need expert inputs here.
Your understanding seems to be correct.
But I'm not sure why you'd think that there is a tool that could cover all the bases.
Yes, if you use stuff by reflection, no tool can reliably detect the fact that you depend on this class or the other.
For example consider this snippet:
String myClassName = "com." + "example." + "SomeClass";
Class.forName(myClassName);
I don't think you can build a tool that can crawl through the code and extract all such references.
I'd use a try-and-fail approach instead, which would consist of:
remove all dependencies that dependency:analyze says are superfluous
whenever you find one that was actually used, you just add it back
This could work well because I expect that the number of dependencies that are actually used by reflection to be extremely small.

How can I handle split packages in automatic modules?

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.

Resources