This question already has answers here:
What's the difference between requires and requires static in module declaration
(2 answers)
Does the Java 9 Module system support optional dependencies?
(1 answer)
Closed 3 years ago.
I started to learn jigsaw java-9 feature and read some articles/video.
I can't understand concept of optional dependencies(requires static)
quote from article:
When a module needs to be compiled against types from another module
but does not want to depend on it at run time, it can use a requires
static clause. If foo requires static bar, the module system behaves
different at compile and run time:
At compile time, bar must be present or there will be an error. During
compilation bar is readable by foo.
At run time, bar might be absent
and that will cause neither error nor warning. If it is present, it is
readable by foo.
So I want to know couple of things:
What the reason to make module dependable on another module during compile time but not in runtime? any examples? instruments like lombok?
Any analogs of optional dependencies in java prior java-9 ?
P.S.
I found one more explanation:
quote from article:
Sometimes we write code that references another module, but that users
of our library will never want to use.
For instance, we might write a utility function that pretty-prints our
internal state when another logging module is present. But, not every
consumer of our library will want this functionality, and they don’t
want to include an extra logging library.
In these cases, we want to use an optional dependency. By using the
requires static directive, we create a compile-time-only dependency:
module my.module {
requires static module.name;
}
But it is absolutely unclear for me. Could anyone explain it in a simple way?
There are a decent number of libraries out there where it only makes sense to have them at compile time. Mostly this deals with annotations that only exist to help during development (e.g. prevent bugs, reduce boilerplate). Some examples include:
java-annotations by JetBrains
spotbugs-annotations by SpotBugs (successor of FindBugs)
Project Lombok (as you mentioned)
jcip-annotations
These annotations tend to have a RetentionPolicy of SOURCE or CLASS, which means they aren't useful (or even available) at runtime. Why ship these dependencies with the rest of your application when you deploy? Without requires static you would be forced to include them when you deploy, otherwise your application would fail to start due to missing dependencies.
You would declare these dependencies as optional pre-Java 9 as well. Many Java projects of any significance use a build tool such as Maven or Gradle. In addition to those tools automatically building and testing your project, a large part of what they do is dependency management. I'm not familiar enough with Maven, but when using Gradle one would use:
dependencies {
compileOnly 'group.id:artifact-id:version'
}
To declare dependencies that are not needed at runtime.
If Dependent Module should be available at compile time but optional at rumtime, then such type of Dependency is called Optional Dependency. We can Specify optional dependency by using static keyword.
Note The static keyword is used to say that "This dependency check is mandatory at compile time and optional at runtime."
Eg.1
module moduleB {
requires moduleA;
}
moudleA should be available at the time of compilation & rumtime. it is not Optional Dependency.
Eg2.
module moduleB {
requires static moduleA;
}
At the time of compilation moduleA should be available, but at runtime it is optional ie, at runtime even moduleA is not avaiable JVM will execute code.
Related
I have two versions of the same Java class (same name / methods). Since it's Java, both .java files have the same name. I want to configure gradle in such a way that I can build a "debug" version of my application that pulls in one of these files, and a "production" version of my application that pulls in the other one. How would I go about doing this?
This class has only static methods. I don't ever want to make an instance of this class. I additionally don't want to add the overhead of an if statement in each of the methods on this class to check which version I'm in.
Following #JFabianMeier's answer you could use 4 projects:
with the production version class
with the debug version class
with code that uses either of the two, parameterized according to Migrating Maven profiles ... → Example 6. Mimicking the behavior of Maven profiles in Gradle. (I'm also a Maven guy and therefore can't tell you exactly how to do it in Gradle.)
a multi-project with 1./2./3. as sub[-]projects for building all of them in one go, maybe parameterized to build just 1.+ 3. or 2.+ 3.
Have you tried creating production and debug source directories/sets? According to the docs you can use multiple directories when specifying source directories in your source set. Try dropping the different versions of your class in their respective production/debug source directories.
I haven't tested myself (not sure about the syntax), but this is based on the Gradle's Java compilation documentation.
sourceSets {
// Could also name this production
main {
java {
srcDirs ['src/main/java', 'src/prod/java']
}
}
debug {
java {
srcDirs ['src/main/java', 'src/debug/java']
}
}
}
You could do the following:
Put the class into a separate project (so generate a separate jar from it)
Then you can have two different jars, for production and debugging
Then you can pull either one or the other jar in gradle depending on a parameter.
Alternatively, you could look into template engines like Velocity which allow you to generate source code during the build depending on variables and then compile it.
Android has a neat feature called Product Flavors. It lets you swap classes at compile time effortlessly and keep your project clean.
This post is very good to get a taste of it: https://android-developers.googleblog.com/2015/12/leveraging-product-flavors-in-android.html
And here is the full documentation: https://developer.android.com/studio/build/build-variants#product-flavors
sun.misc.Perf was in tools.jar and in Java 9 this was removed and restructured based on the modules concept, so the question is how do you access it in newer Java?
I need to know which module now contains this code.
The implementation has been moved under the jdk.internal.perf package within the java.base module.
As the name already suggests, the package has not been exported from the module and hence if you still want to explicitly make use of the classes within this package, you can make use of the VM option:
--add-exports java.base/jdk.internal.perf=<your-module-name>
Do note though, this is an unreliable way of making use of such classes and a better solution would always be to migrate for the specific use cases without depending on the (internal) sun.misc.* classes.
After upgrading a Maven project to Java 9 and adding a module descriptor, javac complains about a transitive dependency for an automatic module:
[WARNING] /.../src/main/java/module-info.java:[3,35] requires transitive directive for an automatic module
An example module-info.java to reproduce the problem:
module com.example.mymodule {
exports com.example.mymodule.myexportedpackage;
requires transitive com.google.common;
}
The meaning of this warning is completely clear, here are some related links:
What's the difference between requires and requires transitive statements in Java 9?
Why does javac complain about named automatic-modules?
Related OpenJDK issue
The question is — how to suppress this warning, without fixing the actual issue, and without disabling all the other javac warnings?
I've tried the following options, but none of them worked:
#SuppressWarnings("module") in module-info.java
#SuppressWarnings("all") in module-info.java
-Xlint:all,-module command line option
Unfortunately, I cannot fix the actual issue (for now) because "my" module has return types and annotations from third-party (automatic) modules (e.g. Guava). Thus, if I'd use "requires com.google.common" (without transitive), then there would be a different warning, e.g.:
[WARNING] .../MyClass.java:[25,20] class com.google.common.collect.Table in module com.google.common is not indirectly exported using requires transitive
And of course I cannot define module descriptors for the third-party libraries (which are automatic modules right now).
I'm using -Werror which I'd prefer to keep, so the warning isn't merely annoying...
P.S. I do not intend to publish my artifacts to any public repositories.
You could try out the option of switching off the warning using
-Xlint:-requires-transitive-automatic
The changes for which were merged with JDK-8178011 stating:-
There should be two new warnings:
when a named module "requires transitive" an automatic module (default on)
when a named module "requires" an automatic module (default off)
Inferring this from the changes made here and also from the edit to the JEP 261: Module System which confirms that(emphasis mine):-
In both of the modular modes the compiler will, by default, generate
various warnings related to the module system; these may be disabled
via the option -Xlint:-module.
More precise control of these warnings
is available via the exports, opens, requires-automatic, and
requires-transitive-automatic keys for the -Xlint option.
You can also just use #SuppressWarnings like so:
#SuppressWarnings({ "requires-automatic", "requires-transitive-automatic" })
module foo {
// ...
}
The JDK itself uses this technique.
Sadly, the accepted answer didn't help me.
BTW, I am using Java 14 with a bunch of module system hacks for JUnit.
I had to add another flag, so the complete list looks as following:
-Xlint:-exports -Xlint:-requires-transitive-automatic -Xlint:-requires-automatic
I have searched for the error message and found the source code. There, one can see that the corresponding compiler key is called compiler.warn.leaks.not.accessible.not.required.transitive, with the command line arg -Xlint:exports.
I've read that OSGI uses separate classloaders per module which allows modules to use different versions of their dependencies.. while at the same time running all modules in the same JVM.
How does this work? If module A uses version #1 of a dependency and module B uses version #2, won't you run into trouble if module A passes an instance of the dependency class to module B as a method parameter?
I would think module B would choke if it was expecting a different interface to the dependency class.
You're right that inconsistent dependencies can cause problems. OSGi avoids this by calculating the transitive closure of these dependencies and ensuring that there are none at resolution time.
This allows you to expose a public dependency whilst having internal/hidden private dependencies and, as a result, hide your implementation dependencies to avoid this. The good thing is all thus is checked at Bundle resolution time rather than obscure runtime errors.
Specifically in your example, if A and B uses an incompatible interface, and A depends on B, then A will fail to resolve with a dependency error. So it won't even be able to start to pass it an incompatible type.
I am looking for a replacement for javadeps, which I used to use to generate sections of a Makefile to specify which classes depended on which source files.
Unfortunately javadeps itself has not been updated in a while, and cannot parse generic types or static imports.
The closest thing I've found so far is Dependency Finder. It almost does what I need but does not match non-public classes to their source files (as the source filename does not match the class name.) My current project has an interface whose only client is an inner class of a package-private class, so this is a significant problem.
Alternatively if you are not aware of a tool that does this, how do you do incremental compilation in large Java projects using command-line tools? Do you compile a whole package at a time instead?
Notes:
javadeps is not to be confused with jdepend, which is for a very different purpose.
This question is a rewrite of "Tool to infer dependencies for a java project" which seemed to be misunderstood by 2 out of 3 responders.
I use the <depend> task in ant, which is ok, but not 100% trustworthy. Supposedly JavaMake can do this dependency analysis, but it seems to be rarely updated and the download page is only sometimes available.