views:

603

answers:

3

Right now in some Java code I have something like this

class A {
 void f() {

 }
 A() {
  f();
 }
}

class B extends A{
 @Override
 void f() {
  //do some stuff
  super.f();
 }
}

class C extends B {
 @Override
 void f() {
  //do some stuff
  super.f();
 }
}

I want to have f() called and then iterate upwards through each parent class, running the overridden f(). I do this by calling super.f() explicitly, although I'd like to not have to do this.

The reason why I do this is there post processing that must be done after the constructor in A is reached. And there is state in each class that much be properly init'd, which is why we have the upward trace of f()'s.

So the constructor of A is really

A() {
  //init some state in a
  f(); //run f(), which will depend on the previous operation
}

If I do something like new C(); I want C.f() called, then B.f() called, then A.f() called

Anyway, if there is a smarter way of doing this, I'm open to it.

+1  A: 

As far as I know, there's no way to do this. AspectJ might do something similar to this, but then you'd have to tag it with an annotation, I suppose, which is hardly less work than just calling super.f(). You need to signify that the superclass method is being called, because you need to have the ability to make that decision for each subclass separately - otherwise, you might have a subclass that doesn't want to delegate anything to the superclass at all - so the default is that you just put in the code.

jprete
+3  A: 

Calling non-final methods in a constructor is generally a bad idea - at the very least, I'd suggest you document it heavily. Bear in mind that when f() is called, C's constructor won't have been called - and neither will any variable initializers. The object is only half-initialized, and so methods will need to be written very carefully.

There's no way of implicitly calling super.f() though in normal Java. Given the large warnings I'd be putting around that code, a single statement is far from the end of the world :)

If you want to verify that it's called, you could always check for the results of A.f() in A's constructor immediately after the call - that will check that the call has reached the top level.

Jon Skeet
+1 for "Calling non-final methods in a constructor is generally a bad idea" (from experience :-)
Jim Garrison
I don't need any of the constructors to have been run, as long as the first part of A() is executed, we're in good shape. This is part of a hack to do serialization without using the Serialization interface by using a private namespace. Basically all classes declare the variables they are going to use beforehand, but A init's the private namespace. Thanks for the reply Jon, I figured this wasn't possible, nice to have a second opinion
Mike
+1  A: 

This may help you somewhat - it's a way to enforce that the child class calls the super; this would help you detect developer mistakes where the implementer of a child class forgot to continue the call up the chain to super.f():

class A {
 boolean fDone;

 public final void f() {
  fDone = false;
  doF();
  if (!fDone) {
   throw new IllegalStateException("super.f() was not called");
  }
 }

 protected void doF() {
  //do some operation
  fDone = true;
 }
}

class B extends A {
 protected void doF() {
  //some operation, maybe repeat this pattern of using a flag to enforce super call
  super.doF();
 }
}

So, the child overrides doF(), but is required to call super.doF();

RMorrisey
That's a helpful suggestion, thanks
Mike