How to make a private package? - java

I'm doing a library. I have three packages:
Spreadsheet is the main package. The io package is an internal package for internal use. Unfortunately, the user can access to them since they are public classes.
I would like to keep this package, since it allows me to separate concepts while programming, but i would like to "hide" these classes to the end user.
What could i do?

It's good that you're asking yourself this question! I don't see much attention on this lately.
As OdsReader and OdsWriter are used only inside the Spreadsheet class, just move them inside the spreadsheet package, removing the public visibility keywork. They'll now be accessible only from the spreadsheed package's classes.
The solution proposed above, which is over-complicated for your use-case, and which is to use Java 9+ modules (or OSGi - please no!), is not really necessary here, but it's neverthless a step forward in maintaining definitions private and sealed, even to Reflection abusers.
As a side note, I see you've got an exceptions package.
I never recommend doing so, as you'll have to expose those exceptions' constructor to the users of your code, and they'll be able to instantiate them for no good reasons.
Move the exceptions inside the packages which uses them, and declare the constructor as package private.

Starting with java9, you can turn this library into a module. See this jigsaw tutorial.
Modules need to export a package in order for its public members to be accessible from other modules: Simply don't export your internal package, and it won't be visible.
You can also go with something like OSGi, a module system that predates java9. It too has this notion that there's a level beyond public (let's call it 'visible').
A final option is to use classloader shenanigans (where you for example rename your class files to some other extension during the build phase, and have a small bootstrapper in your visible package which creates a classloader that loads classes by looking in the same place as the visible API, and then load files with the alternative extension, and defineClass those into being), but that's a drastic step that introduces quite a bit of headache. I wouldn't take it unless you have excellent reasons to go down this rabbit hole.

Related

Is there any way that users of my modular library are able to access classes which have not been exported?

I'm trying to get familiar with the module system introduced in Java 9, and I would like to know the best way to leverage it.
For a library I'm writing, I would like to do the following (ignore the naming of the packages):
Expose only interfaces, simple POJO classes, and factory classes via com.myproject.api. Everything in this class can be used by the users.
Put the implementation of interfaces in com.myproject.core. Users should not be able to access anything in here.
My reasoning is that users do not need to get confused or overwhelmed by the implementation logic. Instead, they can just look at (hopefully) clean and well documentated interfaces.
However, due to the way Java packages work, it can be difficult to restrict use of certain classes without making them all package private. But I don't like putting all the classes in one package, and would rather organize them into various packages.
After reading about the module system, I believe I can do the following to achieve what I want. This is the module-info.java file:
module com.myproject {
exports com.myproject.api;
}
From my understanding, the users of my library will be able to use everything defined in the com.myproject.api package (by using require com.mypojrect.api in their own module-info file).
But is there any way that users will be able to access anything in the com.myproject.core package? I have no problem with them looking at the code (via IDE or the source code itself), but I just don't want to end up supporting classes/methods/logic which I didn't want to expose.
I'm concerned that users who don't have a modularized application or users who put my library JAR on the classpath will somehow find a way to get access to the supposed restricted package.
Please let me know if you need any other information.
A pre-JDK9 user of your library cannot exist, as you're going to use the Java Platform Module System, which is post-JDK8, and thus you're going to compile to a class version greater than 52.
Said that, your users will be able to look at the source code (if shipped), and obviously they will be able to extract your .class files.
By definition
a type in a module is not accessible to other modules unless it’s a
public type and you export its package.
The only way to gain Reflective access to your classes would be if you willingly opened them, with the
opens your.package
directive. So basically, you're covered also on the Reflection aspect.
And the opens directive exposes to Reflection only public definitions.
If you want to control Reflective access to your classes in a non-modular/pre-JDK9 environment, SecurityManager might be what you're looking for. However this requires access to the JVM configuration.

Controlling Class Visibility in Java

My project has currently following package structure.
Here I have added a package name utils and defined all utility classes related to this module inside it. Those have been used by other packages (i.e. impl, internal), and because of that I have made classes and methods in util package public.
Because, it is public, not only classes in this module, classes in other modules can also access this and when I am coding using my IDE they are shown as coding suggestions.
I went through few research papers which describe how this can reduce the usability of the API and give a bad experience to developers who involve in the development [ref1, ref2].
I understand that java does not allow me to make classes inside util accessible to impl and internal packages and not to others.
Is it correct to put my utility classes to a package 'util'? Or should I put all classes that communicate with each other to the same package?
You are correct, something marked public becomes usable in any other package. In contrast to other languages, Java doesn't provide any control beyond that.
A simple workaround: it might be helpful to have one special package containing those public things that should be available to your external users.
Meaning: create something like com.whatever.product.api - and instruct your users that they are fine to use everything from there - but nothing else.
In other words: you make all those things public that you need to public; but you collect those things in a special place that you allow to be used by others.
It is worth mentioning though that Java9 will introduce the concept of modules, those allow you to define which of your packages should be public to users of your module. In that sense, java 9 modules allow you to distinguish between "internal" and "external" public.
Util classes are fine. Util classes are functionality that is used multiple places in a project but doesn't really belong to a specific class.
In a perfect world of OOP there wouldn't be any util classes, but it is however considered a good practice to create util classes if they do not belong to a specific class.
Your options for access modifiers are listed here:
https://docs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html
There is one way to achieve what you you want, it is however concidered a very bad practice. You can change your access modifiers of util classes to protected. This will make your util classes accessible from subclasses and packages. So if a class needs access to one of the util classes, then it has to extend this util class and thereby become a subclass. I cannot stress it enought, this is a very bad practice.

When to package-private (no explicit modifier) in java?

