Java: prohibit the use of object references outside the method

I defined a RecordVisitor interface declared as follows:

 public interface RecordVisitor<K, V, Result> { public Result visit(Record<K, V> rec); } 

The idea is that visit implementations will be called with a Record object, will execute their logic and return a result. I would like the implementation to not remove the value of rec and use it outside of the visit call.

The only way I decided to do this is to add state to the Record and throw an IllegalStateException if any method is called in the recording object until it is "active". Then I will write terrible warnings in javadoc and hope that the performers read it.

Is there a more reliable way to prevent the use of the Record object outside the visit method? If possible, I would like to build an interface that leads to compile-time errors if the contract is broken.

+4
source share
2 answers

It is impossible to prevent the developer from storing a reference to the object as part of his visit .

However, there is a more serious philosophical problem. If you do not trust the code that implements the RecordVisitor interface, then why are you using this code? If so, why is this a problem if this code contains a link to an object?

The only way I decided to do this is to add state to the record and throw an IllegalStateException if any method is called on the record object until it is "active".

If you do not trust the programmers who implement your RecordVisitor interface, this is still not enough. There is nothing to prevent the developer from creating a new method

 public void foo() { this.rec.activate(); // Do something, and there is no IllegalStateException this.rec.deactivate(); } 

which on Record will appear as a call from within visit , but will not actually be from inside visit .

+3
source

First take advice from @AdamMihalcin.

Now, if you still want to control access to the Record object, look at the Java Proxy class and its associated InvocationHandler . This allows you to create a proxy object with a recording interface (provided that the recording is an interface). InvocationHandler attached to the proxy then redirects all calls to the interface methods to the real Record object. When the visitor’s call returns, you can call the invalidate() method on the InvocationHandler to prevent call forwarding to the real recording object.

Here is an example of what an InvocationHandler might look like.

 package test.proxy ; import java.lang.reflect.InvocationHandler ; import java.lang.reflect.Method ; import java.lang.reflect.Proxy ; public class CancelableObjectInvocationHandler implements InvocationHandler { private Object _realObject ; public CancelableObjectInvocationHandler ( Object realObject ) { _realObject = realObject ; } public Object invoke ( Object proxy, Method method, Object[] args ) throws Throwable { Object ret = null ; if ( method.getName ( ).equals ( "equals" ) ) { // If we are invoking the equals method, we have to compare the // Invocation Handlers since the Proxies forward the method call boolean isEquals = true ; if ( isEquals ) { isEquals = ( args[0] instanceof Proxy ) ; } if ( isEquals ) { Proxy otherProxy = (Proxy) args[0] ; isEquals = this.equals ( Proxy.getInvocationHandler ( otherProxy ) ) ; } return new Boolean ( isEquals ) ; } else if ( null != _realObject ) { // The object is active, so execute the method call. ret = method.invoke ( _realObject, args ) ; } else { throw new IllegalStateException ( "Attempt to access an invalidated Object" ) ; } return ret ; } public Object getRealObject ( ) { return _realObject ; } protected void invalidate ( ) { _realObject = null ; } } 
+1
source

Source: https://habr.com/ru/post/1401454/


All Articles