Permalink
Browse files

Inverse behavior of <o:tagAttribute>. It should be allowed to scan all

wrapped EL variables until a parent <o:tagAttribute> is encountered.
  • Loading branch information...
BalusC committed Dec 11, 2016
1 parent 4d80a56 commit c62dd9fdb78abe2c515cff30c449f468cbc07cbb
@@ -25,27 +25,36 @@
*/
public class DelegatingVariableMapper extends VariableMapper {
private final VariableMapper variableMapper;
private static volatile boolean resolveWrappedVariable;
private final VariableMapper wrapped;
private Map<String, ValueExpression> variables = new HashMap<>();
public DelegatingVariableMapper(VariableMapper variableMapper) {
this.variableMapper = variableMapper;
public DelegatingVariableMapper(VariableMapper wrapped) {
this.wrapped = wrapped;
}
@Override
public ValueExpression resolveVariable(String variable) {
ValueExpression valueExpression = variables.get(variable);
if (valueExpression == null) {
valueExpression = variableMapper.resolveVariable(variable);
public ValueExpression resolveVariable(String name) {
if (variables.containsKey(name)) {
return resolveWrappedVariable ? null : variables.get(name);
}
return valueExpression;
return wrapped.resolveVariable(name);
}
public ValueExpression resolveWrappedVariable(String name) {
try {
resolveWrappedVariable = true;
return wrapped.resolveVariable(name);
}
finally {
resolveWrappedVariable = false;
}
}
@Override
public ValueExpression setVariable(String variable, ValueExpression expression) {
return variables.put(variable, expression);
public ValueExpression setVariable(String name, ValueExpression expression) {
return variables.put(name, expression);
}
}
@@ -78,8 +78,6 @@
*/
public class TagAttribute extends TagHandler {
private static final String MARKER = TagAttribute.class.getName();
private final String name;
private final javax.faces.view.facelets.TagAttribute defaultValue;
@@ -91,52 +89,26 @@ public TagAttribute(TagConfig config) {
@Override
public void apply(FaceletContext context, UIComponent parent) throws IOException {
checkAndMarkMapper(context);
VariableMapper variableMapper = context.getVariableMapper();
ValueExpression valueExpressionLocal = variableMapper.setVariable(name, null);
if (valueExpressionLocal == null && defaultValue != null) {
valueExpressionLocal = defaultValue.getValueExpression(context, Object.class);
}
DelegatingVariableMapper variableMapper = getDelegatingVariableMapper(context);
ValueExpression valueExpression = variableMapper.resolveWrappedVariable(name);
if (valueExpressionLocal == null) {
if (variableMapper instanceof DelegatingVariableMapper) {
valueExpressionLocal = context.getExpressionFactory().createValueExpression(null, Object.class);
}
else {
valueExpressionLocal = variableMapper.resolveVariable(name);
}
if (valueExpression == null && defaultValue != null) {
valueExpression = defaultValue.getValueExpression(context, Object.class);
}
variableMapper.setVariable(name, valueExpressionLocal);
variableMapper.setVariable(name, valueExpression);
}
private static void checkAndMarkMapper(FaceletContext context) {
Integer marker = (Integer) context.getAttribute(MARKER);
if (marker != null && marker.equals(context.hashCode())) {
return; // Already marked.
}
private DelegatingVariableMapper getDelegatingVariableMapper(FaceletContext context) {
VariableMapper variableMapper = context.getVariableMapper();
ValueExpression valueExpressionParentMarker = variableMapper.resolveVariable(MARKER);
if (valueExpressionParentMarker == null) { // We're the outer faces tag, or parent didn't mark because it didn't have any attributes set.
context.setAttribute(MARKER, context.hashCode());
return;
}
variableMapper.setVariable(MARKER, null); // If we have our own mapper, this will not affect our parent mapper.
ValueExpression valueExpressionParentMarkerCheck = variableMapper.resolveVariable(MARKER);
if (valueExpressionParentMarkerCheck == null || !valueExpressionParentMarkerCheck.equals(valueExpressionParentMarker)) {
// We were able to remove our parent's mapper, so we share it.
variableMapper.setVariable(MARKER, valueExpressionParentMarker); // First put parent marker back ...
context.setVariableMapper(new DelegatingVariableMapper(variableMapper)); // ... then add our own variable mapper.
if (variableMapper instanceof DelegatingVariableMapper) {
return (DelegatingVariableMapper) variableMapper;
}
context.setAttribute(MARKER, context.hashCode());
DelegatingVariableMapper delegatingVariableMapper = new DelegatingVariableMapper(variableMapper);
context.setVariableMapper(delegatingVariableMapper);
return delegatingVariableMapper;
}
}

2 comments on commit c62dd9f

@kapitanrum

This comment has been minimized.

Show comment
Hide comment
@kapitanrum

kapitanrum Jan 9, 2018

In DelegatingVariableMapper.java write to static field resolveWrappedVariable from instance method resolveWrappedVariable(String name) is BAD Practice.

Accessing to static field from multiple instances without synchronization may be value inconsistent - can we be sure that the variable will not be accessed from multiple instances?

kapitanrum replied Jan 9, 2018

In DelegatingVariableMapper.java write to static field resolveWrappedVariable from instance method resolveWrappedVariable(String name) is BAD Practice.

Accessing to static field from multiple instances without synchronization may be value inconsistent - can we be sure that the variable will not be accessed from multiple instances?

@BalusC

This comment has been minimized.

Show comment
Hide comment
@BalusC

BalusC Jan 27, 2018

Member

@kapitanrum There's indeed a risk. Fixed in 3a57763.

Member

BalusC replied Jan 27, 2018

@kapitanrum There's indeed a risk. Fixed in 3a57763.

Please sign in to comment.