How to prevent public methods from being called from specific classes - java

I have an existing class into which I want to add a method. But I want the method to be called only from a specific method from a specific class. Is there any way that I can prevent that call from other classes/methods?
For example, I have an existing class A
public final class A
{
//other stuff available for all classes/methods
//I want to add a method that does its job only if called from a specific method of a class, for example:
public void method()
{
//proceed if called from Class B.anotherMethod() else throw Exception
}
}
One way of doing this is getting the StackTrace inside the method() and then confirming the parent method?
What I am looking for is a solution that is more clean and advisable solution like a pattern or something.

To be honest, you have painted yourself into a corner here.
If classes A and B are not related and not members of the same package, then visibility won't solve the problem. (And even if it did, reflection can be used to subvert the visibility rules.)
Static code analysis won't solve the problem if the code can use reflection to call the method.
Passing and checking B.this as an extra parameter to A.method(...) doesn't help because some other class C could pass a B instance.
This leaves only the stacktrace approach1... or giving up and relying on the good sense of the programmer2 not to call methods that they shouldn't.
The ideal solution is to revisit the design and/or coding decisions that got you into this mess.
1 - See other answers for examples that use annotations, a security manager, etc to conceal the stacktrace stuff from the application programmer. But note that under the hood you are adding probably hundreds, possibly thousands of instructions overhead per method call.
2 - Do not underestimate the programmer's good sense. Most programmers, when they see advice not to call some method, are likely to follow that advice.

The right way to do this would be a SecurityManager.
Define a permission which all code which wants to call A.method() has to have, and then make sure only B and A have that permission (this also means that no class has AllPermission).
In A, you check this with System.getSecurityManager().checkPermission(new BMethodPermission()), and in B you call the method inside of AccessController.doPrivileged(...).
Of course, this requires that a security manager is installed (and it uses suitable policies) - if it isn't, all code is trusted and everyone can call everything (if necessary, with Reflection).

You might consider using an interface. If you're passing in the calling class, you can confirm that the class is of the appropriate type.
Alternatively, if you're using Java, you can use "default" or "package" level access (e.g. void method() vs. public void method()). This will allow your method to be called by any class inside the package and does not require that you pass the class to the method.

The only way to check for sure at run time is to take a stack trace. Even if its private you can access the method via reflections.
A simpler way to do this would be to check usages in your IDE. (provided its not called via reflections)

As others have mentioned, using the stack trace is one way to implement the functionality that you are looking for. Generally, if one needs to "block" callers from a public method, it could be a sign of poor design. As a rule of thumb, use access modifiers that restrict the scope as much as possible. However, making a method package-private or protected is not always an option. Sometimes, one may want to group some classes in a separate package. In that case, the default (package-private) access is too restrictive, and it usually does not make sense to subclass, so protected is not helpful either.
If restricting calling to certain classes is desired, you can create a method like:
public static void checkPermission(Class... expectedCallerClasses) {
StackTraceElement callerTrace = Thread.currentThread().getStackTrace()[3];
for (Class expectedClass : expectedCallerClasses) {
if (callerTrace.getClassName().equals(expectedClass.getName())) {
return;
}
}
throw new RuntimeException("Bad caller.");
}
Using it is very simple: just specify what class(es) can call the method. For example,
public void stop() {
checkPermission(ShutdownHandler.class);
running = false;
}
So, if the stop method gets called by a class other than ShutdownHandler, checkPermission will throw an IllegalStateException.
You may wonder why checkPermission is hard-coded to use the fourth element of the stack trace. This is because Thread#getStackTrace() makes the most recently called method the first element. So,
getStackTrace()[0] would be the call to getStackTrace itself.
getStackTrace()[1] would be the call to checkPermission.
getStackTrace()[2] would be the call to stop.
getStackTrace()[3] would be the method that called stop. This is what we are interested in.
You mentioned that you want methods to be called from a specific class and method, but checkPermission only checks for class names. Adding the functionality to check for method names requires only a few modifications, so I'm going to leave that as an exercise.

Make proper use of protected

The standard way to do this in java is to put Class B and Class A in the same package (maybe a subpackage of your current application) and use the default visibility.
The default java visibility is "package-private" which means everything in that package can see your method, but nothing outside that package can access it.
See Also:
Is there a way to simulate the C++ 'friend' concept in Java?

