Skip to Content

In Java, one almost certainly will see the following statement, when using a larger API:

“When overriding this method, a call to super must be the first (the last) statement of the overriding method”

One will see this quite likely when using frameworks where the overridden method will do some initialization of any kind. Obviously, violating the contract can have severe consequences. There is, however, a quite simple pattern to enforce this. I always wondered that one does not see it more often in books about patterns, as it is very simple, and, by means of object orientation, very straightforward. First, assume an API class:

This pattern can be seen quite often in complex frameworks. A better alternative is:

Since Base.initialize() is final, it cannot be overridden. Instead any subclasser is enforced to use Base.doInitialization() which is called at a well defined point. Furthermore (if that is needed in the concrete case) there is no possibility to hamper with Foo.

I used this pattern when I wrote a specialized TestCase for JUnit tests for UI tests. There had specific actions for tearDown() to be done (like closing erronously opened modal dialogs). Therefore I overrode tearDown() marking it final and introduced a second method for client specific tearDown actions.

To report this post you need to login first.

4 Comments

You must be Logged on to comment or reply to a post.

  1. Valery Silaev
    Richard,

    “When overriding this method, a call to super must be the first (the last) statement of the overriding method”

    Do you know that this is automatically enforced by compiler to object constructors? Then why to have separate method + programming pattern if you have language feature + strict compiler combo???

    Next, your case work for post-initialization in sublass. Pre-initialization will require other sequence that is hard to enforce using similar technique.

    Overall, I firmly believe that documentation is part of API. If we would have programming language that can express all API constraints/contracts using only lnaguage itself, then it will be “perfect language”, i.e. the last invention in programming laguages theory 😉 So I’m voting for having simplier API + good docs in favor of ad-hoc patterns and bloated API.

    Btw, for Java it’s better to have bytecode analyzer that is run as part of build and enforces semantic you described. Checking that no field/method access happens before defined invokevirtual instruction is not that complex.

    VS

    (0) 
    1. Richard Birenheide Post author
      You are right, this is enforced for constructors but not for other methods.

      Note, that this pattern is proposed for particular cases, where post-initialization is required. I am not claiming to cover every case.

      I am not agreeing with you in two points:

      1. I do not think that the API gets bloated. You are simply overriding another method. The original method cannot be overridden and is not longer API in that respect. As well, I have seen many stupid things or abuse even from experienced people, so my favourite is letting the compiler do the job.

      2. I think that using a byte code analyzer during build is (how simple it might be) more complex than using the features the language has to offer.

      Richard

      (0) 
      1. Valery Silaev
        Richard,

        Sure, your solution works perfectly for post-initialization tasks or any __post_processing__ task.

        However, my point was just to pay attention that it’s simpler to enforce contract for __initialization__ tasks using just constructors.

        Well, I agree, “API bloat” is too strong term here. However, any public (even final) and any protected method / field is part of API… 2 instead of one methods here, 3 instead of one there, and when you invoke IDE auto-completion on something like Swing UI control you see what “bloat” means 🙂

        Regarding bytecode analyzer. Well, after more then 4 years with CGLIB and ObjectWeb ASM it looks like quite simple exercise for me. Though I still remeber how complex it was for first time 😉

        VS

        (0) 
        1. Richard Birenheide Post author
          Valery,

          yes, one should use constructors for that task whereever possible. On the other hand, consider the following situation: Using a third party API which made a TCP/IP connection I had a very strange and annoying bug when the connection failed to establish. Only after a few hours of debugging I realized that a class within that API registered itself as a listener in its constructor and the constructor failed afterwards when the connection could not be established. This shows to me that not all initialization can nor should be done in constructors.

          For bytecode analyzer, I have an environment in view like the one I am working in where hundreds of developers are using a centralized build infrastructure. Beside the fact that the central build runs already painfully long, the bureaucratic obstacles to establish central byte code analyzation would be huge.

          Richard

          (0) 

Leave a Reply