To make more clear this point about when we should add additional code on
component class, I will take some examples from my experience using
myfaces-faces-plugin for tomahawk. There is some situations where you have
to add custom code like this:
This is the code of
src/main/java-templates/org/apache/myfaces/component/html/ext/HtmlCommandButtonTemplate.java
public class HtmlCommandButton
extends javax.faces.component.html.HtmlCommandButton
implements UserRoleAware
{
public static final String DEFAULT_RENDERER_TYPE = "
org.apache.myfaces.Button";
public String getClientId(FacesContext context)
{
String clientId = HtmlComponentUtils.getClientId(this,
getRenderer(context), context);
if (clientId == null)
{
clientId = super.getClientId(context);
}
return clientId;
}
public boolean isRendered()
{
if (!UserRoleUtils.isVisibleOnUserRole(this)) return false;
return super.isRendered();
}
}
If you want forceId feature works, you need to override getClientId(),and if
you want to use visibleOnUserRole property, you need to override
isRendered(). And also if you want that the component implements some
interfaces you need to specify this on the template.
In this case, we can use abstract classes to do this but the result is the
same as with templates.
One useful example of why templates are better than abstract classes is
this:
This is the code of
src/main/java-templates/org/apache/myfaces/custom/buffer/BufferTemplate.java
public class Buffer extends UIComponentBase{
{
/**/private String _into = null;
void fill(String content, FacesContext facesContext){
ValueExpression intoVB;
if (_into == null) {
intoVB = getValueExpression("into");
_into = intoVB.getExpressionString();
} else {
intoVB = facesContext.getApplication().
getExpressionFactory().createValueExpression(
facesContext.getELContext(), _into, Object.class );
}
intoVB.setValue(facesContext.getELContext(), content);
}
}
Please take attention on this line:
/**/private String _into = null;
If you write an abstract class, you have to put this field as protected,
which is bad. To make abstract class works for this code you have to write
more code than shown here, or exclude component class generation for this
guy.
Trinidad view about how to develop components is that if we have some code
that could be in renderer we have to put in the renderer. But the practice
says that there are some situations when we need to write custom code on
component class.
In tomahawk 1.2.x, the 80% of the components use template files to add
custom code to use forceId, visibleOnUserRole, implements additional facets,
define constants used on the renderer, or override
processXXXXXX(FacesContext context) methods (and tomahawk is full of
components created by users!).
Actually, the only code that breaks the templates is when you want to define
restoreState and saveState methods. In that case you have to use abstract
class or exclude the class for component generator, use the generator,
generate some code and put this on the real component class.
Not have code completion and other features on the IDE is a low price for we
have with templates.
regards
Leonardo Uribe