Java – How to Encapsulate Internal Classes in an API Written in Java?

javalibrariespackages

We have to write a library. Naturally, it should only have a very small API (as broad as needed as small as possible). The internals of the library are somewhat complex. Therefore, they need structuring.

For the structuring I currently see two ways:

1. use packages.

pros: the library can be neatly structured. Everything in its place.

cons: usage of classes through package borders need public classes and therefore broaden the API of the whole library.

2. use static inner classes, all in one package.

pros: only very little public things (classes, methods etc.) needed.

cons: Classes are hidden only to structure them. This would be one of very few use cases where there are so many static inner classes used. Developers are not used to that and might overlook them.


Is there a better way to achieve a small API in a well structured library?

Edit: I forgot to mention: it's for an Android library. Therefore, no java9.

Best Answer

I see what you're doing with 2. You're using classes as packages and packages as modules so you can isolate yourself within the package but still organize within the package using classes.

That's very clever. Beware of clever.

This will force you to jam multiple classes in the same source file (which you might prefer) and the path will have an extra capitalized word.

This will also force you to write any test code within the package unless you use reflection to hack your way in from outside.

Other then that, this will work. It will just seem weird.

People are more used to inner classes being used like EntrySet in Hashtable. It's private so I can't create it but it implements a public interface so I just talk to it through the interface and have something grab one for me.

But you're describing classes you don't want me talking to even through an interface. So no interface for me. This means I have nothing to look at and be confused by (unless you provide me with source).

Biggest issue I foresee is this confusing newbies maintaining the API. You can throw documentation and comments at them but don't be supersized when they don't read or trust either one.

You've created yet another pattern that makes up for a deficiency in the language. Java has no access modifier that grants access to a group of packages. I've heard that a "module" access modifier had been proposed but see no sign of it happening.

The default access modifier (no modifier) is likely what you'll use here unless you don't mind me sneaking in through inheritance, in which case protected.

Modifier        Class     Package   Subclass  World
public          Y         Y         Y         Y
protected       Y         Y         Y         N
no modifier     Y         Y         N         N
private         Y         N         N         N 

What you really want is module access. That way you could keep your tests in one package and code in another. Sadly we don't have it in Java.

Most people just do 1 and expand the API. Proper use of interfaces keeps the pressure off the implementation.

Hacking what you want into 1 is even uglier. Peek at the call stack and throw an exception whenever what called you is from a package you don't like. Eeew.

Related Topic