Assuming that you only need to apply this restriction to classes within your project, static analysis could work for you - for example an ArchUnit test:
package net.openid.conformance.archunit;
import com.google.gson.JsonElement;
import com.tngtech.archunit.base.DescribedPredicate;
import com.tngtech.archunit.core.domain.AccessTarget;
import com.tngtech.archunit.core.domain.JavaClass;
import com.tngtech.archunit.core.domain.JavaClasses;
import com.tngtech.archunit.core.importer.ClassFileImporter;
import com.tngtech.archunit.lang.ArchRule;
import net.openid.conformance.testmodule.OIDFJSON;
import org.junit.Test;
import static com.tngtech.archunit.core.domain.JavaCall.Predicates.target;
import static com.tngtech.archunit.core.domain.JavaClass.Predicates.assignableTo;
import static com.tngtech.archunit.core.domain.properties.HasName.Predicates.*;
import static com.tngtech.archunit.core.domain.properties.HasOwner.Predicates.With.owner;
import static com.tngtech.archunit.lang.conditions.ArchPredicates.are;
import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.noClasses;
public class PreventGetAs {
#Test
public void doNotCallJsonElementGetAs() {
JavaClasses importedClasses = new ClassFileImporter().importPackages("net.openid.conformance");
JavaClasses allExceptOIDFJSON = importedClasses.that(DescribedPredicate.not(nameContaining("OIDFJSON")));
ArchRule rule = noClasses().should().callMethodWhere(
target(nameMatching("getAs[^J].*")) // ignores getAsJsonObject/getAsJsonPrimitive/etc which are fine
.and(target(owner(assignableTo(JsonElement.class)))
)).because("the getAs methods perform implicit conversions that might not be desirable - use OIDFJSON wrapper instead");
rule.check(allExceptOIDFJSON);
}
}

You can do it by using annotations and reflection. I will report a similar case, i.e. the case where you can let the method being called only by specific methods from extenal classes. Suppose that the class that must be "protected" by a whatsoever invocation of the its public methods is Invoked, while Invoker is the class tha has a method enabled to invoke one or more methods from Invoked. Then, you can do something like reported in the following.
public class Invoked{
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public static #interface CanInvoke{}
public void methodToBeInvoked() {
boolean canExecute=false;
try {
//get the caller class
StackTraceElement element = (new Throwable()).getStackTrace()[1];
String className = element.getClassName();
Class<?> callerClass = Class.forName(className);
//check if caller method is annotated
for (Method m : callerClass.getDeclaredMethods()) {
if (m.getName().equals(methodName)) {
if(Objects.nonNull(m.getAnnotation(EnabledToMakeOperationRemoved.class))){
canExecute = true;
break;
}
}
}
} catch (SecurityException | ClassNotFoundException ex e) {
//In my case does nothing
}
if(canExecute){
//do something
}
else{
//throw exception
}
}
}
and the Invoker class is
public class Invoker{
private Invoked i;
#Invoked.CanInvoke
public void methodInvoker(){
i.methodToBeInvoked();
}
}
Note that the method that is enabled to invoke is annotated with the CanInvoke annotation.
The case that you requested is similar. You annotate the classes/method that cannot call the public method and then you set to true the canExecute variable only if the method/class is not annotated.

You can use a tool like Macker and add it to your build process to check some rules are respected, like
<?xml version="1.0"?>
<macker>
<ruleset name="Simple example">
<access-rule>
<deny>
<from class="**Print*" />
<to class="java.**" />
</deny>
</access-rule>
</ruleset>
</macker>
It will NOT prevent you from writing wrong code but if you use Maven or another build system it can raise an error during your build process.
This tools work at a "class" level not at a "method" level but I do not see the point of preventing the call of only one method from a certain class ...

