Scope of internal visibility modifier in Kotlin - visibility

I have a problem understanding the internal access modifier. In my examples I could not produce any situation where it behaves different then public. Even if I create a jars I can access the internal functions in the jar from outside the jar (from a different package unrelated to the one used in the jar). In the documentation the term module is used but I could not find out what a module is exactly.
My questions thus are:
what is a module in kotlin?
how does the access modifier internal differs from the public modiefier?

The Kotlin compiler version M8 (0.8.11) ignores modules, more precisely, it works as if all your code were put into the same module, this is why you can't get a visibility error for internal.
Starting with the next milestone release, every IDE module you create has its own visibility scope, and when you try to access an internal declaration from one module in another, you get an error. Publics, on the other hand, are visible across the whole project.
UPDATE: This has not been turned on in M8, postponed for later
UPDATE: This has been turned on since later Kotlin milestones and betas

Related

Gradle kotlin how to call function defined in parent?

When working with gradle multimodule project, is it possible to define functions in parent project but use them in submodules build.gradle.kts?
Note i do not need untyped tasks registered and called with strings... I want actual typesafe code to be shared to submodules.
Ideally without creating a plugin or using buildSrc.
Whats the most to the point way to share a class from parents build.gradle.kts to all submodules?
NOTE : this is not the same as sharing closure trough ext... you loose type safety, what i ask for is Type safety on submodule side.
I'm thinking that there is no way. When a Kotlin build script gets compiled, it will end up as a class called Build_gradle in the default package (i.e. empty package) that extends CompiledKotlinBuildScript. Any class that is defined within a script becomes a public nested class in its corresponding Build_gradle. When the subproject build script gets compiled, it has no access to the classpath that contains the parent projects build script. This makes sense, as there would be multiple Build_gradle files in the same (default) package.
I'd go for buildSrc, to solve the problem, but I'm speculating that what you also wanted was some sort of nice separation of concerns in a multimodule project, not having unrelated projects knowing about what others need to communicate. What you could do to minimize the exposure is to only keep the API (interfaces, data classes) in buildSrc and have a script plugin in a parent project provide the implementation.

When to use "optional" dependencies and when to use "provided" scope?

Dependencies decorated by <optional>true</optional> or <scope>provided</scope> will be ignored when they are dependent transitively. I have read this, and my understanding is like the difference between #Component and #Service in Spring, they only vary semantically.
Is it right?
In addition to the comment, there is more important semantic difference: "Provided" dependencies are expected to be supplied by the container, so if your container gives you hibernate, you should mark hibernate as provided.
Optional dependencies are mainly used to reduce the transitive burden of some libraries. For example: If you can use a library with 5 different database types, but you usually only require one, you can mark the library-dependent dependencies as optional, so that the user can supply the one they actually use. If you don't do, you might get two types of problems:
The library pulls a huge load of transitive dependencies of which you actually need very few so that you blow up your project without reason.
More dangerously: You might pull two libraries with overlapping classes, so that the class loader cannot load both of them. This might lead to unexpected behaviour of your library.
A minor difference I'd like to point out is the treatment of optional vs. provided by various plugins that create packages.
Apparently war plugin will not package optional dependencies, but there is an open bug about it: https://issues.apache.org/jira/browse/MWAR-351
The assembly plugin doesn't seem to provide any way to filter based on optional status, while it allows you to filter based on scope.
It seems the same is true for the shade plugin.
TL;DR if you are not developing a library, but a top-level application provided scope will give you more flexibility.

Can class conflict cause "java.lang.NoSuchMethodError"?

In my maven project, there were two different jars but contain the same class with the same package name. Can that cause NoSuchMethodError?
I know if the method does't exist will cause this Error? What if there have the method, but duplicate?
This usually happens when you have two versions of the same project on the classpath and they changed the API. Depending on which JAR is looked at first, the method will be found or not.
If the method exists in both JARs, then it will work but something else might fail (there will be other differences).
If you add the same JAR several times on the classpath, then it will always work.
Solutions:
Always make sure the classpath is clean. Every fully qualified class name should resolve to a single class resource (file).
Sometimes, people add classes from different projects to their JARs "to make them easier to use." If that is the case, then open the JAR with a ZIP tool and delete the extra classes. Maven works better without such "help".
If the conflict exists, and the method exists in both classes, the error won't show, however its a common case that there's a difference in a signature, between the conflicting versions, which can confuse you. My advice, check if the signature of the loaded class matches, and work your exclusions properly

