4

Is there some type of @annotation, or other method, in Java to enforce method extension, instead of overriding?

To be specific, let's say I have a class Foo:

class Foo {
    public void bar(Thing thing) {
        // ...
    }
}

Is there a way I can enforce, at compile time, that any class X that extends Foo, and also overrides bar, makes a call to super.bar(thing) first?

2
  • 2
    You could probably do that with an annotation processor. Commented Apr 15, 2013 at 18:18
  • @Rob perhaps create an @Extend annotation to use in place of @Override? Commented Apr 15, 2013 at 18:27

5 Answers 5

3

No, you have to explicitly write it.

Side note for constructors: the superclass' nullary constructor will be implicitly called when instantiating the subclass, however many parameters the latter's constructor has.

Sign up to request clarification or add additional context in comments.

2 Comments

note, nullary constructor is implicitly called only when no other constructor is called explicetly (you can call another constructor both from superclass and this class).
@AlexeiKaigorodov ...and a nullary constructor must be available in the super class (either explicitly, or by defining no constructors at all), and it must not be private.
1

You could declare bar to be final, then call an abstract method from bar, which would force subclasses to implement an "extension".

abstract class Foo {
    public final void bar(Thing thing) {
        barImpl(thing);
        overrideMe(thing);
    }

    private final void barImpl(Thing thing) {
        // Original implementation of "bar" here.
    }

    protected abstract void overrideMe(Thing thing);
}

EDIT

I've changedoverrideMe from public to protected so users of Foo can't just call overrideMe instead of bar.

1 Comment

Like I noted on GaborSch's answer, this method only delays the problem somewhat. If there is a second level of inheritance, the overrideMe method acquires the exact same problem as the original bar method.
1

Generally, what you can do is to create a final method, that calls the extendable one.

class Foo {

    @Override
    public final void bar(Thing thing) {
        // super code comes here
        this.doBar(thing);
    }

    public abstract void doBar(Thing thing);

}

When you call

foo.bar(thing);

your super code runs first, then the code from the child class.

This way you can protect your full bar logic, and allow only certain parts to be extended/reimplemented.

Also, it allows you to postprocess the result, or to break up your code to certain subtasks.

2 Comments

I use this sort of pattern all the time, the problem is that it doesn't work for > 1 levels of inheritance. The doBar method would have the same contract/problem as the original bar method, or you would have to start a doDoBar, doDoDoBar, ... paradigm.
@torquestomp that's true, better try to find a proper name for the wrapped logic. Actually I never had to use it in multiple layers.
0

While you cannot force code to call up to its superclass at compile time, it's not too hard to detect at run time when code does not call up to the superclass.

class Foo {
    private boolean baseCalled;
    public final void bar(Thing thing) {
        baseCalled = false;
        barImp(thing);
        if (!baseCalled) {
            throw new RuntimeException("super.barImp() not called");
        }
    }
    protected void barImp(Thing thing) {
         baseCalled = true;
         . . . // base class implementation of bar
    }
}

Note that this extends to multiple levels of inheritance without further elaboration. The method works particularly well for methods that are called from within Foo; in those cases, you can often forgo the final qualifier and redirection to an implementation method, and just define the base class method to set the flag. Clearing the flag would be done at each point of invocation.

The above pattern is used extensively in the Android framework. It doesn't guarantee that super.barImp was called as the first thing in subclass overrides; just that it was called.

Comments

0

You can try to use @AroundInvoke annotation, if you are using EJBs.

By using reflection, you can find the same method in your parent class, and yo can invoke it with the same parameters as the original method was called.

Note, that in this case you must avoid super.bar(thing) calls, otherwise they would be called twice.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.