Skip to main content

JSF: UIComponent.getAttributes() -- good, bad or ugly?

Posted by bdudney on February 14, 2004 at 3:49 PM PST

Back in September Allen Holub said that accessors are evil, there was also a long thread on TSS about Allen's article. Then very recently Cedric Beust posted that he thought accessors are here to stay and that Allen Holub was all wrong (I tend to agree with Cedric on accessors but Allen did make a couple of good points). Which all seem to have very little to do with JSF I know but...

Consider the UIComponent.getAttributes() : Map method, which is new in the latest beta release. This method returns a map that gives you get and put access to the JavaBean attributes on your component (all those evil accesors:). This fascinates me and I think its a cool thing to do. Tools have a very simple (java.util.Map) API to use and we as programmers have the accessors for the stuff we need typed access to (its likely to be a little quicker too but probably not called often enough to matter much). So for example;


  public class MyComponent extends UIComponentBase {
    ...
    public static final String FOO = "foo";
    private String foo;
    public void setFoo(String foo) {
      this.foo = foo;
    }
    public String getFoo() {
      return foo;
    }
    ...
  }

  public class MyRenderer extends Renderer {
    public static final String BAR = "bar";
    ...
    public void encodeBegin(FacesContext context, UIComponent component) {
      // instead of casting component to MyComponent I can use the attributes
      // map to get at 'foo' or I could cast and call getFoo() either way
      // it works the same (the map is of course a bit slower)
      ...
      String foo = (String)component.getAttributes().get(MyComponent.FOO);
      ...
      // even more interesting I can get at the renderer specific
      // values put into the component by the creator of the component
      // (usually a JSP tag) with the same logic
      // Typically I'd be setting the value of bar in a JSP tag
      // also using the map interface like this
      // component.getAttributes().put(MyRenderer.BAR, valueSpecifiedInJSP);
      ...
      String foo = (String)component.getAttributes().get(MyRenderer.BAR);
      ...
     
    }
  }

The spec calls this 'attribute-property transparency'. I like this a lot better than the way that the API was laid out in the EA4 version of JSF. In that world you had to keep everything in a Map and if you wanted accessors they had to delegate to the Map. This is a lot cleaner in my opinion.

Another side effect is that you can just assume that put(Object, Object) will 'just work' and will call the underlying set method when it can and put the value into a map otherwise. Thus we will be able to iterate through properties in a very straightforward way. This comes in very handy in the way JSP custom actions (tags) are implemented. The first example in the spec in section 9.3 shows how this could/should work.

With this API components could conceivably be writen without any accessors and no fields. All the instance data would be stored in the map. I think there is a certian danger of abuse like this.

On the positive side tools can access the whole component without having to know anything about it. This is a key aspect of the tooling requirements behind JSF and was possible in EA4 but uglier.

I've seen this sort of thing done on a limited scale on other projects but I've never seen something like this in a project like JSF (that will be used by lots and lots of people). What are your thoughts on doing this? Will it scale up in terms of usability? Will it get abused so much that we will end up with lots of nasty code? What do you think?

Related Topics >>