"Module local" access behaviour in Java 9 - java

As a core of Jigsaw project is the Java Module System, it would be nice to have an ability to restrict access to particular program elements (classes, methods and fields) within particular module only.
It can be helpful when there are some elements in module which are essentially public for this module, but shouldn't be accessible outside this module.
So I'm talking about the next level of access after "package-local", which could be named "module-local".
However a brief look on Jigsaw rules and early specs didn't help me to find out such kind of functionality. More specifically this Modifier specification doesn't contain any new elements.
So is there any other possibility to do it in future Java 9?

A public element (i.e., a class, interface, method, or field) in a
non-exported package is, in effect, “module local.” It will be
accessible to all other code in the module, but not from outside the
module.
There is no way to declare a module-local element in an exported package.
A public element of an exported package is accessible from outside the
module, a package-private element is still package-private, and there’s
no element-level access mode between these two modes. We could define a
new such mode but we’ve seen few compelling use cases for it and,
moreover, implementing modular access control in the JVM at a granularity
finer than that of exported packages would impose significant performance
costs.

Short Answer
It can be helpful when there are some elements in module which are essentially public for this module, but shouldn't be accessible outside this module.
That is not possible. (With means of the module system alone - there is a workaround.)
Long Answer
The explanation lies within the term Accessibility:
The Java compiler and virtual machine consider the public types in a package in one module to be accessible by code in some other module only when the first module is readable by the second module, in the sense defined above, and the first module exports that package. [...]
A type referenced across module boundaries that is not accessible in this way is unusable in the same way that a private method or field is unusable: Any attempt to use it will cause an error to be reported by the compiler, or an IllegalAccessError to be thrown by the Java virtual machine, or an IllegalAccessException to be thrown by the reflective run-time APIs. [...]
A method or field referenced across module boundaries is accessible if its enclosing type is accessible, in this sense, and if the declaration of the member itself also allows access.
While there are different ways exactly how and to whom a package can be exported, once the compiler/JVM deems a type accessible no additional mechanism applies. Its members are as accessible as they were before Jigsaw.
This means that there is no way to have an accessible type's members visible within the module (that would require public) but not outside of it (because a public member of an accessible type is accessible).
Workaround
So is any other possibility to do it in future Java 9?
Yes. :)
You can have a public interface Global in an exported package that defines the methods you want to export to the world. Then have either an interface or a class Local extend Global and add all the members you want. Key is that Local must not be in an exported package!
Now if your module's API only returns Global-s but never accepts them as a method argument, you're good to go. Just make sure that internally you always use - and maybe cast to - Local.
If you also accept Global-s you have to clearly document that these can only ever be instances your API returned (i.e. the user is not allowed to create her own implementation). This might sound prohibitive but if you think hard about your original request, it would have the same characteristics.

Related

Do static classes used in different jars in the same program access the same data?

Well, the title says most of it. I searched and most people don't really answer what I'm trying to get at. In Minecraft plugins, you make jars of code that get run by Bukkit/Spiggot. If I create a static class that is used in multiple jars, but inside the same program(Bukkit), so they act statically and share data?
Jar files are not a unit of scoping or encapsulation in Java. They are simply sources from which a ClassLoader can load classes and resources, and that can carry additional metadata. Java code has no (direct) sense of the Jar, if any, from which a given class was loaded, and once loaded, classes are global to the VM*.
Supposing that all the classes in question are loaded by the same or suitably-related ClassLoaders, there will be at most one in the VM for each distinct, fully-qualifed class name, and all references to each class name will refer to the same class. If that class has static variables, then they will be shared among all objects that access the class.
*Classes are, however, scoped by the ClassLoader that loaded them, so it is possible to have distinct classes with the same name in one VM. Although I do not know Minecraft implementation details, it seems unlikely that it would be leveraging that capability.
Public classes loaded by the same classloader, regardless of where they are defined (same or different .jar, .class, etc), are in the same scope which means they can access each other.
The answer is "maybe".
In a raw JVM, the static class is loaded by a universal ClassLoader, so all references to that static class will refer to the same data stored in the static members of that class.
In more complicated frameworks, scoped ClassLoaders segregate accessibility of data between application components. In this case, two separate components might have different references to the "same" class. The rules here get tricky .. because it's hard to understand, and because sometimes there are bugs visibility between the component scopes may or may not "leak" or there might be a scoping boundary that you're not expecting.

