Easily enforce open source policies in real time and reduce MTTRs from six weeks to six seconds with the Sonatype Nexus Platform. See for yourself - Free Vulnerability Scanner.

Disclaimer: the following is a devious hack, it should only be used if you know what you’re doing.

As developers, we should only call public APIs. However, the Java language cannot differentiate between public API and private stuff: as soon as a class and one of its method is public, we can reference the former and call the later. Therefore, we are exposed to the Dark Side of the Force, and sometimes tempted to use it.

A good example of this terrible temptation is the sun.reflect.Reflection.getCaller(int) method. As its name implies, this evil piece returns which class called your current code, letting you tailor your code behavior depending on the calling class. The Dark Side can be seductive indeed!

This way, we can check whether some caller has some property and let it invoke our stuff or not accordingly. For example, let’s design a code piece that can be invoked only from “privileged” code. Such privileges include: be a specific class, come from a specific package, be annotated with a specific annotation, etc. The following code uses the third option.

The int parameter in the getCallerClass() method refers to the number of frames up the calling stack. Index 0 is Reflection.getCallerClass() itself, while index 1 is our restricted constructor, so that real work should begin at 2.

The algorithm is to search up the stack until either the whole stack has been browsed and no privileged code has been found or stop when the matching annotation is found. In the former case, throw an exception, in the latter, do the job as expected.

Of course, this algorithm shouldn’t be hard-coded but factorized in a aspect and injected at some determined pointcut (perhaps a @Restricted annotation?)

Ok, but what use-case does this solve? Well, I’ve always thought about what requirements Hibernate (or JPA) put on your design. One of such requirement is to provide a no-arg constructor, for the framework to instantiate. After that, it can use setter or inject attributes directly. Unfortunately, this conflicts with my desire to provide immutable objects that have all mandatory parameters in the constructor. A basic solution would be to provide both constructors but document them accordingly (/** Do not use: this one is for Hibernate. */). However, to really enforce this rule, you’d probably need to use getCallerClass() with a check on an org.hibernate package.