How to use separate class loaders and run in same JVM? (OSGI) - java

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.

Related

Use java serviceloader build with jdk8 use in >= java9

I have two jars. One provides a service interfaces and a service loading class and one provides the implementation of that service.
This works perfectly when running this in jdk8, but I get an service type not accessible to unnamed module #3754a4bf error when running on jdk9 or higher.
I migrated that two jars to a module base jar and that works great when running on >= jdk9, but that fails on jdk8 of cause, because of wrong class file version.
So, I don't have problem using java serivceloader api with java 8 or 9.
I'm aware of https://blog.codefx.org/tools/multi-release-jars-multiple-java-versions/ , but I want to avoid to make the build process more complicated. The build already involves class relocation and
other stuff.
My question: Is there a way to use the same jars running on jdk8 and >=jdk9 using java serviceloading api?
In JDK9 and up, all jars are effectively 'modules'. If they do not have a module definition (which you create by making a file named module-info.java and putting a module declaration inside), its name is 'unnamed module #whatever', it exports all its packages, and can access anything exported by any other module (in module-speak: it 'reads' everything). Meaning, if all your classpath dependencies are such unnamed modules, they all export everything and they all read everything thus they all can access anything marked public from anybody else – which is how it worked in JDK8, and thus, why it's all compatible.
To be clear: in JDK9, for code in module (jar) A to access a method, class, or field from module (jar) B, then in addition to the usual access modifiers (the public keyword), B needs to 'export' that package, and A needs to read that module, or it doesn't work. If you aren't explicitly writing module info files for either side, well, then you get the default behaviour which is 'export everything' and 'read everything', bringing us back to the JDK8 scenario of: the thing has to be marked public, and then you can access it.
I actually do not recommend you make that module-info file; that's a big step, one you should only take once you're familiar with the module system.
The error means that the 'service type'[1] is not 'accessible'[2] to 'unnamed module #3754a4bf'[3]. Let's break that into pieces:
[1] serviceloader works by defining an interface that a 'service provider' implements, and the class using the service loader then ends up with a bunch of instances of that interface; each representing one implementation. It's the Foo in ServiceLoader.load(Foo.class).
[2] 'accessible' is module speak for: Either the code that needs this did not explicitly 'read' it, or the code that has this did not export it.
[3] 'unnamed module#3754abf' is the name of the module that is trying to access it.
Taking this all together, it means: You're operating under false assumptions: Whatever jar contains your service interface (that Foo I was talking about), is NOT an unnamed module, or, possibly, isn't public. Note that if it is a public interface inside a not-public class (i.e.: /* package private */ class Example { public interface MyServiceInterface {} }), that probably still counts as 'not public enough'.
If it's a named module (which means: it has a module-info.java file), then export the package that the service interface is in. See any jigsaw (the name of the java module system) tutorial on how to set that up. If it's not, ensure it's a public interface or abstract class, and if its inside some other type, make sure those are public too. If neither is the case, check your classpaths; javac is rather adamant that one of these two is the case.

Practical use for requires static from java module system [duplicate]

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.

How split packages are avoided in Java 9

I am new to Java 9 and was going though the modular video lectures by Java on YouTube.
They mentioned 3 benefits of modularization-
1. No missing dependencies
2. No cyclic dependnpcies
3. No split packages.
As far as I understand about split packages is that let's say an application is dependant on multiple dependncies and let's say package abc.pqr.xyz is present in more that 1 jar.
Then there is a chance that some of the classes in that package will be used from jar1 while other classes from jar2.
This might lead to some problems at runtime which will be hard to debug.
Video says modularization solves this issue.
But how that's what I am trying to understand?
Let's say there is test.module1 which has below module info -
module test.module1{
exports abc.pqr.xyz;
}
Another module2 with below module info-
module test.module2{
exports abc.pqr.xyz;
}
Now let's say in my application I added dependencies of both of these modules-
module test.myapp{
requires test.module1;
requires test.module2;
}
Now again I have 2 modular dependencies where there is a chance that some of the classes will be present in both of these modules.
So at runtime how it will be resolved from which module to pick up the class definitions?
How Java 9 will avoid split packages problem?
With the scenario described in the question, you'll start facing an error reading :
Module test.myapp reads package from both test.module1 and test.module2
Readability of the Modules from The State of the Module System elaborates over the use of Modules as follows and shall interest your use-case(emphasis mine):
The readability relationships defined in a module graph are the basis
of reliable configuration: The module system ensures
that every dependence is fulfilled by precisely one other module
that the module graph is acyclic
that every module reads at most one module defining a given package
and that modules defining identically-named packages do not interfere with each other.
the benefit of implying the same in the module system is detailed as well
Reliable configuration is not just more reliable; it can also be
faster. When code in a module refers to a type in a package then that
package is guaranteed to be defined either in that module or in
precisely one of the modules read by that module.
When looking for the
definition of a specific type there is, therefore, no need to search
for it in multiple modules or, worse, along the entire class path.
That said, the current solution to your implementation is
if the modules test.module1 and test.module2 are explicit modules, you can choose to implement the package abc.pqr.xyz in either one of them
OR you pull it out from both into a separate module test.mergeModule of your own which can thereafter be used as an independent module across its clients.
if these(or any one of them) are automatic modules, you can make use of the bridge extended to the classpath and let such jar remain on the classpath and be treated as the unnamed module, which shall by default export all of its packages. At the same time, any automatic module while reading every other named module is also made to read the unnamed module.
Quoting the document again and to illustrate with an example, so that you can correlate to your question :
If code in the explicit module com.foo.app refers to a public type in
com.foo.bar, e.g., and the signature of that type refers to a type in
one of the JAR files still on the class path, then the code in
com.foo.app will not be able to access that type since com.foo.app
cannot depend upon the unnamed module.
This can be remedied by treating com.foo.app as an automatic module temporarily, so that its
code can access types from the class path, until such time as the
relevant JAR file on the class path can be treated as an automatic
module or converted into an explicit module.
The Java module system resolves the split package problem by rejecting this sort of scenario at JVM startup time. When the JVM starts it will immediately begin resolving the module graph, and when it encounters two modules in test.myapp's module path, the JVM will throw an error indicating test.module1 and test.module2 are attempting to export the same package.

