5

I am developing a java API. During my development, I keep facing the following issue:

I have two classes in two different packages. Class A in package x, and class B in package y. I need the class A to access a method M defined in class B. Hence, the modifier that should be used for the method M is public. However, I do not want to allow the developer who will use my API in his/her java application to access the method M. The problem is that the method M has a public modifier as I mentioned, and hence anyone can access it within the API or from outside the API. At the same time, if I decrease the modifier level of the method M to protected or private, the class A will not be able to access the method M because it belongs to a different package. How can I solve this problem? Is my only solution to have A and B in the same package?

Traveling Salesman
  • 2,209
  • 11
  • 46
  • 83
  • Will clients be able to access anything else in class `B`? – cherouvim May 30 '14 at 19:33
  • 2
    You most probably should redesign your code structure if you need something like that. There is no way to achieve what you are looking for. Unfortunately it is a bit too abstract to give a better recommendation and it is probably better suited at programming.se – Stephan May 30 '14 at 19:34
  • There's no language-level construct that will do exactly what you want, unfortunately. Depending on how bad it is if others call `M`, one thing you could do is document it with "Not for external consumption", a la the `com.sun` packages. – kuporific May 30 '14 at 19:45
  • 1
    You could do this with OSGi, but it smells. – chrylis -cautiouslyoptimistic- May 30 '14 at 19:49

5 Answers5

1

Create an interface and expose only that to the public, hiding your implementation. For example:

My implementation (in say, for example, application.jar):

public class Test implements TestInterface {
    public void somePrivateStuff() { }

    public void somePublicStuff() { }
}

Dear world, here is my API (in say, for example, publicAPI.jar):

public interface TestInterface {
    public void somePublicStuff();
}

Other developers would compile against your publicAPI.jar. The runtime implementation would come from your application.jar.

martinez314
  • 12,162
  • 5
  • 36
  • 63
  • This is what I immediately though. Only works if the end user doesnt need to construct the class themselves, of course factories could solve that issue – Richard Tingle May 30 '14 at 22:29
0

The only way to restrict access to specific classes is to make the method protected or package-private. Both only allow access within the package. I would suggest reformatting your package structure.

Rainbacon
  • 933
  • 1
  • 16
  • 24
0

Inside the method, you can insert:

Throwable th = new Throwable().fillInStackTrace();
StackTraceElement element = th.getStackTrace()[TEST BETWEEN 3 AND 5];

if (element.getClassName().startsWith("your.package")) {
  // CONTINUE YOUR METHOD.
}
else {
  // USER ACCESSING FROM AN APPLICATION.
  // THROW EXCEPTIONS, SHUTDOWN THE SYSTEM... DO WHAT YOU WANT.
}

On the second line, test between 3, 4 and 5, and see which one returns the correct element.getClassName().

0

You can split you project into 2: the public API and it implementation. Define 2 interfaces for the class B:

  1. The public interface for your library users (in API project).
  2. Your inner interface that extends the public one and adds method M.

User will be dependent on you API in compilation and will get the implementation in the run-time.

j3ny4
  • 442
  • 2
  • 8
0

You could use reflection. Here's an example.

package b;

public class B {
    private void m() {
        System.out.println("Called m()");
    }
}

and

package a;

import b.B;

import java.lang.reflect.Method;

public class A {
    public static void main(String[] args) throws Exception {
        B b = new B();
        Method m = B.class.getDeclaredMethod("m");
        m.setAccessible(true);
        m.invoke(b);
    }
}

Which outputs

Called m()
kuporific
  • 10,053
  • 3
  • 42
  • 46