3

Suppose I have an inheritance chain where every class extends its superclass by adding a new field and I want every class of that chain to override the toString() method like so:

public String toString()
{
    return super.toString() + "[newfield=" + newfield + "]";
}

If I use an abstract base class then when a class of the inheritance chain becomes concrete by implementing the abstract method all the subclasses from that point on become concrete as well by inheriting the already implemented method.

Is there a way in Java to force every class to override (reimplement) the abstract method even though it has already been implemented higher in the inheritance chain?

emmp
  • 33
  • 4

2 Answers2

3

Short answer: no.

Long answer: you could write a unit test that scans the class path (use a library like reflections for that), loads every subclass of the abstract class and checks for the method using reflection. But there's no way to do it at compile time.

Aside from Java, AspectJ has a hasMethod() pointcut, which could do the check for you, but unfortunately that's only valid for the declare parents advice. Perhaps you could do it in two steps using aspectj:

  • define an interface IllBehaved.
  • define an advice that assigns this interface to classes that extend from your base class but don't have the member
  • then declare a compile error for all types that implement this interface

    pointcut isSubTypeOfYourClass(): within(com.your.BaseClass+);
    pointcut overridesMethod(): hasmethod(public void yourMethodName(..));
    declare parents: isSubTypeOfYourClass() && !overridesMethod()
                     implements com.yourcompany.IllBehaved;
    declare error: isSubTypeOfYourClass() && within(com.yourcompany.IllBehaved+):
                     "Implementation class must override <Foo> method";
    

I haven't tested this, but it should work if you turn on the -XhasMember option. And it's easy enough to integrate aspectj into your build when you use standard tools like Maven, Ant, Eclipse etc.

Sean Patrick Floyd
  • 292,901
  • 67
  • 465
  • 588
  • You can do it at compile time with annotations and a custom annotation processor (if you consider APT to be compile-time). – Eli Acherkan Apr 24 '12 at 13:12
  • @EliAcherkan true, good point. But I guess you could only do it if you have the annotation on all overriding classes, right? Or maybe an annotation marked with `@Inherited` would do the job? – Sean Patrick Floyd Apr 24 '12 at 13:18
  • Good question, I admit I haven't _completely_ thought it through. I was hoping that it'd be enough to mark the topmost class with an annotation, and that APT allows you to either a) find a list of descendants of a given class; or b) invoke your annotation processor on all classes (so that you can check whether the current class's ancestors have a particular annotation). – Eli Acherkan Apr 24 '12 at 13:27
  • @EliAcherkan I'm pretty sure that neither a) nor b) are possible. If your class doesn't have an annotation, apt doesn't see it – Sean Patrick Floyd Apr 24 '12 at 13:36
  • I wasn't aware of this. So maybe APT is not the best tool for this after all :-) – Eli Acherkan Apr 24 '12 at 13:40
2

No, but you could let your classes implement an interface instead of the abstract super class. You might can check on compile time if the class implements the interface, that depends on what you are doing with this classes.

Kai
  • 38,985
  • 14
  • 88
  • 103