问题
Is there a way to programmatically, in a java code, register custom taglib reference?
I am using JSF 1.2_09, rich faces 3.3.3, jsf-facelets 1.1.14.
Specifically:
In this code, jsf Expression Language is used to do some job for us, like concatenation of 2 results in one field or similar stuff..
FacesContext ctx = FacesContext.getCurrentInstance();
Application app = ctx.getApplication();
ExpressionFactory ef = app.getExpressionFactory();
ELContext elContext = ctx.getELContext();
ValueExpression valueExpression = new OverrideValueExpression(singleResult.getClass(), singleResult);
elContext.getVariableMapper().setVariable("row", valueExpression);
for (int i = 0; i < jsfDisplayValue.size(); i++){
Object value = ef.createValueExpression(elContext, jsfDisplayValue.get(i), Object.class).getValue(ctx.getELContext());
//Do something with value...
}
E.g., elements of jsfDisplayValue
can be:
"#{row.name} #{row.surname}", "#{row.age}", "#{tagfoo:fooFunction(row.age)}"
...
The problem occurs when expression contains a function, like highlighted, tagfoo:fooFunction
.
Stack trace:
javax.el.ELException: Function 'tagfoo:fooFunction' not found
at org.apache.el.lang.ExpressionBuilder.visit(ExpressionBuilder.java:198)
at org.apache.el.parser.SimpleNode.accept(SimpleNode.java:147)
at org.apache.el.lang.ExpressionBuilder.prepare(ExpressionBuilder.java:155)
at org.apache.el.lang.ExpressionBuilder.build(ExpressionBuilder.java:173)
at org.apache.el.lang.ExpressionBuilder.createValueExpression(ExpressionBuilder.java:217)
at org.apache.el.ExpressionFactoryImpl.createValueExpression(ExpressionFactoryImpl.java:67)
ELContext doesn't recognize custom function, and it can't resolve the function because tagfoo
is unknown to ELContext.
How can I register taglib reference in java class, so ELContext can recognise custom functions?
On a JSF page, I would do this:
<jsp:root version="2.0" xmlns:jsp="http://java.sun.com/JSP/Page"
xmlns:tagfoo="http://tagfoo.org/tags">
P.S.
My custom functions are working properly on jsf pages.
回答1:
I'm sorry I'm a bit late, but I just stumbled upon the same problem today.
Inspecting the ElContext and FunctionMapper instances, I have seen they definitely are custom implementations of the standard abstract class.
As I want to keep my code portable, I decided not to get involved into writing code for a specific implementation, and as the abstract class only defines the read contract and omits the write side of things, I just wrote a custom FunctionMapper. Here is the meaningfull code:
public void register(String prefix, String function, Method method) {
register.put(prefix + ":" + function, method);
}
@Override
public Method resolveFunction(String prefix, String localName) {
if (register.containsKey(prefix + ":" + localName)) {
return register.get(prefix + ":" + localName);
}
for (FunctionMapper it : delegates) {
final Method current = it.resolveFunction(prefix, localName);
if (current != null) {
return current;
}
}
return null;
}
By wrapping the standard FunctionMapper, I can easily add my own functions and keep the standard environment ok. In my case, I had to write a custom ElContext implementation too, that basicaly clones the default ElContext and just wraps the FunctionMapper.
I'm pretty happy with the results, hope this helps.
来源:https://stackoverflow.com/questions/16214371/programmatically-register-taglib-reference