JavaBean Components Considered Evil

Introduction

If you’re reading this, you’ve likely spent the last few years of your programming life following the ever-present JavaBean paradigm. That’s just handy dandy for type-safe configuration, but it wreaks havoc on your application security.

Why is that? The answer is simple: it opens up the possibility of components being in an unsafe state. Which is bad.

Required reading

I assume you are at least passingly familiar with the JavaBeans pattern, basic component-oriented design and the “design by contract” principle. If not, read the Design Patterns book and some bits on the avalon website.

Unsafe state defined

We say that a component is in an unsafe state when it is not capable of fulfilling the contract of its work interface. Here is a trivial example of a component class that will always result in instances that are in an unsafe state:

  // Example 1                                                (fragments)
  public interface MyContract
  {
    public void doSomeStuff();
  }
  public class MyComponent implements MyContract
  {
    public void doSomeStuff()
    {
      throw new UnsupportedOperationException();
    }
  }

More realistically, a component can be in an unsafe state when it has been constructed, but not yet initialized or configured. For example:

  // Example 2                                                (fragments)
  public class MyComponent implements MyContract
  {
    private MyHelper helper;

    public void setHelper( MyHelper h )
    {
      Assert.assertNotNull( "The helper may not be null!", h );
      helper = h;
    }

    private void doSomeStuff()
    {
      helper.helpDoSomeStuff();
    }
  }

  // elsewhere...
  MyContract comp = new MyComponent();                             // 1
  try {                                                            // 2
    comp.doSomeStuff(); // results in NullPointerException         // 3
  } catch( Exception e ) {}                                        // 4
  comp.setHelper( new MyHelperImpl() );                            // 5
  comp.doSomeStuff();                                              // 6

In this example, the component instance ‘comp’ is in an invalid state on the lines marked 1 through 4. Line 5 corrects this, and the fact that line 6 does not cause an exception proves that the component is, at that point, no longer in an invalid state.

Unsafe states should be avoided!

Clearly, we do not want to use any component instance until it is in a safe state. We should look for a mechanism that ensures that client components will not be able to call any method on any component in an unsafe state.

Use constructors to avoid unsafe state

Fortunately, a powerful and flexible safety mechanism is built right into the java language: the constructor. The suggestion I want to make in this essay is simple: use constructors to avoid unsafe state. That may sound trivial, and it is. We are specifying a contract surrounding the constructor:

“On successfully leaving a constructor, a component may not be in an unsafe state”.

But the components in the example above are in blatant violation of that contract. Fortunately, this is trivial to fix:

  // Example 3                                                (fragments)
  public class MySafeComponent implements MyContract
  {
    private MyHelper helper;

    public MySafeComponent( MyHelper h )
    {
      Assert.assertNotNull( "The helper may not be null!", h );
      helper = h;
    }

    private void doSomeStuff()
    {
      helper.helpDoSomeStuff();
    }
  }

In this example, we’ve only had to change one line of code to make this work. Most realistic components need more than just a helper before they can be considered safe, but the changes to existing beans are quite often just as trivial. Usually the use of the constructor results in less typing!

Note that the assertion statement is important: if it is omitted, the component could be unsafe after returning from the constructor:

  // Example 4                                               (fragments)
  MyContract comp = new MySafeComponent( null );                    // 1
  comp.doSomeStuff(); // results in NullPointerException            // 2

With consistent application of this simple contract applied to all your constructors, you are totally sure that all references to all components in your system are always to components in a safe state. This is a re-assuring fact. And all this from following a simple coding pattern!

JavaBeans are evil

Many JavaBeans do not follow this pattern. Most will use an empty constructor, then use “setters” (as in example 2) to bring a component into a safe state. This is a bad idea, mainly because your average guaranteed-to-be-safe contract is far less simple:

“For each new instance of this component, you must call each of the setHelper(), setOtherHelper(), setConfig(), …, setXXX() methods exactly once to bring it into a safe state.”

Furthermore, these contracts vary on a per-class basis. Some classes might require all setXXX() methods to be called, others may be in a safe state even if some of its setXXX() methods have never been called. A user of such a JavaBean must figure out these contractual specifics, often via a little trial and error.

JavaBeans really are evil

Chances are, that you, will be in strong disagreement with what I just wrote. After all, there’s various solutions out there which work just as well and avoid all thes hassles. Right? Well, let us take a look…

Alternative: use a Factory

