How can we create a Maven test jar with Java 11 modules?
The only way I found is to add a module-info.java file to test/java and change the module name (e.g. append ".test"). Then provide the class in a separate package (e.g. append ".test") and export that package:
module my.module.test {
requires my.module;
exports my.module.test;
}
Otherwise the classes are not visible or I get split package issues.
But this isn't really the purpose of the test-jar goal and it limits access to "my.module".
What is the proper way to use test-jar with Java 11 modules? Or should it be avoided?
Related
I'm just trying to get the basic Hello World (project Trial0) application running using:
Eclipse Version: 2020-12 (4.18.0)
With SWT 4.18 (Linux, GTK)
with the Java Compiler set to 15
Following the (kinda ancient, it's about JDK 1.4 and SWT 3.1) description in Developing SWT applications using Eclipse, I have imported the SWT project into Eclipse:
Go to https://download.eclipse.org/eclipse/downloads/index.html#Stable_Builds
Click on "4.18" to reach https://download.eclipse.org/eclipse/downloads/drops4/R-4.18-202012021800/
Scroll down until you reach "SWT Binary and Source" and download the zip
swt-4.18-gtk-linux-x86_64.zip.
The zip includes 'swt.jar' (which includes the '.so' files). Launch Eclipse's "File > Import > General > Existing Projects into Workspace", the select the above zip as "Archive File"
I immediately hit a modularization/Jigsaw snag in a project that uses the imported SWT project. The compiler apparently is not allowed to see the SWT classes, which are not modularized:
"The package org.eclipse.swt.widgets is not accessible"
In this code:
package trial;
import org.eclipse.swt.widgets.*; // "The package org.eclipse.swt.widgets is not accessible"
public class MyApp {
}
Here is the project:
Note the module-info.java file on the importing project. It contains:
module trial0 {
requires java.desktop;
}
The swt.jar indeed does not advertise modules:
$ jar --file=swt.jar --describe-module
No module descriptor found. Derived automatic module.
swt automatic
requires java.base mandated
contains org.eclipse.swt
contains org.eclipse.swt.accessibility
contains org.eclipse.swt.awt
contains org.eclipse.swt.browser
contains org.eclipse.swt.custom
contains org.eclipse.swt.dnd
contains org.eclipse.swt.events
contains org.eclipse.swt.graphics
contains org.eclipse.swt.internal
contains org.eclipse.swt.internal.accessibility.gtk
contains org.eclipse.swt.internal.cairo
contains org.eclipse.swt.internal.dnd.gtk
contains org.eclipse.swt.internal.gtk
contains org.eclipse.swt.internal.image
contains org.eclipse.swt.internal.opengl.glx
contains org.eclipse.swt.internal.webkit
contains org.eclipse.swt.layout
contains org.eclipse.swt.opengl
contains org.eclipse.swt.printing
contains org.eclipse.swt.program
contains org.eclipse.swt.widgets
Do I need to add module-info.java files to the SWT jar? Is there another "canonical" way of pulling the SWT jar up into modularization-land?
As you could see based on the output describing the module from the jar file.
In your module-info.java file, you shall add the following directive:
requires swt;
This would provide you the access to the package org.eclipse.swt.widgets which the module swt(automatic module name) claims to
contains org.eclipse.swt.widgets
in its description itself.
The file module-info.java of the importing project now contains:
module trial0 {
requires java.desktop;
requires swt;
}
Eclipse attaches this warning to the line requires swt;:
Name of automatic module 'swt' is unstable, it is derived from the
module's file name.
That's ok.
The above may still not not work. In that case, verify the following:
The project org.eclipse.swt is on the importing project's Modulepath, instead of Classpath:
There needs to be an access rule on the imported module. The following access rules seems to work:
Note that there is nothing specific defined in the "Module Dependencies" for the importing project:
I'm creating a pom.xml for a project that is a library.
Is <main.class> POM XML element under <properties> required for this?
(the library has a small test Main.java which I didn't really intend to include in the library JAR file in the first place, so I'd rather not use that test file as main.class unless required).
Is “main.class” XML element required in Maven's pom.xml if the artefact is a library?
No.
At the most basic level, maven creates jars from projects of a certain structure, it does not care if you have a main class or not. Using mvn clean install:
This command tells Maven to build all the modules, and to install it in the local repository. The local repository is created in your home directory (or alternative location that you created it)... (which other projects can declare as a dependency)
The only time maven cares about having a main class, is when you want to make the jar executable
What do you mean by "main.class"? A class Main? No, it's not required.
If you meant a method main, an entrypoint to execution like below, it's not required either. Unless you want to execute the code directly.
public static void main(String[] args) {
}
In my projects, I need to import third party jar file and Facebook SDK.
compile files('libs/SkinSDK.jar')
compile 'com.facebook.android:facebook-android-sdk:4.14.0'
Both include same BundleJSONConverter class. So, I cannot do generate signed APK. It always shows duplicate entry com/facebook/internal/BundleJSONConverter.
So, I want to exclude in Facebook or SkinSDK.jar. I tried like
compile ('com.facebook.android:facebook-android-sdk:4.14.0') {
exclude group: 'com.facebook.internal', module: 'BundleJSONConverter'
}
It's not working and showing same error.
The exclude method of the configuration closure for a dependency excludes transitive dependencies. So, if your module dependency depends on other modules, you can exclude them from your build. You can check out the transitive dependencies of the 'com.facebook.android:facebook-android-sdk:4.14.0' module on its Maven repository info page.
If the BundleJSONConverter class exists in a transitive dependency, you can exclude the specific module in the same way you are trying now. Just specify the group, the module and the version, like you do for dependencies.
If you just want to exclude one class for a dependency jar, take a look at the jar jar links tool and its Gradle plugin. It allows you to alter included jars, e.g. to change packages or remove classes.
The following (shortened) example shows the usage of the plugin and some methods to alter the dependency jar:
compile jarjar.repackage {
from 'org.apache.hive:hive-exec:0.13.0.2.1.5.0-695'
archiveBypass "commons*.jar"
archiveExclude "slf4j*.jar"
classDelete "org.apache.thrift.**"
classRename 'org.json.**', 'org.anarres.hive.json.#1'
}
Bumped into similar situation. This is what I did, not elegant as I hoped, but it works:
Rename the jar file (SkinSDK.jar in your case): .zip instead of .jar
Go "inside" the zip file (I'm using DoubleCommander, there are many other utilities for that), or extract it to a temporary folder.
Delete the duplicate class that causes the problem. Go "outside" the zip file.
Rename (or re-pack) the file from .zip to .jar . Compile.
Hope it works...
I had a similar problem with duplicated classes after importing a jar. In my case, the conflict was between a class in that jar and a class in my own project.
Below I share the solution you can use to discard classes that you have available in your own source tree, assuming the one in the jar is the right one to use:
android {
sourceSets {
main {
java {
filter.excludes = [
"com/package/Duplicated.java",
]
}
}
}
}
working with java 9 modules, if i am using java.xml in my code...
1) i will import xml package using import statement...
2) if i don't mention that this package is required in the module declaration of my module...
- will the compilation of my module work.. ??
i would guess... no... and on mentioning that xml package is required on module-info.java... it might work.
so.. what I am wondering is... is that not redundancy... every importing package is implicitly... required. (unless i need to understand module even better)
Is there a way to mention that all imported packages are required in module declaration, other wise it could be a long list to mention in module-info.java?
First of all, in module-info.java you mention modules, not packages. E.g. java.xml is a module which contains about 25 packages. So, if your module uses 10 packages from the java.xml module, you don't have to repeat that 10 times in module-info.java, you write requires java.xml just once. So, that huge list of dependencies is not huge actually.
If you really want to skip all those declarations, you can just not create module-info.java (but I don't recommend to do that). A module that does not have module-info.java is called an automatic module and it implicitly requires all other modules.
I have a project structure, where I have some basic projects, where all the features are implemented and on top of that some projects for different kinds of usage/deployment as follows:
foo-core
foo-production, depends on foo-core (produces a war file and i delivered to customers)
foo-standalone, depends on foo-core (produces a war used for internal testing)
foo-ui-test, depends on foo-core (UI tests with Arquillian+Selenium)
Now I have a rising number of classes that are useful for foo-standalone and for foo-ui-test, but I don't want to deploy these classes to the customer. Therefore foo-core is out as a possible project where to store these classes. The two remaining options are:
A new project foo-helper which depends on foo-core and make foo-standalone and foo-ui-test depend on foo-helper instead of foo-core.
Make foo-ui-test depend on foo-standalone
I'd like to go for option 2 as I already have a lot of projects. The remaining problem for option 2 is that both of these projects (foo-standalone and foo-ui-test) have a Spring WebApplicationInitializer...
Now I fiddled around with my build system (I use gradle) and was able to exclude the WebApplicationInitializer in the foo-standalone project and only explicitly include it when building the foo-standalone.war file.
The resulting build.gradle file for foo-standalone seems "hackish" and will break if I rename or move the WebApplicationInitializer class. I wonder, if there is another way to achieve what I'm looking for or if I have to make a new project.
Update
I moved the WebApplicationInitializer class from src/main/java to src/init/java and changed the build.gradle of foo-standalone as follows:
sourceSets {
init {
java {
compileClasspath += sourceSets.main.runtimeClasspath
}
}
}
war {
classpath sourceSets.init.runtimeClasspath
}
I guess that's the shortest, custom way to do this, or is there any built-in gradle functionality which does this?
Maven will only allow you to have a dependency to a JAR project. There is a feature where you can have war overlays, where one war project extends a child and overrides certain bits (see https://maven.apache.org/plugins/maven-war-plugin/overlays.html) this seems the relationship between your foo-standalone and foo-ui-test.
So make foo-helper a war project and make foo-standalone, foo-ui-test and foo-production extend it using war overlays.
foo-core can stay as a jar, if there are non-production bits create a foo-core-internal to depend on foo-core and ring fences the internal/test bits.