martedì 20 settembre 2011

The Java Beans specification sucks!

Ok, the title is quite harsh, but it is so true...
The Java Beans specification imposes that each object property (i.e., variable) is accessed thru a couple of setter and getter method. In particular the method must be named with set/get prefix (lowercase) followed by the name of the property (with the first letter capitalized and the remaining as the original name). The return type and the arguments depends on the type of the method (often called accessor): in the case of a getter there are no arguments and the return type is of the same type of the property; in the case of the setter there is no return type and there is a single argument of the same type of the property.
As an example, the following is a correct Java Bean class definition:

class Person{
      private String name;
      private String surname;

      public void setName( String newName ){ name = newName; }
      public String getName(){ return name; }
      public void setSurname( String newSurname ){ surname = newSurname; }
      public String getSurname(){ return surname; }
}


As you can see the "name" property generates the "setName" and "getName" methods, as well as the "surname" property generates the "setSurname" and "getSurname" methods. All the getXX methods have a return value of the same type of the property and accept no arguments; all the setXX methods do not return any value and accept a single argument of the same type of the property they refer to.

Why I don't like this naming convention?

Let's start with the naming schema: while it is clear that I have to separate a getter name from the setter one, why should I have the get prefix? I mean, if I want to access the "name" property, that is exactly what I want to type. What is the simpler and beautiful code between the following?

      person.getName();     // Java Bean style
      person.name();        // Qt style


The latter does exactly what I want: I want to access the name property, so I don't want to explicity say "get the name property", but simply "the name property". Easier to type, simpler to read: I'm accessing the person name, I don't need to emphasize that I wan to "get" the person name because it is implicit that I am asking the person's name!
On the other hand the setter can remain the same, so that my bean becomes:


class Person{
      private String name;
      private String surname;

      public void setName( String newName ){ name = newName; }
      public String name(){ return name; }
      public void setSurname( String newSurname ){ surname = newSurname; }
      public String surname(){ return surname; }
}


A drawback of this approach is that using a standard prefix I have all the method grouped together: all the getXX and all the setXX. Removing the get prefix I find only the setters grouped together, while the other methods are sorted as the property names. This can be boring only if you are used to inspect a bean by means of reading the getter method names and not by reading its documentation.
Moreover, it is not clear how to behave when you have boolean properties: should you use "is" or "has" prefixes in the method names? A lot of framework seems to deal with the "is" convention, but I'm sure that a getter method called "isMoney" to return true in the case has still money sounds awkward even to the stricter Sun's engineer.

Anyway, another big, even huge problem of the Java Bean specification is that it does not consider side-effects. How can you test a setter method? You have to create a getter method! While this can sound ok to you, it does not look very good to me. When you execute a method call like:

    person.setName( "Luca" );

how can you assure that the name has really been set to "Luca"? You have to call getName() and test the two values. While setter and getters are usually simple and straightforward methods (those that can even be inlined), a lot of things can go wrong while in the execution path of one or the other. What is the solution? To have a setter that can return the actual value of the property, so that it is defined as returning the same type of its parameter. In other words:


class Person{
      ...
      public String setName( String newName ){ 
          name = newName; return name; 
      }
      public String setSurname( String newSurname ){ 
         surname = newSurname; return surname;    
      }
}


In this way the setter methods represent a single unit of testing, therefore can be tested as they are without requiring anything else (in particular a gettere method). Moreover in this way the classes are exposing to the outside world a clear side effect of the setter methods.

In conclusion I disagree with the Java Bean specification mainly for:
- their naming convention;
- their definition of setter method.
The worst thing in the whole story is that you cannot even think to change the Java Bean convention to use a different name schema or even to change the return type of the setter methods. This is due to the fact that a lot of Java frameworks adopt reflection to inspect and access properties, and while doing so they will stupidly search for setter methods that return void!

Nessun commento: