in java/org/apache/jasper/compiler/Validator.java [904:1070]
private void checkXmlAttributes(Node.CustomTag n, Node.JspAttribute[] jspAttrs, Map<String,Object> tagDataAttrs)
throws JasperException {
TagInfo tagInfo = n.getTagInfo();
TagAttributeInfo[] tldAttrs = tagInfo.getAttributes();
Attributes attrs = n.getAttributes();
for (int i = 0; attrs != null && i < attrs.getLength(); i++) {
boolean found = false;
boolean runtimeExpression = ((n.getRoot().isXmlSyntax() && attrs.getValue(i).startsWith("%=")) ||
(!n.getRoot().isXmlSyntax() && attrs.getValue(i).startsWith("<%=")));
boolean elExpression = false;
boolean deferred = false;
double libraryVersion = Double.parseDouble(tagInfo.getTagLibrary().getRequiredVersion());
boolean deferredSyntaxAllowedAsLiteral =
pageInfo.isDeferredSyntaxAllowedAsLiteral() || libraryVersion < 2.1;
String xmlAttributeValue = attrs.getValue(i);
ELNode.Nodes el = null;
if (!runtimeExpression && !pageInfo.isELIgnored()) {
el = ELParser.parse(xmlAttributeValue, deferredSyntaxAllowedAsLiteral);
Iterator<ELNode> nodes = el.iterator();
while (nodes.hasNext()) {
ELNode node = nodes.next();
if (node instanceof ELNode.Root) {
if (((ELNode.Root) node).getType() == '$') {
if (elExpression && deferred) {
err.jspError(n, "jsp.error.attribute.deferredmix");
}
elExpression = true;
} else if (((ELNode.Root) node).getType() == '#') {
if (elExpression && !deferred) {
err.jspError(n, "jsp.error.attribute.deferredmix");
}
elExpression = true;
deferred = true;
}
}
}
}
boolean expression = runtimeExpression || elExpression;
// When attribute is not an expression,
// contains its textual value with \$ and \# escaping removed.
String textAttributeValue;
if (!elExpression && el != null) {
// Should be a single Text node
Iterator<ELNode> it = el.iterator();
if (it.hasNext()) {
textAttributeValue = ((ELNode.Text) it.next()).getText();
} else {
textAttributeValue = "";
}
} else {
textAttributeValue = xmlAttributeValue;
}
for (int j = 0; tldAttrs != null && j < tldAttrs.length; j++) {
if (attrs.getLocalName(i).equals(tldAttrs[j].getName()) && (attrs.getURI(i) == null ||
attrs.getURI(i).isEmpty() || attrs.getURI(i).equals(n.getURI()))) {
TagAttributeInfo tldAttr = tldAttrs[j];
if (tldAttr.canBeRequestTime() || tldAttr.isDeferredMethod() || tldAttr.isDeferredValue()) { // JSP
// 2.1
if (!expression) {
String expectedType = null;
if (tldAttr.isDeferredMethod()) {
// The String literal must be castable to what is declared as type
// for the attribute
String m = tldAttr.getMethodSignature();
if (m != null) {
m = m.trim();
int rti = m.indexOf(' ');
if (rti > 0) {
expectedType = m.substring(0, rti).trim();
}
} else {
expectedType = "java.lang.Object";
}
if ("void".equals(expectedType)) {
// Can't specify a literal for a
// deferred method with an expected type
// of void - JSP.2.3.4
err.jspError(n, "jsp.error.literal_with_void", tldAttr.getName());
}
}
if (tldAttr.isDeferredValue()) {
// The String literal must be castable to what is declared as type
// for the attribute
expectedType = tldAttr.getExpectedTypeName();
}
if (expectedType != null) {
Class<?> expectedClass = String.class;
try {
expectedClass = JspUtil.toClass(expectedType, loader);
} catch (ClassNotFoundException e) {
err.jspError(n, "jsp.error.unknown_attribute_type", tldAttr.getName(),
expectedType);
}
// Check casting - not possible for all types
if (String.class.equals(expectedClass) || expectedClass == Long.TYPE ||
expectedClass == Double.TYPE || expectedClass == Byte.TYPE ||
expectedClass == Short.TYPE || expectedClass == Integer.TYPE ||
expectedClass == Float.TYPE ||
Number.class.isAssignableFrom(expectedClass) ||
Character.class.equals(expectedClass) || Character.TYPE == expectedClass ||
Boolean.class.equals(expectedClass) || Boolean.TYPE == expectedClass ||
expectedClass.isEnum()) {
try {
expressionFactory.coerceToType(textAttributeValue, expectedClass);
} catch (Exception e) {
err.jspError(n, "jsp.error.coerce_to_type", tldAttr.getName(), expectedType,
textAttributeValue);
}
}
}
jspAttrs[i] = new Node.JspAttribute(tldAttr, attrs.getQName(i), attrs.getURI(i),
attrs.getLocalName(i), textAttributeValue, false, null, false);
} else {
if (deferred && !tldAttr.isDeferredMethod() && !tldAttr.isDeferredValue()) {
// No deferred expressions allowed for this attribute
err.jspError(n, "jsp.error.attribute.custom.non_rt_with_expr", tldAttr.getName());
}
if (!deferred && !tldAttr.canBeRequestTime()) {
// Only deferred expressions are allowed for this attribute
err.jspError(n, "jsp.error.attribute.custom.non_rt_with_expr", tldAttr.getName());
}
// EL or Runtime expression
jspAttrs[i] = getJspAttribute(tldAttr, attrs.getQName(i), attrs.getURI(i),
attrs.getLocalName(i), xmlAttributeValue, n, el, false);
}
} else {
// Attribute does not accept any expressions.
// Make sure its value does not contain any.
if (expression) {
err.jspError(n, "jsp.error.attribute.custom.non_rt_with_expr", tldAttr.getName());
}
jspAttrs[i] = new Node.JspAttribute(tldAttr, attrs.getQName(i), attrs.getURI(i),
attrs.getLocalName(i), textAttributeValue, false, null, false);
}
if (expression) {
tagDataAttrs.put(attrs.getQName(i), TagData.REQUEST_TIME_VALUE);
} else {
tagDataAttrs.put(attrs.getQName(i), textAttributeValue);
}
found = true;
break;
}
}
if (!found) {
if (tagInfo.hasDynamicAttributes()) {
jspAttrs[i] = getJspAttribute(null, attrs.getQName(i), attrs.getURI(i), attrs.getLocalName(i),
xmlAttributeValue, n, el, true);
} else {
err.jspError(n, "jsp.error.bad_attribute", attrs.getQName(i), n.getLocalName());
}
}
}
}