how to restrict protected method access to only subclasses

It is not possible. You have a choice between protected modifier (subclasses + classes in the same package) and default modifier (classes in the same package). There is no third option.

Also you cannot easily enforce that at runtime as it is not simple to find the class name and package of the calling code. See: How do I find the caller of a method using stacktrace or reflection?

One option is using aspectj. It can even work at compile time to reject code trying to access protected method from the same package while not being a subclass (with a help of declare warning and declare error directives). You probably want to include some compile-time annotation like @SubclassesOnly. See: Compile-time architecture enforcement revisited: AspectJ, Maven and Eclipse and Compile-time checks with AspectJ.


Easy: Remove all other classes from the package, leaving only your base class there.

That will mean the only classes that can access your class are from another package.

In the case that another library copies your package name, you could easily check the package of the caller and assert that it isn't the same as yours:

if (getClass().getPackage().equals(MyBaseClass.class.getPackage())
    throw new IllegalAccessError(); // or similar

FYI getClass() gives you the class of this, which would the subclass's class.

Edited:

To find the caller's class, use this code:

Class<?> callerClass = Class.forName(Thread.currentThread().getStackTrace()[2].getClassName());