March 22, 2008

JSF und die wesentlichen Bestandteile einer Bohne

Benötigt man für jedes Feld einer JSF-Seite wirklich ein weitgehend sinnfreies Getter/Setter-Paar in der zugehörigen Managed-Bean ?
Nein - denn JSF ist konfigurierbar und Java bietet das Reflection-Package...

In der faces.config.xml kann der zu verwendende ELResolver geändert werden:

<application>  
  <el-resolver>
     com.whatever.package.FieldResolver
  </el-resolver>     
</application>
Die Methoden des EL-Resolvers werden dann analog dem folgenden Beispiel für getValue implementiert.
Zuerst wird weiterhin versucht, einen passenden Getter zu finden. Das ist wichtig, um Sonderfälle, die ohne Getter nicht auskommen, behandeln zu können. Wurde keine Methode gefunden, wird nach einem entsprechenden Class-Field gesucht. Nur bei letztendlichem Erfolg wird die Anfrage als bearbeitet markiert (context.setPropertyResolved(true)) - andernfalls werden implizit die übrigen EL-Resolver aufgerufen.
Da dies alles nur Sinn macht, wenn es überhaupt um Objekt-Properties geht, werden nur Ausdrücke mit einem Basis-Objekt bearbeitet (base != null).
public class FieldResolver extends ELResolver {
    private static final Object[] sNoArgs = new Object[0];
    private static final Class[] sNoClassArgs = new Class[0];

    public Object getValue(ELContext context, Object base, Object property) throws NullPointerException, PropertyNotFoundException, ELException {
        String name = property.toString();

        if (base != null) {
            // 1. try getter
            try {
                String getterName = "get" + name.substring(0, 1).toUpperCase() + name.substring(1);
                Method getter = base.getClass().getMethod(getterName, sNoClassArgs);
                context.setPropertyResolved(true);
                return getter.invoke(base, sNoArgs);
            }
            catch (NoSuchMethodException ne) {
                // no error so far           
            }
            catch (Exception ex) {
                throw new RuntimeException(ex);
            }

            // 2. direct field access
            try {
                Field field = getField(base, property);
                if (field != null) {
                    context.setPropertyResolved(true);
                    return field.get(base);
                }
            }
            catch (Exception e) {
                String message = "Error accessing property '" + name + "' in bean of type " + base.getClass().getName();
                throw new PropertyNotFoundException(message, e);
            }
        }

        return null;
    }
...
}

1 comment:

  1. Hallo!
    Ich bin schon seit einiger Zeit auf der Suche nach einer Lösung wie dieser.
    Leider fehlt in deinem Beispiel die Methode getField.
    Es wäre sehr nett, wenn du mir die komplette Klasse, inklusive der Methode getField und allen für extends ELResolver benötigten Methoden an se-mueller at gmx de schicken könntest.

    Vielen Dank!

    ReplyDelete