Why Java 9 does not simply turn all JARs on the class path into automatic modules?

In order to understand the categories we have:
platform explicit modules
application explicit modules
open modules
automatic modules
unnamed module
All classes and jars within the classpath will be part of the unnamed module. But why is that what we need? Where is the advantage over automatic modules? I could "require" those damn legacy jars to make them to an automatic module. Do I not have included everything with it?
There are at least two reasons:
Just as regular modules, automatic ones are suspect to certain examinations by the module system, e.g. not splitting packages. Since JARs on the class path can (and occasionally do) split packages, imposing that check on them would be backwards-incompatible and break a number of applications.
The unnamed module can read all platform modules, whereas automatic modules can only read those that made it into the module graph. That means a JAR needing the java.desktop module (for example) will work from the class path but not from the module graph unless java.desktop also makes it into the graph (via a dependency or --add-modules).
I have no time right now to check the second but that's what the State of the Module system says:
After a module graph is resolved, therefore, an automatic module is made to read every other named module, whether automatic or explicit
Resolution works on the declared dependencies and an automatic modules declares none.
Apart from the items listed in the accepted answer, there is one more difference: unnamed modules can access all packages of modules that come with Java, even is they are not exported.
As long the class is public, access will work - the same as before Java 9. But as soon as a jar is run from module path, it will be able to access only exported packages.
For example if some .jar has this code:
com.sun.jmx.remote.internal.ArrayQueue c = new com.sun.jmx.remote.internal.ArrayQueue(10);
it will run normally without any warnings when placed on class path, but when run from module path (as automatic module) it will fail at runtime:
Exception in thread "main" java.lang.IllegalAccessError: class test1.C
(in module test1) cannot access class com.sun.jmx.remote.internal.ArrayQueue
(in module java.management) because module java.management does not export
com.sun.jmx.remote.internal to module test1
Note that this is different from the well known illegal reflective access warning, which is about using reflection to access private fields or methods. Here we are statically (non-reflectively) accessing public class (but from non-exported package).

Will Cyclic Module Dependencies be Possible in Java 9?

In Java 9, will cyclic modules be allowed? If no, what are the reasons?
module com.foo.bar {
requires com.foo.baz;
exports com.foo.bar.fizz;
}
module com.foo.baz {
requires com.foo.bar;
exports com.foo.baz.buzz;
}
Nope.
Documentation
Interestingly enough neither the State of the Module System nor the Jigsaw Quick Start Guide address this issue. One source (found by Andy) is a JavaOne talk by Alex Buckley (see him explain it here). A more recent one is the list of open issues, which explicitly mentions cyclic dependencies:
The current draft disallows cycles when the module graph is initially resolved at compile time, link time, and run time. Cycles can arise later on at run time if readability edges are added for automatic modules, or via reflection. [...] This constraint is not, however, a documented requirement [...].
Justification
Cyclic dependencies are bad, mkay. ;)
They emerge when two entities (methods, classes, modules, projects, ...) collaborate but are not sufficiently decoupled. For users as well as maintainers this coupling means that they can not use or improve one without considering the other. But this is exactly the benefit modularization is trying to achieve.
From the issue list, linked above:
The rationale for disallowing cycles during resolution is that it makes the module graph easier to reason about, it simplifies the module system itself, and that, philosophically, any modules involved in a cycle are logically one module anyway, so they should be defined as such in the first place.
Experimentation
I've created a little demo project on GitHub that contains two cycles (pair: two -> one -> two; triple: three -> two -> one -> three). Trying the multi-module compilation as shown in the quick start guide, these are the results:
./compile.sh
> creating clean directories
> compiling and packaging cycle "pair"
src/org.codefx.demo.cyclic.pair.one/module-info.java:2: error: cyclic dependence involving org.codefx.demo.cyclic.pair.two
requires org.codefx.demo.cyclic.pair.two;
^
1 error
> compiling and packaging cycle "triple"
src/org.codefx.demo.cyclic.triple.three/module-info.java:2: error: cyclic dependence involving org.codefx.demo.cyclic.triple.two
requires org.codefx.demo.cyclic.triple.two;
^
1 error
So you can't even compile the modules, let alone use them in a configuration.
Except the modules are automatic modules, the issue will not arise. Only transitive dependencies are allowed and transitive dependencies are never cyclic.

Categories