This idea is pretty simple as well: let something else (not the component author) make sure that all references to all components are always to components in a safe state. You get a reference to a component instance only by asking the factory/container for it, and the factory/container will guarantee that the instance is not in an unsafe state. That usually looks like somewhat this:

  // Example 5                                               (fragments)
  public interface Factory
  {
    public Object getInstance();
  }
  public class MyComponentFactory implements Factory
  {
    public Object getInstance()
    {
      MyComponent comp = new MyComponent();
      comp.setHelper( new MyHelperImpl() );
      return comp;
    }
  }
  public class MyComponent implements MyContract
  {
    // package access
    MyComponent() { /* ... */ }

    /* ... */
  }

  // elsewhere...
  ComponentFactory factory = new MyComponentFactory();
  MyContract comp = (MyContract)factory.getInstance();

The contract associated with the factory is this:

“The return value of getInstance() will be a component that is never in an unsafe state”

Variations on this theme include static factories and factory methods. All of them require another work interface (Factory) and an implementation of that interface (inside the component itself in the case of the factory method), including possibly association of that implementation with the component implementation, and travelling of that association by the client component. (In other words, the client needs to find a reference to the factory and know how to deal with it).

That’s considerably more typing. Also note that, in most realistic examples, you need a typecast. While this is usually not a big deal, it just opens a tiny little window for bugs.

I am not saying that the Factory pattern is a bad pattern. But using it merely to avoid having to pass in state through the constructor is not a very good idea, especially not when the use of factories is optional.

Alternative: use a framework

You can take the factory approach further and delegate the instantation and setup of a component to a sort of “generic factory” that also happens to do lots of other things: a container. A sweet example of such a container is the Spring framework. Most uses of the spring framework revolve around the component user creating or modifying an xml file. This xml file is read in by the framework at runtime and component instances are created based on the xml file. Here’s how you could use Spring with example 2:

  // Example 5                                               (fragments)
  <?xml version="1.0"?><!-- config.xml -->

   <!DOCTYPE beans PUBLIC  "-//SPRING//DTD BEAN//EN"
     "http://www.springframework.org/dtd/spring-beans.dtd">

   <beans>
     <bean id="helper" class="MyHelperImpl"/>
     <bean id="my" class="MyComponent">
       <property name="helper"><ref bean="helper"/></property>
     </bean>
   </beans><!-- end of config.xml -->

  // somewhere else...
  InputStream conf = getClass().getResourceAsStream("config.xml");
  factory = new XmlBeanFactory( conf );
  factory.preInstantiateSingletons();
  MyContract comp = (MyContract)factory.getBean( "my",
    MyContract.class );
  comp.doSomeStuff();                                                // 5

Unfortunately, this does not solve anything; it just moves the problem into the xml file. Consider

  // Example 6                                               (fragment)
  <beans>
    <bean id="helper" class="MyHelperImpl"/>
    <bean id="my" class="MyComponent">
      <!-- forgetting the setHelper() here -->
    </bean>
  </beans>

it suffers from the exact same problem we saw in example 2: there will be a NullPointerException on line number 5 if you use the fragment from example 6.

Note that this is not a problem with or a bug in the Spring framework. How could the framework possibly know that it is supposed to call the setHelper() method? There is simply no way for the framework to satisfy the desired contract

“The return value of getBean() will be a component that is never in an unsafe state”

since it doesn’t know about the specific contract surrounding the MyComponent bean

“For each new instance of this component, you must call the setHelper() method exactly once to bring it into a safe state.”

Of course, there’s ‘workarounds’, and many have been proposed. One that seems to be popular is the use of attributes:

  // Example 7                                               (fragment)
  /** @@Required */
  setHelper( Helper h } { /* ... */ }

where we expect the container to find and interpret the ‘@@Required’ attribute and have it make sure this method is called before agreeing to return an instance. Again, this just moves the problem: now a programmer might forget to add the attribute.

It is just not going to work.

PicoContainer

PicoContainer is a container that is in many ways a lot like spring (only its a lot smaller and has a lot less features). One of the cool things about Pico is its ability to call a constructor, with all the proper arguments, for you. Like this:

  // Example 8                                               (fragments)
  MutablePicoContainer pico = new DefaultPicoContainer();
  pico.registerComponentImplementation( MyHelperImpl.class );
  pico.registerComponentImplementation( MySafeComponent.class );

  MyContract comp = (MyContract)pico.getComponentInstance(
     MyContract.class );

Conclusion

We started out by defining the concept of “unsafe state”, which is a state in which a component does not do its work properly. We briefly outlined what is so bad about allowing components to be in an unsafe state. Then we showed a simple way to avoid that by using the constructor.

Charging on, we visited some attempts to fix the issue in other ways and showed why they’re inferior. Finally, I gave a very brief overview of how Picocontainer supports the use of the constructor as I outlined it.