# How to encapsulate internal classes in an API written in Java?

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.

• Why do your inner classes need to be static? – David Arno Dec 1 '16 at 14:35
• Don't inner classes make code units larger? I mean a class with several inner classes can become very long. – Tulains Córdova Dec 1 '16 at 14:36
• @TulainsCórdova, good point, I read the term "inner" as "internal", which I think Java calls "package-private". The normal way to create a lib is surely to have one package, containing a few public classes, with everything else being internal/package-private. – David Arno Dec 1 '16 at 14:47
• Hi @frmarkus. I tried to re-write your question title to be more specific and avoid "unclear what you're asking" close votes. Feel free to re-edit it if you think it misrepresents your actual question. – Andres F. Dec 1 '16 at 14:59
• @TulainsCórdova: Yes, the code units get way to big (3k lines of code per file). That is another important problem of this way of structuring. – Markus Frauenfelder Dec 1 '16 at 15:15

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.

By all means, separate your code into packages. It will go a long way toward improving maintainability.

To keep end-users from accessing things that they shouldn't, you need to separate your API into interface and implementation.

You can do that very literally, by defining the entire API in terms of Java interfaces and providing some number of factory classes to produce implementation objects. This is what JDBC does.

Or you can do it via convention, by creating internal packages, and documenting those packages as implementation-dependent and subject to change without warning or backwards compatibility.

• Unfortunately, this is a complete no go. This leaves to many public classes. They might have hints (being factories or 'internal'). But a I have to apply additional tooling to them (to all public class), this is just not good. – Markus Frauenfelder Dec 2 '16 at 7:05
• @frmarkus - I think that (1) you're expecting far too much out of access controls, or (2) you need to re-think your package structure so that classes from one package don't need to depend on classes from another package (if you can keep everything as static nested classes this shouldn't be difficult). – kdgregory Dec 2 '16 at 12:21