2

Is it possible to enforce an overriden method to call the superclass method? Constructors always need to call their superclass constructor. But i want to enforce this on normal methods, without the position of when it is called mattering.

Example:

public class A {

    public void doSth() {
        System.out.println("I must appear on console!");
    }

}

public class B extends A {

    @Override
    public void doSth() {
        System.out.println("Bla!");  // IDE should mark an error, because supermethod is not called.
    }

}
Torhan Bartel
  • 550
  • 6
  • 33

5 Answers5

9

No, that is not possible. It is entirely up to the overriding method to call the superclass method, or not.

However, there is a way to do it, if you want to enforce control.

This is called the Template Method Pattern. Whether the template methods are abstract or stubs (like shown here), depends on whether they must do something, or simply allow something extra to be done.

public class A {
    public final void doSth() { // final, preventing override by subclasses
        beforeDoSth();
        System.out.println("I must appear on console!");
        afterDoSth();
    }
    protected void beforeDoSth() { // protected, since it should never be called directly
        // Stub method, to be overridden by subclasses, if needed
    }
    protected void afterDoSth() {
        // Stub method, to be overridden by subclasses, if needed
    }
}

public class B extends A {
    @Override
    protected void afterDoSth() {
        System.out.println("Bla!");
    }
}

If you then execute new B().doSth(), you'll get:

I must appear on console!
Bla!
Andreas
  • 154,647
  • 11
  • 152
  • 247
  • It's not _entirely_ up to the overriding method. If the super class is designed so that the method returns a type that cannot be created by the subclass, then there is no option but to call the super implementation from the subclass. – Mick Mnemonic Feb 05 '16 at 20:22
  • 1
    @MickMnemonic If you want to nitpick like that ;-), I could respond by saying that overriding method could choose to not call super and return `null`. ;-P – Andreas Feb 05 '16 at 20:31
  • Now _that's_ nitpicking! But good point; the return value should be specified as `@Nonnull` so that no contract-abiding subclass could avoid the `super` call. – Mick Mnemonic Feb 05 '16 at 21:40
2

No, it is not possible. If you allow a method to be overridden at all (by not declaring it or its class final) then you cannot control much of anything about the implementation of methods that override it. You can, however, document that such methods should invoke the superclass's version. There's only so much you can do to protect your users from themselves.

You may also find that there are alternative designs that would suit you better. For example, if you want to allow subclasses to override particular details of a computation, but not to override the whole computation altogether, then you could employ the Template Method pattern. In that case, the computation is driven by one "template" method, which you can declare private or final if you wish, and the customizable details are implemented in a separate, non-final, public or protected, possibly abstract method that the driver method calls where appropriate.

John Bollinger
  • 160,171
  • 8
  • 81
  • 157
1

No, it is not possible. It is up to the overriding method to call or to not call the method that it overrides.

Adam Siemion
  • 15,569
  • 7
  • 58
  • 92
1

Yes, it's possible, given the following constraints:

  • The method has a non-void return type
  • Subclasses (or other classes accessible by the subclasses) cannot create instances of the return type

As @Andreas pointed out, the super call could still be avoided by returning null. In practice, this shouldn't be a problem, but it's reasonable to enforce non-nullness in the contract (super class documentation) and also by using a null-preventing annotation, e.g. @Nonnull, so that any modern IDE can give a compile error when the super class method is not called.

For example:

import javax.annotation.Nonnull;

public class A {

    public static final class Result {
        private Result() {
            // declare constructor private so the class cannot be 
            // instantiated from outside
        }        
    }

    /**
     * Does something.
     * 
     * @return the result; never {@code null}
     */
    public @Nonnull Result doSth() {
        System.out.println("I must appear on console!");
        return new Result();
    }
}

//...
public class B extends A {

    @Override
    public @Nonnull Result doSth() {
        System.out.println("Bla!");

        // only way to get a Result instance is through super.doSth()
        Result res = super.doSth();

        /* manipulate the result as needed */

        return res;
    }        
}
Community
  • 1
  • 1
Mick Mnemonic
  • 7,808
  • 2
  • 26
  • 30
1

Although not strictly Java related, I was looking for an answer to this issue as it relates to Android and found the annotation in the support annotations library called "@CallSuper". It does exactly what you think, and throws a lint error if the subclass does not call the super's implementation of methods annotated with @CallSuper.

That solved my usecase, but again, I know that the solution is strictly tied with Android. Please let me know if that is too far off base and I will remove the answer.

Here is some more documentation on @CallSuper. https://developer.android.com/reference/android/support/annotation/CallSuper.html https://developer.android.com/studio/write/annotations.html (just search for CallSuper and it'll show right up in that second link.

technoplato
  • 3,293
  • 21
  • 33
  • I don't remember in which case i was asking for this, but i'm sure it was android related, so thank you! :) – Torhan Bartel May 03 '17 at 13:00
  • You're quite welcome! I hope you're able to use this in your future projects. Let me know if you run into any other questions. – technoplato May 03 '17 at 14:15