I realise your use case states 'specific method in specific class', but I don't think you can reliably solve this at design time (and I can't think of a use case where this would have to be enforced anyway).
The following example creates an easy design time solution for restricting the access of a class' method to a particular class. It can, however, be easily extended to multiple allowed classes.
It is achieved by defining a public inner class with a private constructor that acts as a key to the method at hand. In the following example the class Bar has a method that should only be called from an instance of the Foo class.
Class Foo:
public class Foo
{
public Foo()
{
Bar bar = new Bar();
bar.method(new FooPrivateKey());
}
public class FooPrivateKey
{
private FooPrivateKey()
{ }
}
}
Class Bar:
public class Bar
{
public Bar()
{
}
public void method(FooPrivateKey fooPrivateKey)
{
if(fooPrivateKey == null)
{ throw new IllegalArgumentException("This method should only be called from the Foo class.");}
//Do originally intended work.
}
}
I don't think this is by any means safe for things like reflection or even things like FooPrivateKey.class.newInstance(), but this will at least warn the programmer a little more obtrusively than a simple comment or documentation, while you don't have to look in to more complicated things like what was suggested by people like Roberto Trunfio and Ronan Quillevere (which are perfectly viable answers as well, just too complicated for most situations in my opinion).
I hope this is sufficient for your use case.

Related

How to capture all mockito spied class method invocations without counting inner delegations

Assuming that with a class like:
public class A {
public void smth {
}
public void smth2 {
smth();
}
}
We spy it with mockito and make a simple call :
A spiedA = spy(new A());
spiedA.smth2();
After that when we want to retrieve call count:
Mockito.mockingDetails(spiedA).getInvocations().size()
And it returns two calls as expected. But i want to only register outside calls without inner delegations. Is there possibility to achieve the result i demand? If only Mockito.Invocation could provide with call stack i would filter it out.
There is Location location field in Invocation class. In has actually stack trace inside (which is actually private field, so you should make it available through reflection). And after that you can grab required information, something like that:
((LocationImpl)((LinkedList<Invocation>) invocations).get(1).getLocation()).stackTraceHolder.stackTrace
But I would really not recommend to do that, because you would not want to maintain that test in the future.
You can extract smth() into different class and spy on it if you really need.
Ok problem solved. Wrapped in java.lang.reflect.Proxy with custom invocation handler.

Testing a method which calls private void method inside using mockito

