Click here to Skip to main content
15,885,886 members
Articles / Programming Languages / Java

Emulate the internal keyword in Java

Rate me:
Please Sign up or sign in to vote.
0.00/5 (No votes)
4 Apr 2013CPOL3 min read 9.4K   4  
Emulate the internal keyword in Java

C# introduced the internal keyword to enable information hiding across program boundaries. It can improve the ease of maintenance on much larger programs. When a public class is declared as internal, it’s accessible from the assembly containing this class, but hidden from any other assembly using it.

Java doesn’t have an equivalent of the internal keyword, and does not provide any solution out of the box to have the same behavior.

Let’s declare a class Test like this:

Java
package com.sample;
class Test
{
}

The class Test is visible inside the package but not outside it, and if we declare Test as public, it will be visible from any class inside or outside the jar.

What’s the solution we have to make the class test visible inside the jar and hidden from any other jar?

Alternatives

1. Naming Convention

The method most used to inform that some classes are internals is to put them inside a package named internal, for example, here are all internal packages from the hibernate core jar.

internal

With this solution, we inform the library user that these classes are internals, but they can be instantiated from other jars.

2. Custom Class Loader

To resolve the issue of the first alternative, we have to not accept the instantiation of classes inside internal package, for that, we have to know how they are instantiated.

ClassLoader

The Java Classloader is a part of the Java Runtime Environment that dynamically loads Java classes into the Java Virtual Machine. Usually, classes are only loaded on demand.

It is the class responsible for finding and loading class files at run time. Creating your own ClassLoader lets you customize the JVM in useful and interesting ways, allowing you to completely redefine how class files are brought into the system.

To have more control over class instantiation, we can create our own class loader and add a custom logic. And in this case, we can refuse the creation of a specific class if it’s inside an internal package. And to use our custom class loader, the setContextClassLoader method is invoked.

We can improve this solution by defining an internal annotation instead of checking the package name, for example, we can declare an internal class like this:

Java
@internal
public class InternalClass
{
}

And the custom class loader checks if a class is tagged as internal. But it's not perfect yet, the drawback of this solution is that the using of internal class is detected at runtime and not when compiling the code, refusing the creation of internal class could create problems in production environment. To avoid this behavior, we can only log a warning instead of refusing the creation.

And to check the not using of internal classes at the development level, we can use JArchitect and create a custom CQLinq query like this:

Java
from t in Types where
t.TypesUsingMe.Where(a=>a.ParentProject!=t.ParentProject).Count()>0 && t.HasAnnotation("internal")
select t

What’s interesting with the custom class loader solution is that we can restrict a package to use only some specified packages.

3. External Framework

OSGi became very popular today, thanks to its modularity approach and its capability to enforce logical boundaries between modules. OSGI is an example of framework using a custom class loader to define many rules related to visibility and accessibility between packages and jars.

OSGI gives us many possibilities to define logical boundaries and emulate the internal behavior, here’s a post describing the OSGI framework.

4. Wait for Java 9

Java 9 will come with jigsaw another alternative to OSGI to simplify modular programming, and in this case, the JRE class loader is modified to restrict the creation of classes depending on configuration files defining the boundaries. This post describes the jigsaw alternative.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



Comments and Discussions

 
-- There are no messages in this forum --