Make attributes support full value range
This commit is contained in:
@ -6,8 +6,11 @@ package net.sourceforge.pmd.lang.ast.xpath;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
@ -98,17 +101,20 @@ public class AttributeAxisIterator implements Iterator<Attribute> {
|
||||
return new Attribute(node, m.name, m.method);
|
||||
}
|
||||
|
||||
private static final Set<Class<?>> CONSIDERED_RETURN_TYPES
|
||||
= new HashSet<>(Arrays.<Class<?>>asList(Integer.TYPE, Boolean.TYPE, Double.TYPE, String.class, Long.TYPE, Character.TYPE, Float.TYPE));
|
||||
|
||||
private static final Set<String> FILTERED_OUT_NAMES
|
||||
= new HashSet<>(Arrays.asList("toString", "getClass", "getTypeNameNode", "hashCode", "getImportedNameNode", "getScope"));
|
||||
|
||||
protected boolean isAttributeAccessor(Method method) {
|
||||
|
||||
String methodName = method.getName();
|
||||
boolean deprecated = method.getAnnotation(Deprecated.class) != null;
|
||||
|
||||
return !deprecated
|
||||
&& (Integer.TYPE == method.getReturnType() || Boolean.TYPE == method.getReturnType()
|
||||
|| Double.TYPE == method.getReturnType() || String.class == method.getReturnType())
|
||||
&& method.getParameterTypes().length == 0 && Void.TYPE != method.getReturnType()
|
||||
&& !methodName.startsWith("jjt") && !"toString".equals(methodName) && !"getScope".equals(methodName)
|
||||
&& !"getClass".equals(methodName) && !"getTypeNameNode".equals(methodName)
|
||||
&& !"getImportedNameNode".equals(methodName) && !"hashCode".equals(methodName);
|
||||
&& CONSIDERED_RETURN_TYPES.contains(method.getReturnType())
|
||||
&& method.getParameterTypes().length == 0
|
||||
&& !methodName.startsWith("jjt")
|
||||
&& !FILTERED_OUT_NAMES.contains(methodName);
|
||||
}
|
||||
}
|
||||
|
@ -5,15 +5,12 @@
|
||||
package net.sourceforge.pmd.lang.ast.xpath.saxon;
|
||||
|
||||
import net.sourceforge.pmd.lang.ast.xpath.Attribute;
|
||||
import net.sourceforge.pmd.lang.rule.xpath.SaxonXPathRuleQuery;
|
||||
|
||||
import net.sf.saxon.om.NodeInfo;
|
||||
import net.sf.saxon.om.SequenceIterator;
|
||||
import net.sf.saxon.trans.XPathException;
|
||||
import net.sf.saxon.type.Type;
|
||||
import net.sf.saxon.value.BooleanValue;
|
||||
import net.sf.saxon.value.EmptySequence;
|
||||
import net.sf.saxon.value.Int64Value;
|
||||
import net.sf.saxon.value.StringValue;
|
||||
import net.sf.saxon.value.Value;
|
||||
|
||||
/**
|
||||
@ -48,20 +45,7 @@ public class AttributeNode extends AbstractNodeInfo {
|
||||
public Value atomize() throws XPathException {
|
||||
if (value == null) {
|
||||
Object v = attribute.getValue();
|
||||
// TODO Need to handle the full range of types, is there something
|
||||
// Saxon can do to help?
|
||||
if (v instanceof String) {
|
||||
value = new StringValue((String) v);
|
||||
} else if (v instanceof Boolean) {
|
||||
value = BooleanValue.get(((Boolean) v).booleanValue());
|
||||
} else if (v instanceof Integer) {
|
||||
value = Int64Value.makeIntegerValue((Integer) v);
|
||||
} else if (v == null) {
|
||||
value = EmptySequence.getInstance();
|
||||
} else {
|
||||
throw new RuntimeException(
|
||||
"Unable to create ValueRepresentaton for attribute value: " + v + " of type " + v.getClass());
|
||||
}
|
||||
value = SaxonXPathRuleQuery.getAtomicRepresentation(v);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
@ -26,6 +26,7 @@ import net.sf.saxon.sxpath.XPathExpression;
|
||||
import net.sf.saxon.sxpath.XPathStaticContext;
|
||||
import net.sf.saxon.sxpath.XPathVariable;
|
||||
import net.sf.saxon.trans.XPathException;
|
||||
import net.sf.saxon.value.AtomicValue;
|
||||
import net.sf.saxon.value.BigIntegerValue;
|
||||
import net.sf.saxon.value.BooleanValue;
|
||||
import net.sf.saxon.value.DoubleValue;
|
||||
@ -42,18 +43,19 @@ import net.sf.saxon.value.UntypedAtomicValue;
|
||||
*/
|
||||
public class SaxonXPathRuleQuery extends AbstractXPathRuleQuery {
|
||||
|
||||
// Mapping from Node name to applicable XPath queries
|
||||
private XPathExpression xpathExpression;
|
||||
private List<XPathVariable> xpathVariables;
|
||||
|
||||
private static final int MAX_CACHE_SIZE = 20;
|
||||
private static final Map<Node, DocumentNode> CACHE = new LinkedHashMap<Node, DocumentNode>(MAX_CACHE_SIZE) {
|
||||
private static final long serialVersionUID = -7653916493967142443L;
|
||||
|
||||
|
||||
protected boolean removeEldestEntry(final Map.Entry<Node, DocumentNode> eldest) {
|
||||
return size() > MAX_CACHE_SIZE;
|
||||
}
|
||||
};
|
||||
// Mapping from Node name to applicable XPath queries
|
||||
private XPathExpression xpathExpression;
|
||||
private List<XPathVariable> xpathVariables;
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
@ -63,6 +65,7 @@ public class SaxonXPathRuleQuery extends AbstractXPathRuleQuery {
|
||||
return XPATH_1_0_COMPATIBILITY.equals(version) || XPATH_2_0.equals(version);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@ -112,38 +115,14 @@ public class SaxonXPathRuleQuery extends AbstractXPathRuleQuery {
|
||||
}
|
||||
Item[] converted = new Item[val.size()];
|
||||
for (int i = 0; i < val.size(); i++) {
|
||||
converted[i] = getItemRepresentation(val.get(i));
|
||||
converted[i] = getAtomicRepresentation(val.get(i));
|
||||
}
|
||||
return new SequenceExtent(converted);
|
||||
} else {
|
||||
return getItemRepresentation(value);
|
||||
return getAtomicRepresentation(value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private Item getItemRepresentation(Object value) {
|
||||
if (value == null) {
|
||||
return UntypedAtomicValue.ZERO_LENGTH_UNTYPED;
|
||||
} else if (value instanceof String) {
|
||||
return new StringValue((String) value);
|
||||
} else if (value instanceof Boolean) {
|
||||
return BooleanValue.get((Boolean) value);
|
||||
} else if (value instanceof Integer) {
|
||||
return Int64Value.makeIntegerValue((Integer) value);
|
||||
} else if (value instanceof Long) {
|
||||
return new BigIntegerValue((Long) value);
|
||||
} else if (value instanceof Double) {
|
||||
return new DoubleValue((Double) value);
|
||||
} else if (value instanceof Character) {
|
||||
return new StringValue(value.toString());
|
||||
} else if (value instanceof Float) {
|
||||
return new FloatValue((Float) value);
|
||||
} else {
|
||||
// We could maybe use UntypedAtomicValue
|
||||
throw new RuntimeException("Unable to create ValueRepresentation for value of type: " + value.getClass());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
private DocumentNode getDocumentNode(Node node) {
|
||||
// Get the root AST node
|
||||
@ -164,6 +143,7 @@ public class SaxonXPathRuleQuery extends AbstractXPathRuleQuery {
|
||||
return documentNode;
|
||||
}
|
||||
|
||||
|
||||
private void initializeXPathExpression() {
|
||||
if (xpathExpression != null) {
|
||||
return;
|
||||
@ -200,4 +180,36 @@ public class SaxonXPathRuleQuery extends AbstractXPathRuleQuery {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the Saxon representation of the parameter, if its type corresponds
|
||||
* to an XPath 2.0 atomic datatype.
|
||||
*
|
||||
* @param value The value to convert
|
||||
*
|
||||
* @return The converted AtomicValue
|
||||
*/
|
||||
public static AtomicValue getAtomicRepresentation(Object value) {
|
||||
if (value == null) {
|
||||
return UntypedAtomicValue.ZERO_LENGTH_UNTYPED;
|
||||
} else if (value instanceof String) {
|
||||
return new StringValue((String) value);
|
||||
} else if (value instanceof Boolean) {
|
||||
return BooleanValue.get((Boolean) value);
|
||||
} else if (value instanceof Integer) {
|
||||
return Int64Value.makeIntegerValue((Integer) value);
|
||||
} else if (value instanceof Long) {
|
||||
return new BigIntegerValue((Long) value);
|
||||
} else if (value instanceof Double) {
|
||||
return new DoubleValue((Double) value);
|
||||
} else if (value instanceof Character) {
|
||||
return new StringValue(value.toString());
|
||||
} else if (value instanceof Float) {
|
||||
return new FloatValue((Float) value);
|
||||
} else {
|
||||
// We could maybe use UntypedAtomicValue
|
||||
throw new RuntimeException("Unable to create ValueRepresentation for value of type: " + value.getClass());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user