javadesign-patternsbuilder-pattern

How to ensure that builder pattern is completed?


EDIT: I am not worried about being called in the wrong order since this is enforced through using multiple interfaces, I am just worried about the terminal method getting called at all.


I am using a builder pattern to create permissions in our system. I chose a builder pattern because security is so important in our product (it involves minors so COPPA et al), I felt it was imperative that permissions be readable, and felt that the readability was of the utmost importance (i.e. use a fluent-style builder pattern rather than a single function with 6 values).

The code looks like this:

 permissionManager
      .grantUser( userId )
      .permissionTo( Right.READ )
      .item( docId )
      .asOf( new Date() );

The methods populate a private backing bean, that upon having the terminal method (i.e. asOf ) commit the permission to the database; if that method does not get called nothing happens. Occasionally developers will forget to call the terminal method, which does not cause a compiler error and is easy to miss on a quick reading/skimming of the code.

What could I do to prevent this problem? I would not like to return a Permission object that needs to get saved since that introduces more noise and makes permission code harder to read, follow, track, and understand.

I have thought about putting a flag on the backing which gets marked by the terminal command. Then, check the flag in the finalize method and write to the log if the object was created without persisting. (I know that finalize is not guaranteed to run, but it's the best I can think of.)


Solution

  • There is now an annotation processing based compiler plugin, that will check that for you, and throw compilation error, if the method is not present: Fluent API sentence end check.

    You can either annotate your final method with @End annotation, or if you do not control the class, you can still provide a text file with fully qualified method name(s), and get the check working.

    Then Maven can check during compilation.

    It only works in Java 8, upwards, because it uses new compiler plugin mechanism, introduced there.