I have been reading the tutorial Controlling Access to Members of a Class. I am confused what might be good use case for using package-private. Because as I understand, you can always change your package declaration to whatever the package declaration of such a class and act as if that is a public class. I understand that this is not a good thing to do, but what is stopping me?
Because as I understand, you can always change your package declaration to whatever the package declaration of such a class and act as if that is a public class
Well, for one thing, the access modifiers are there to help the developer. There's always ways around them, such as via reflection for instance.
I understand that this is not a good thing to do, but what is stopping me?
Not much really!
As a developer you can however distribute your classes in sealed .jar-files which basically means that you're not letting anyone else in to your packages.
From Sealing Packages within a JAR File
Sealing Packages within a JAR File
Packages within JAR files can be optionally sealed, which means that all classes defined in that package must be archived in the same JAR file. You might want to seal a package, for example, to ensure version consistency among the classes in your software.
A couple of reasons to use package-private classes/methods:
Implementation classes that are part of a library, but not part of the library's API. This allows you to still have modular code, and acts as a sign to users of the API that the implementation classes are not for use as part of the API.
Making things available to tests. Sometimes (particularly when working with legacy code) you need to make classes or members more visible so that you can more easily unit test them. An example might be testing a class with a method that performs a resource-intensive operation that you want to override with a no-op version in your test. Another example is a class that only gets used in one place: it doesn't want to be visible to the whole app, but it needs to be unit tested.
In both cases using package-priviate visibility helps to make your code easier to use (people using it have a better idea of the scope of the class/member's intended use), while allowing you to still have modular code.
Regarding "what is stopping me":
The Java Security mechanism is stopping you, potentially. If the "target" package is sealed and signed, then Java will not allow any source other than the original to declare classes in that package.

Creating an invisible class in a jar

How do I create a jar in java that only one class is visible (public) to users of the jar?
I know I can omit the "public" from the declaration of a class, which makes it visible only to that package, but how do I do it in a jar with several packages, when the visibility should be public to all the classes inside the jar, but not outside of the jar?
You're basically looking for the Java counterpart of .Net's assembly-wide visibility. I'm afraid you don't have this ability within the framework of current Java. Future version of Java will offer better support for modules, which should allow something along these lines.
You'd have to include all your classes in a single Java package, and omit the "public" modifier in the class definition.
I recommend against this. If you want to indicate a class shouldn't be used by clients of a library, put it in a package named "impl" or "internal" and don't provide public documentation.
Does using protected as modifier fix this? I know it does allow access for inherited classes, but I don't know about all the other classes in the package.
Just a wild idea, but you could play around with a custom classloader that loads files from your .jar which are not recognised as classes otherwise.
For instance you could postprocess class files by encrypting them and storing with your own file extension, then loading and decrypting them from the jar by your custom classloader from the "main" class that is visible to the users of the class. (caveat; I have never tried to do something like this myself :-))
Another method (if the code base isn't too large) might be to develop your classes like normal, run your tests on the package structure and as the last step before packaging use a (perl) script to rebuild your main class by inserting all other classes as private static inner classes and rebuild that. Using this transformation as a pre-package step means you can develop in a sane structure while hiding the implementation classes in the jar.

Why shouldn't we use the (default)src package?

I recently started using Eclipse IDE and have read at a number of places that one shouldn't use the default(src) package and create new packages.
I just wanted to know the reason behind this.
Using the default package may create namespace collisions. Imagine you're creating a library which contains a MyClass class. Someone uses your library in his project and also has a MyClass class in his default package. What should the compiler do? Package in Java is actually a namespace which fully identifies your project. So it's important to not use the default package in the real world projects.
Originally, it was intended as a means to ensure there were no clashes between different pieces of Java code.
Because Java was meant to be run anywhere, and over the net (meaning it might pick up bits from Sun, IBM or even Joe Bloggs and the Dodgy Software Company Pty Ltd), the fact that I owned paxdiablo.com (I don't actually but let's pretend I do for the sake of this answer) meant that it would be safe to call all my code com.paxdiablo.blah.blah.blah and that wouldn't interfere with anyone else, unless they were mentally deficient in some way and used my namespace :-)
From chapter 7, "Packages", of the Java Language Spec:
Programs are organized as sets of packages. Each package has its own set of names for types, which helps to prevent name conflicts.
I actually usually start by using the default package and only move it into a real package (something fairly easy to do with the Eclipse IDE) if it survives long enough to be released to the wild.
Java uses the package as a way to differentiate between classes. By using packages, you can have an org.example.Something class and an org.example.extended.Something class and be able to differentiate between them even though they are both named Something. Since their packages are different, you can use them both in the same project.
By declaring a package you define your own namespace (for classes). This way if you have two identical classes using a different package name (namespace) will differentiate between which one you want to use.
The main reasons I can think of are:
It keeps things organised, which will help you (and others!) know where to look for classes/functionality.
You can define classes with the same name if they are in different packages.
Classes/etc in the default package cannot be imported into named packages. This means that in order to use your classes, other people will have to put all their classes in the default package too. This exacerbates the problems which reasons 1 & 2 solve.
From a java point of view, there are two general dev/deploy lifecycles you can folllow, either using ant to build and deploy, or the maven lifecycle. Both of these lifecycles look for source code and resources in local directories, and in the case of maven, in defined repositories, either locally or on the net.
The point is, when you set up a project, for development and eventually deployment, you want to build a project structure that is portable, and not dependent on the IDE, ie. your project can be built and deployed using either of your build environments. If you use a heavy dependence on the Eclipse framework for providing class variables, compile paths, etc.. you may run into the problem that your project will only build and deploy using that configurationj, and it may not be portable to another developers environment, so to speak.

Categories