Why do people cite the ability to "define module boundaries" as an advantage of OSGI?

Don't the default Java access modifiers (public, protected, private) already define boundaries for how classes can be accessed. Why are these modifiers not sufficient? Why is OSGI's way of "defining moudle boundaries" better than this?
Yes, the java access modifier's define a classes boundaries and to some extent a package's boundaries but a module is larger than a single class or package. You may want to see http://www.slideshare.net/bjhargrave/why-osgi which explains the progression of encapsulation through classes and onto modules.
Short answer
In a modularized system it is very important to separate API from implementation where only API is exported. You cannot do that based on class modifiers. Other very important part of OSGi is the versioning of packages. You have to assign version only to those packages that are exported.
Long answer
A more prcise answer to this question is available at the following wiki post that was written by Neil Bartlett: http://wiki.osgi.org/wiki/Export_Only_APIs
Similar question
Why do we need object-orientation when functions are already available in structured languages? Are not the functions used to separate logical units of an algorithm?
I thought about it a little bit, and realized that there are certain privacy restrictions that OSGI's export mechanism can impose that plain old Java access modifiers cannot. See the diagrams below.
Notice how in Plain Old Java, a public class is visible (indicated by a green arrow) to all classes no matter what. In OSGI, a public class is visible to all classes (including classes in another bundle) ONLY if it is part of an exported package.
Note:The "protected classes" in the diagram are really just classes without any modifier (since there is no "protected" modifier for classes, just for fields and methods)
Edit: I'm adding this relevant quote from here: http://njbartlett.name/files/osgibook_preview_20091217.pdf
"A public class is visible to every class in every other package; a default access
class is only available to other classes within the same package.
There is something missing here. The above access modifiers relate to visibility
across packages, but the unit of deployment in Java is not a package, it is a
JAR file. Most JAR files offering non-trivial APIs contain more than one
package (HttpClient has eight), and generally the classes within the JAR need
to have access to the classes in other packages of the same JAR. Unfortunately
that means we must make most of our classes public, because that is the only
access modifier which makes classes visible across package boundaries.
As a consequence, all those classes declared public are accessible to clients
outside the JAR as well. Therefore the whole JAR is effectively public API,
even the parts that we would prefer to keep hidden. This is another symptom
of the lack of any runtime representation for JAR files."

Why does bnd add a uses directive for a package used only within a method body?

I have a project with a single source file, listed here in its entirety:
package com.acme.el;
public class ExpressionUtils {
public static Object evaluate() {
new org.apache.commons.el.ExpressionEvaluatorImpl();
return null;
}
}
The functionality is irrelevant to the question. When I build the project as an OSGi bundle using Gradle, the manifest contains the following instruction:
Export-Package: com.acme.el;uses:="org.apache.commons.el";version="1.0"
What baffles me is that uses directive. As I've understood the directive, it is meant to define dependencies on other packages that need to be propagated to other bundles importing this exported package - if my class definitions or method signatures refer to classes in the org.apache.commons.el package, for instance. But in this class, the dependency on org.apache.commons.el is completely contained within the body of a method. It is not exposed in the API, and no other bundle importing com.acme.el could ever get a hold of the ExpressionEvaluatorImpl instance created in the method. So the dependency shouldn't need to be propagated, right?
Did I misunderstand the meaning of the uses directive, or is its use here unnecessary?
I made a minimal example GitHub repo for reproduction which you can clone and import as a Gradle project in Eclipse.
If, in your bnd file, you set -experiments: true you should get the proper uses: clause, only based on public API references.
The problem is that bnd from the beginning has used all the imports to calculate the uses constraints. This was by far the easiest and nobody, so far, has ever complained about it. However, I did create the code to scan the public API but never felt confident enough to remove it from the experimental phase ... The current model is creating too many uses constraints but that should in general be the safe way.
This code has not been tested enough nor do I feel confident that changing this calculation will not create problems in existing builds. So I am in a bit of a bind here.
Gradle 1.7 uses bnd 2.1.0, instead of bnd 1.50.0 which is used by earlier Gradle distributions. This problem does not occur when using Gradle 1.7, as demonstrated by this GitHub repo.

Resources