javaarchitecturemethodsconstraintsinvariants

Imposing constraints or restrictions on method body, in Java


Context (Edit)

Some clarification was on demand, so I'll try to sum up what influences the question.

Examples:

  1. Think of a small game, where almost everything is implemented and managed by the already implemented classes. The only thing left for the programmer to do, is to write a method, or a couple of them, that describe what the character will do (walk, change direction, stop, inspect object). I would want to make sure that their methods (possibly marked with an annotation?) just walk, or changeDirection, or calculate diff = desiredValue - x, and not, say, write to some file, or open a socket connection.

  2. Think of a transaction manager. The manager would be provided by this library, as well as some constant attributes of transactions (their isolation level, time-outs, ...). Now, the programmers would like to have transactions and use this manager. I would want to make sure that they only read, write, commit, or rollback on some resources, known to the manager. I wouldn't want them to launchRocket in the middle of the transaction, if the manager does not control any rockets to launch.

The Problem

I want to impose some invariants / restrictions / constraints on the body of a method (or group of methods), to be later implemented by some other programmer, in some other package/location. Say, I give them something along the lines of:

public abstract class ToBeExtended {
    // some private stuff they should not modify
    // ...
    public abstract SomeReturnType safeMethod();
}

It is important (probably imperative), for the purposes of this project, that the method body satisfies some invariants. Or rather, it is imperative that the set of commands this method's implementation uses is limited. Examples of these constraints:

Put another way:

I've been looking through Annotations, and there seems to be nothing close to this.
My options so far:

  1. Define some annotation, @SafeAnnotation, and apply it to the method, defining a contract with the implementer, that he will follow the rules imposed, or else the system will malfunction.

  2. Define an Enum with the allowed operations. Instead of exposing the allowed methods, only a method is exposed, that accepts a list of these enum objects (or something similar to a Control Flow Graph?) and executes it, giving me the control of what can be done.

Example:

public enum AllowedOperations { OP1, OP2 }

public class TheOneKnown {
    public void executeMyStuff (List<AllowedOperations> ops) {
        // ...
    }
}

My Question

Is there any feature in the language, such as annotations, reflection, or otherwise, allowing me to inspect (either at compile time or runtime) if a method is valid (ie, satisfies my constraints)?
Or rather, is there any way to enforce it to call only a limited set of other methods?

If not (and I think not), would this second approach be a suitable alternative?
Suitable, as in intuitive, well designed and/or good practice.

Update (Progress)

Having had a look at some related questions, I'm also considering (as a third option, maybe) following the steps given in the accepted answer of this question. Although, this may require some rethinking on the architecture.

The whole idea of using annotations to impose restrictions seems to require implementing my own annotation processor. If this is true, I might as well consider a small domain-specific language, so that the programmer would use these limited operations, later translating the code to Java. This way, I would also have control over what is specified.


Solution

  • I think that the direction in this question is good.

    In addition to the above, I recommend 2 options:

    Give the method a controller, that would contain the functions it can call

    For example:

    public void foo(Controller ctrl) {
    }
    
    public class Controller {
       public boolean commit();
       public boolean rollback();
    }
    

    This can give the user a handle, what operations are allowed.

    Use an Intent-like command pattern

    In Android, the components of the system are quite closed. They cannot directly communicate to each other, they only can fire an event, that "this happened", or "I want to do that".

    This way the set of the usable commands are not restricted. Usually, if the methods do only small business logic, that is enough.