Friday, January 16, 2009

JSF VariableResolver & PropertyResolver

Resolving
Mit Hilfe des VariableResolvers und des PropertyResolvers löst JSF die EL-Expressions auf.
Der VariableResolver ist zuständig für den linken Teil der Expression. Für den restlichen rechten Teil ist der PropertyResolver zuständig.

Beispiel:
Bean Person:

public class PersonBean implements java.io.Serializable {
private Address address;
...
}

Klasse Address

public class Address implements java.io.Serializable {
private City city;
private String street;
private String zipCode;
...
}

Klasse City

public class City implements java.io.Serializable {
private String name;
...
}

JSF-Tag

<inputField value="#{personBean.address.city.name}" />

Der VariableResolver löst "personBean" auf.
Der PropertyResolver löst in Teilschritten zuerst "address" und anschließend "city" auf um zum Schluß auf die Property "name" der Klasse City zuzugreifen.

Implementierung eigener Variable- und PropertyResolver
Schritt 1
Anlegen der Klassen CustomVariableResolver und CustomPropertyResolver
Klasse CustomVariableResolver

package org.j4fry.jsf;
public class CustomVariableResolver extends VariableResolver {
private Logger log = Logger.getLogger(CustomVariableResolver.class);

// Ursprünglicher VariableResolver
private VariableResolver variableResolver;

public CustomVariableResolver(VariableResolver variableResolver) {
this.variableResolver = variableResolver;
}

@Override
public Object resolveVariable(FacesContext arg0, String arg1)
throws EvaluationException {
log.info("resolve: " + arg1);
// Delegation an ursprünglichen VariableResolver
return variableResolver.resolveVariable(arg0, arg1);
}
}

Klasse CustomPropertyResolver

package org.j4fry.jsf;
public class CustomPropertyResolver extends PropertyResolver {
private Logger log = Logger.getLogger(CustomPropertyResolver.class);

// Ursprünglicher PropertyResolver
private PropertyResolver propertyResolver;

public CustomPropertyResolver(PropertyResolver propertyResolver) {
this.propertyResolver = propertyResolver;
}

@Override
public Object getValue(Object fromObject, Object property)
throws EvaluationException, PropertyNotFoundException {
log.debug("getValue: fromObject[" + fromObject + "] property[" + property + "]");
// Delegation an ursprünglichen PropertyResolver
return propertyResolver.getValue(fromObject, property);
}

@Override
public void setValue(Object toObject, Object property, Object value)
throws EvaluationException, PropertyNotFoundException {
log.debug("setValue: toObject[" + toObject + "] property[" + property + "] value[" + value + "]");
// Delegation an ursprünglichen PropertyResolver
propertyResolver.setValue(toObject, property, value);
}

// Bei den restlichen Methoden wird einfach an den PropertyResolver delegiert

@Override
public void setValue(Object arg0, int arg1, Object arg2)
throws EvaluationException, PropertyNotFoundException {
propertyResolver.setValue(arg0, arg1, arg2);
}

@Override
public Class getType(Object arg0, int arg1) throws EvaluationException,
PropertyNotFoundException {
return propertyResolver.getType(arg0, arg1);
}

@Override
public Class getType(Object arg0, Object arg1) throws EvaluationException,
PropertyNotFoundException {
return propertyResolver.getType(arg0, arg1);
}

@Override
public Object getValue(Object arg0, int arg1) throws EvaluationException,
PropertyNotFoundException {
return propertyResolver.getValue(arg0, arg1);
}

@Override
public boolean isReadOnly(Object arg0, int arg1)
throws EvaluationException, PropertyNotFoundException {
return propertyResolver.isReadOnly(arg0, arg1);
}

@Override
public boolean isReadOnly(Object arg0, Object arg1)
throws EvaluationException, PropertyNotFoundException {
return propertyResolver.isReadOnly(arg0, arg1);
}

}

Die Klassen werden jeweils von den JSF-eigenen Resolvern abgeleitet. Zudem bekommt jeder CustomResolver einen Konstruktor der den ursprünglichen Resolver übergeben bekommt. Das ist wichtig um in den Methoden ggf. die Verarbeitung an diesen Resolver zu delegieren.

Schritt 2
CustomResolver in der faces-config.xml bekannt machen

<application>
<variable-resolver>
org.j4fry.jsf.CustomVariableResolver
</variable-resolver>
<property-resolver>
org.j4fry.jsf.CustomPropertyResolver
</property-resolver>
</application>

Interpretierung der Log-Ausgaben
Als Beispiel dient die o.g. EL-Expression #{personBean.address.city.name}

Lesender Zugriff
1. Auflösen von personBean durch VariableResolver
Logausgabe: resolve: personBean
2. Auflösen von address durch PropertyResolver
Logausgabe: getValue: fromObject[org.j4fry.beans.PersonBean@1f68572] property[address]
3. Auflösen von city durch PropertyResolver
Logausgabe: getValue: fromObject[org.j4fry.model.Address@1b335b7] property[city]
4. Auflösen von name durch PropertyResolver
Logausgabe: getValue: fromObject[org.j4fry.model.City@15c018] property[name]

Schreibender Zugriff
1. Auflösen von personBean durch VariableResolver
Logausgabe: resolve: personBean
2. Auflösen von address durch PropertyResolver
Logausgabe: getValue: fromObject[org.j4fry.beans.PersonBean@1f68572] property[address]
3. Auflösen von city durch PropertyResolver
Logausgabe: getValue: fromObject[org.j4fry.model.Address@1b335b7] property[city]
4. Setzen von name durch PropertyResolver
Logausgabe: setValue: toObject[org.j4fry.model.City@15c018] property[name] value[Munich]

No comments:

Post a Comment