I want to test a method which internally calls a void method.
Below is the code
public String process(MKSConnectionParams mksConnectionParam, IProgressMonitor progressMonitor) throws Exception {
if (null != progressMonitor) {
progressMonitor.beginTask("Starting the creation of report", 100);
}
if (null == mksConnectionParam) {
initialize(MksLibFactory.getDefault());
}
else {
initialize(mksConnectionParam, MksLibFactory.getDefault());
}
--------------
}
public void initialize(MKSConnectionParams mksConnectionParam, IMksLibrary mksLibDefault) throws Exception {
paramMKSConnectionParams = mksConnectionParam;
GlobalConstants.hostName = paramMKSConnectionParams.hostname;
GlobalConstants.port = String.valueOf(paramMKSConnectionParams.port);
try {
localISi = mksLibDefault.getSi(paramMKSConnectionParams);
localIIm = mksLibDefault.getIm(paramMKSConnectionParams);
}
catch (MksLibException | AuthenticationError e) {
throw e;
}
ProjectInfo prjInfo = localISi.getProjectInfo(pathToPj);
projRevCmd = prjInfo.getConfigPath().getConfigPath() + "#b=" + projectRevision;
}
I am writing mockito test case for process() method. Testing is getting failed when initialize(mksConnectionParam, MksLibFactory.getDefault()) is called. It is because in the process we are calling real mks connection and I am passing dummy user name and password.
We aren't able to mock this initialize method. Is there any way to do this?
Small pseudocode would be of great help.
Earlier I had initialize method as private. Would changing it to public make any difference?
There are several ways to test this scenario, and different people would advocate different approaches, mostly based on personal preference.
Notice that testing this, will require changes in the code of the class you're testing (I believe you neglected to mention its name). There is one exception, and that's if you're using PowerMock. I won't go into the details here, but you find out more on how to incorporate it into your mockito code here.
Back to regular testing methods, the problem is that you're using the real IMksLibrary instead of a mock, and that's because you obtain a reference to it inside the process method. Here are a few method that you might want to consider:
Change the signature of the process method to receive the reference to the IMksLibrary instance, so that the test code can supply a mock of it
Instead of creating the reference inside the process method inject a reference to the class, either by using some DI framework (e.g. Spring, Guice, CDI, etc.), or as a constructor parameter
Create a protected method called something like getIMjsLibraryInstance() in the class, that will return MksLibFactory.getDefault(), and use it instead of the explicit code (this is the Extract Method refactoring that can be automatically done by most IDEs for Java nowadays). In the test code, you need to create a subclass (this is why it's my least favorite method) which overrides this method and returns a mock, and test the subclass instead of the real class. Notice that this is the ONLY method that you should subclass
You might feel deterred from using the third method, since in effect, you're not really testing the class that you meant to test (but rather a subclass of it). I tend to agree that this has a bed smell to it. However, keep in mind, that unlike the other two methods, this will not require any changes to the clients of the class (this is a pretty strong argument in favor of it).
There are other methods that you can use, but they are pretty similar in nature to the first two methods, and they also require some changes in the code.
If you feel that any "regular" method of testing is not good enough (due to code changes or whatever other reason), you are welcomed to take a look at PowerMock, which will enable you to intercept the static method call that returns the IMksLibrary instance, and return a mock instead. A word of caution though. There are some serious coupling that happens when these type of solutions are used, so it is usually not highly recommended, unless you are really in a dire need.

Run extra code for any method in a class

I have some code I want to run every time any method is invoked in a specific Java class, but don't want to touch the actual method bodies. This is because there are a lot of methods that change frequently, and the people programming these methods shouldn't have to worry about adding my code to every method.. even if it is just a single line that calls another method.
I can't think of a way to achieve this with inheritance, so I was wondering if it is possible with reflection? Or even at all?
It's possible to get a list of methods in a class, inspect their properties and even invoke them. But I'm not seeing anything that lets you attach extra code, such as an event handler for example. Maybe Java is the wrong language for something like this..
This is very common behavior, where Aspect Oriented Programming is definitely the right thing to use.
But I also get impressed with how the famous CMS does it.
For each class which contains the concrete method around, you can have a property (List of methods) which contains the code you want to execute before the method call.
You can write a registerBeforeCall(Method m) method which takes a method and adds to teh list.
Your method should contain a for loop at the first line(which goes through the list of methods) and invoke each of the method one by one.
Do not forget to put a try and catch and ignore the exception if there is any in the invocations.
For e.g. :
public void myActualMethod(){
for(Method m : registeredMethodsToCallBeforeActualCode){
m.invoke();
}
//my actual code
// here you can also write a for loop to execute all the methods which you want to call after your actual code is executed.
}
This approach is not very special, but is widely use, when you do not choose AOP.
one way to implement it by inheritance is:
public SuperClass {
public void doSomething() {
doBefore();
doSpecific();
doAfter();
}
protected abstract void doSpecific();
}
public SubClass extends SuperClass {
protected void doSpecific() {
System.out.println("Do specific implementation....");
}
}
public static void main(String[] args) {
SuperClass clazz = new SubClass();
clazz.doSomething();
}

How to override instance/concrete class's method runtime? (e.g. reflection, cglib)

What I wanna do is a method that can
generate instance of Class X (a class variable passed in arg) and
override some of it's method
More specifically, the parent class X I want to override contains
Contains no default constructor (e.g. all constructors with args)
Constructors calling non-private method within the same class
Originally I thought it's quite simple to use reflection or something similar,
Then I found there's limitation on implementing my requirement.
For refection: Can only override "interface" via java.lang.reflect.Proxy
http://download.oracle.com/javase/1.3/docs/guide/reflection/proxy.html
for cglib: it cannot create instance of no default constructor and constructor calling non-private member methods
http://insufficientinformation.blogspot.com/2007/12/spring-dynamic-proxies-vs-cglib-proxies.html
I think this is achievable, since Mockito can do all kinds of method injection runtime.
Please anyone give some advise, Thanks.
The pseudo-code I image is like this:
createAndOverride(Class X) {
X newObj = X.newInstance(args) {
#override
methodOfX(args2) {
...
}
}
return newObj;
}
Original problem scenario
I was intended to test a Class which has several methods calling X1.get(), X2.get(), X3.get()
In some test case, I need to make Xn.get() to return something I can control for test (e.g. null)
Due to below constraint:
But due to mock tool restriction to JMock 1.0 (I have no control :( ), so I cannot just simply mock Xn.get() to returns "someSpecifiedObjects"
Xn has no null constructors and constructors calling non-private member
My workaround is self made Xn Class and pass them to test case to let Cn.get() to be expected
code example:
ClassToTest.SomeMethod(new X1() {
#override
get() {
return someSpecifiedObjects;
}
});
And this kind of thing is spread-ed over the Test Case.
Therefore, In order to reduce duplicate code, I would like to build a method to generate Xn instance with specified overrided method for test. e.g.
X1 x1 = createAndOverride(X1);
Then, the problem of this post comes
are you looking for something like javassist? You can instrument code and inject your methods at runtime. I personally try to avoid byte code manipulation as much as possible. Can you not have these overrides in your code base rather than doing on the fly? May be something like wrappers?
So what I think you need is a similar functionality to C#'s Reflection.Emit:
Using Reflection.Emit to create a class implementing an interface
Java Equivalent of Reflection.Emit
Dynamically Create Java Classes With JavaClassCreator
While I haven't done this myself, I think you should be able to use reflection/emission and dynamic type creation in order to achieve what you're looking for. However, I would still like to mention that if you're trying to test "functionality" that's not int he code path of the function you're testing, then you probably shouldn't be testing it at all. For example:
SomeObjectInterface get()
{
if(_someObjectStateIsSet)
{
// Return a concrete implementation A
return new ConcreteImplA();
}
else
{
// Return a concrete implementation B
return new ConcreteImplB();
}
}
In this case get has no code path that would return null, so you shouldn't need to test for null. I'm not sure if I understood your question 100% correctly, especially why you're testing for null, but consider the above advice and see what works for you.

Change private member to default for testing

Is that good idea to change private class members to default(package access) for testing their behavior? I mean test case should destinate in test directory but in same package as tested member's class.
EDIT: All you guys tell the true. But classes have helper private methods often. And these methods can be complicated so need to be tested. And that is too bad - to test public methods for ensure correct working for private complicated methods. Don't you think so?
I generally prefer writing my classes and tests in a way that writing the tests against the public API makes sense. So basically I'm saying if you need to access the private state of your class under test you're probably already too involved in the internals of that class with your test..
No, it isn't. Because changing the test object may change the result. If you really need to call private members or methods during test, it's safer to add an accessor. This still changes the class, but with a lower risk. Example:
private void method() { /* ... */ }
// For testing purpose only, remove for production
#Deprecated // just another way to create awareness ;)
void testMethod() {
method();
}
OK - one more solution, if you need to test private methods: you can call any method with reflection and instantiation API.
Assuming, we have:
public class SomeClass {
private Object helper(String s, String t) { /* ... +/ }
}
then we can test it like
#Test public void testHelper() {
try {
SomeClass some = new SomeClass();
Method helperMethod = some.getClass().getDeclaredMethod("helper", String.class, String,class);
helperMethod.setAccessible(true);
Object result = helperMethod.invoke(some, "s", "t");
// do some assert...
catch(Exception e) {
// TODO - proper exception handling
}
}
I understand what you mean about needing to test private methods, and I also see why people say only test the public methods. I have just encountered some legacy code that has a lot of private methods, some of which are called by public methods, but some are threads, or called by threads, which are kicked off when the object is constructed. Since the code is riddled with bugs and lacks any comments I am forced to test the private code.
I have used this method to address the issue.
MainObject.cs
class MainObject
{
protected int MethodOne(); // Should have been private.
....
}
TestMainObject.cs
class ExposeMainObject : MainObject
{
public int MethodOne();
}
class TestMainObject
{
public void TestOne()
{
}
}
Since the test objects aren't shipped I can't see a problem with it, but if there is please tell me.
Testing trumps privacy modifiers. Really, how often is a bug caused by having "a little too much" visibility for a method? Compared to bugs caused by a method that was not fully tested?
It would be nice if Java had a "friend" option, like C++. But a limitation in the language should never be an excuse for not testing something.
Michael Feathers chimes in on this debate in "Working Effectively with Legacy Code" (excellent book), and suggests that this may be a smell of a sub-class that wants to be extracted (and have public methods).
In our shop (~ 1M LOC), we replace 'private' with '/TestScope/' as an indicator that a method should be effectively private, but still testable.
Trying to circumvent 'private' with reflection is IMHO a smell. It's making the tests harder to write, read, and debug in order to retain a 'fetish' of privacy, which you're working around anyway. Why bother?

Categories