design of Java classes and packages

I have a context class -> prototype.context -> which apps can create objects of, but cannot extend. The system developer can however extend the classes to more types. The package of system classes would be prototype.system and prototype.dbengine . These classes should have full access to context objects, but other classes should not.
If I keep the fields in context class as package access, these classes cannot access it, because they are from a different package. So how should I name the packages so that the classes are available to other developers, and also have full access to system classes?
What you want is actually a simulation of the C++ friend-class feature. A nice trick is described here: https://stackoverflow.com/a/18634125/2886891
If you absolutely have to use package-private access and/or cannot use protected, then really the only option you have short of using public is to stick everything into the same package.
This is because in Java, "subpackages" don't really exist -- for example, java.util is an entirely different package than java.util.concurrent; thus, whether java.util.concurrent is called that or java.concurrent doesn't make a difference from the standpoint of access scope. In either case, classes in java.util.concurrent won't be able to access package-private members from java.util. The naming is only for convenience, and doesn't indicate any actual hierarchy.
Thus, no matter how you name your packages, you won't be able to access package-private members from another package.
Have the system and dbengine classes extend the necessary classes in context and set fields/methods that the system and dbengine classes need to protected.

Package and visibility

I'm making an SDK and I'm trying to separate classes to different packages, those classes use some other shared classes. The issue is if I made the shared classes public everyone will be able to see them, not only my classes. What's the right way to make them only accessible by my application?
Example :
Package a
MyClass1
Package b
MyClass2
Package c
public MySharedClass
Because c is public MySharedClass will be able to access it, but the issue is that it will also will be visible to the world, how could I prevent that?
Create a package that is documented as an internal package, not to be used by clients.
There is no way in Java to make a class public only for certain packages: It either is public for everyone or package-private (public only in the declared package).
I think there's a proposal for modules to allow better control in the visibility of classes, but we'll have to wait, at least, for Java 8.
The packages are all "public" in Java, what you can protect is the classes within a package. For limiting the visibility of a class to only a given package, declare it like this (without the public visibility modifier):
class MyClass {
// ...
}
In that way, only the classes in the same package as MyClass will be able to see it.
Non trivial:
The shared classes could be defined by a generally accessible set of interfaces. The actual implementation should be loaded explicitly via a Classloader. After that, simply apply Java Security Management mechanisms to control access to the implementation classes. Anyone can see the interfaces and access to actual implementation will be restricted to your SDK.
(A varient of above is what every web/app server needs to do. How do you think Tomcat prevents you from accessing some other app's "public" classes?)
edit: note above is a runtime mechanism. There are static (post) compile approaches as well. APT for example, could be effective here. Naturally I am not addressing a restructuring of your package (in OP) and only addressing how to secure access to a general approach. But these are a bit 'hacky' -- the runtime mechanism of class loading is canonical and imo strictly more correct.
If the class is shared by classes from two different packages, it could be a good indication that these two classes should be in the same package, along with the shared class, which wouldn't be public and would thus only be usable by classes of the same package.
If it's really not an option, just document the shared class appropriately, to indicate that it's not supposed to be used outside of the SDK internal code, that it's subject to changes in future versions, and make it even clearer by naming the package "internal" or somthing like this.
protected modifier can use,in case of your class will access only in same package. otherwise there is no possibility.

Does Java provide 'friend' access modifier?

I wonder if Java provides 'friend' (as in C++) access modifier? Someone said we can tread 'friend' as default modifier in Java. Is it true?
The default access modifier in Java allows members to be accessed by any code in the same package.
There is no such keyword (in Java) named as -
“Friendly”
The default access modifier has no keyword, but it is commonly referred to as “friendly.” It means that all the other classes in the current package have access to the friendly member, but to all the classes outside of this package the member appears to be private. Since a compilation unit – a file – can belong only to a single package, all the classes within a single compilation unit are automatically friendly with each other. Thus, friendly elements are also said to have package access .
Friendly access allows you to group related classes together in a package so that they can easily interact with each other. When you put classes together in a package (thus granting mutual access to their friendly members; e.g. making them “friends”) you “own” the code in that package. It makes sense that only code that you own should have friendly access to other code that you own. You could say that friendly access gives a meaning or a reason for grouping classes together in a package. In many languages the way you organize your definitions in files can be willy-nilly, but in Java you’re compelled to organize them in a sensible fashion. In addition, you’ll probably want to exclude classes that shouldn’t have access to the classes being defined in the current package.
There isn't a friendly modifier in Java. In Java it is called package private. And it is the default modifier. It allows members of the same package to access it.
As others have said, there is no friend access, but package based access is available.
However OSGI, and the (hopefully) forthcoming Super Packages attempt to extends this concept to classes in a some higher lever grouping of classes.

Why is each public class in a separate file?

I recently started learning Java and found it very strange that every Java public class must be declared in a separate file. I am a C# programmer and C# doesn't enforce any such restriction.
Why does Java do this? Were there any design considerations?
Edit (based on a few answers):
Why is Java not removing this restriction now in the age of IDEs? This will not break any existing code (or will it?).
I have just taken a C# solution and did just this (remove any file that had multiple public classes in them) and broke them out to individual files and this has made life much easier.
If you have multiple public classes in a file you have a few issues:
What do you name the file? One of the public classes? Another name? People have enough issues around poor solution code organization and file naming conventions to have one extra issue.
Also, when you are browsing the file / project explorer its good that things aren't hidden. For example you see one file and drill down and there are 200 classes all mushed together. If you have one file one class, you can organize your tests better and get a feel for the structure and complexity of a solution.
I think Java got this right.
According to the Java Language Specification, Third Edition:
This restriction implies that there must be at most one such type per compilation unit. This restriction makes it easy for a compiler for the Java programming language or an implementation of the Java virtual machine to find a named class within a package; for example, the source code for a public type wet.sprocket.Toad would be found in a file Toad.java in the directory wet/sprocket, and the corresponding object code would be found in the file Toad.class in the same directory.
Emphasis is mine.
It seems like basically they wanted to translate the OS's directory separator into dots for namespaces, and vice versa.
So yes, it was a design consideration of some sort.
From Thinking in Java
:
There can be only one public class per compilation unit (file).
The idea is that each compilation unit has a single public interface represented by that public class. It can have as many supporting “friendly” classes as you want. If you have more than one public class inside a compilation unit, the compiler will give you an error message.
From the specification (7.2.6)
When packages are stored in a file system (?7.2.1), the host system may choose to enforce the restriction that it is a compile-time error if a type is not found in a file under a name composed of the type name plus an extension (such as .java or .jav) if either of the following is true:
The type is referred to by code in other compilation units of the package in which the type is declared.
The type is declared public (and therefore is potentially accessible from code in other packages).
This restriction implies that there must be at most one such type per compilation unit.
This restriction makes it easy for a compiler for the Java programming language or an implementation of the Java virtual machine to find a named class within a package; for example, the source code for a public type wet.sprocket.Toad would be found in a file Toad.java in the directory wet/sprocket, and the corresponding object code would be found in the file Toad.class in the same directory.
In short: it may be about finding classes without having to load everything on your classpath.
Edit: "may choose" seems like it leaves the possibility to not follow that restriction, and the meaning of "may" is probable the one described in RFC 2119 (i.e. "optional")
In practice though, this is enforced in so many platform and relied upon by so many tools and IDE that I do not see any "host system" choosing to not enforce that restriction.
From "Once upon an Oak ..."
It's pretty obvious - like most things are once you know the design reasons - the compiler would have to make an additional pass through all the compilation units (.java files) to figure out what classes were where, and that would make the compilation even slower.
(Note:
the Oak Language Specification for Oak version 0.2 (postcript document): Oak was the original name of what is now commonly known as Java, and this manual is the oldest manual available for Oak (i.e. Java).
For more history on the origins of Java, please have a look at the Green Project and Java(TM) Technology: An Early History
)
It's just to avoid confusion in the sense that Java was created with simplicity in mind from the perspective of the developer. Your "primary" classes are your public classes and they are easy to find (by a human) if they are in a file with the same name and in a directory specified by the class's package.
You must recall that the Java language was developed in the mid-90s, in the days before IDEs made code navigation and searching a breeze.
If a class is only used by one other class, make it a private inner class. This way you have your multiple classes in a file.
If a class is used by multiple other classes, which of these classes would you put into the same file? All three? You would end up having all your classes in a single file...
That's just how the language designers decided to do it. I think the main reason was to optimize the compiler pass-throughs - the compiler does not have to guess or parse through files to locate the public classes. I think it's actually a good thing, it makes the code files much easier to find, and forces you to stay away from putting too much into one file. I also like how Java forces you to put your code files in the same directory structure as the package - that makes it easy to locate any code file.
It is technically legal to have multiple Java top level classes in one file. However this is considered to be bad practice (in most cases), and some Java tools may not work if you do this.
The JLS says this:
When packages are stored in a file
system (§7.2.1), the host system may
choose to enforce the restriction that
it is a compile-time error if a type
is not found in a file under a name
composed of the type name plus an
extension (such as .java or .jav) if
either of the following is true:
The type is referred to by code in other compilation units of the package in which the type is declared.
The type is declared public (and therefore is potentially accessible from code in other packages).
Note the use of may in the JLS text. This says that a compiler may reject this as invalid, or it may not. That is not a good situation if you are trying to build your Java code to be portable at the source code level. Thus, even if multiple classes in one source file works on your development platform, it is bad practice to do this.
My understanding is that this "permission to reject" is a design decision that is intended in part to make it easier to implement Java on a wider range of platforms. If (conversely) the JLS required all compilers to support source files containing multiple classes, there would be conceptual issues implementing Java on a platform which wasn't file-system based.
In practice, seasoned Java developers don't miss being able to do this at all. Modularization and information hiding are better done using an appropriate combination of packages, class access modifiers and inner or nested classes.
Why is java not removing this restriction now in the age of IDEs? This will not break any existing code (or will it?).
Now all code is uniform. When you see a source file you know what to expect. it is same for every project. If java were to remove this convention you have to relearn code structure for every project you work on, where as now you learn it once and apply it everywhere. We should not be trusting IDE's for everything.
Not really an answer to the question but a data point none the less.
I grepped the headers of my personal C++ utilty library (you can get it yourself from here) and almost all of the header files that actually do declare classes (some just declare free functions) declare more than one class. I like to think of myself as a pretty good C++ designer (though the library is a bit of a bodge in places - I'm its only user), so I suggest that for C++ at least, multiple classes in the same file are normal and even good practice.
It allows for simpler heuristics for going from Foobar.class to Foobar.java.
If Foobar could be in any Java file you have a mapping problem, which may eventually mean you have to do a full scan of all java files to locate the definition of the class.
Personally I have found this to be one of the strange rules that combined result in that Java applications can grow very large and still be sturdy.
Well, actually it is an optional restriction according to Java Language Specification (Section 7.6, Page No. 209) but followed by Oracle Java compiler as a mandatory restriction. According to Java Language Specification,
When packages are stored in a file system (§7.2.1), the host system
may choose to enforce the restriction that it is a compile-time error
if a type is not found in a file under a name composed of the type
name plus an extension (such as .java or .jav) if either of the
following is true:
The type is referred to by code in other compilation units of the package in which the type is declared.
The type is declared public (and therefore is potentially accessible from code in other packages).
This restriction implies that there must be at most one such type per
compilation unit. This restriction makes it easy for a Java compiler
to find a named class within a package.
In practice, many programmers choose to put each class or interface
type in its own compilation unit, whether or not it is public or is
referred to by code in other compilation units.
For example, the source code for a public type wet.sprocket.Toad would
be found in a file Toad.java in the directory wet/sprocket , and the
corresponding object code would be found in the file Toad.class in the
same directory.
To get more clear picture let's imagine there are two public classes public class A and public class B in a same source file and A class have reference to the not yet compiled class B. And we are compiling (compiling-linking-loading) class A now while linking to class B compiler will be forced to examine each *.java files within the current package because class B don’t have it’s specific B.java file. So In above case, it is a little bit time consuming for the compiler to find which class lies under which source file and in which class the main method lies.
So the reason behind keeping one public class per source file is to actually make compilation process faster because it enables a more efficient lookup of the source and compiled files during linking (import statements). The idea is if you know the name of a class, you know where it should be found for each classpath entry and no indexing will be required.
And also as soon as we execute our application JVM by default looks for the public class (since no restrictions and can be accessible from anywhere) and also looks for public static void main(String args[]) in that public class. Public class acts as the initial class from where the JVM instance for the Java application (program) is begun. So when we provide more than one public class in a program the compiler itself stops you by throwing an error. This is because later we can’t confuse the JVM as to which class to be its initial class because only one public class with the public static void main(String args[]) is the initial class for JVM.
You can read more on Why Single Java Source File Can Not Have More Than One public class

Categories

Resources