Skip to content

[core] Inconsistent boolean value representation with Jaxen #1244

@oowekyala

Description

@oowekyala

The problem

Our Jaxen adapter treats boolean attribute values as strings, ie an attribute with the Java value true will have the XPath string value 'true', and same for false.

The problem with that is that it's inconsistent with the XPath spec. In XPath, strings are truthy if they are non-empty. That means the string 'false' is in fact truthy. Moreover, the only way to obtain boolean values in both XPath 1.0 and 2.0 is through the functions true() and false().

So for example, given:

class Foo {} // the @Interface attribute is of course false 

and the XPath query (<val> is a placeholder):

//ClassOrInterfaceDeclaration[@Interface=<val>]

We have the following evaluation results, depending on the value of <val> and the XPath engine used.

  • n means no match
  • y means a match
  • Bold table cells mean inconsistent behaviour
<val>: 'true' 'false' true() false()
Jaxen n y y n
Saxon type error type error n y

Saxon's behaviour is expected, it even has a type error when we try to compare the boolean with a string (at least in the designer).

Jaxen, on the other hand, is confused when using the boolean XPath functions:

  • 'false' is truthy so @Interface=true() is true, because @Interface is 'false'
  • For the same reason, @Interface=false() is false

This is the inverse of what we'd expect.

So what?

Due to that inconsistency, all XPath 1.0 rules (so nearly all our XPath rules, and probably the majority of user rules as well) compare boolean attributes with string values.

The problem is that it's incompatibile with the correct behaviour of Saxon

Because of that, Jaxen rules cannot be transparently ported to Saxon without transforming at least these comparisons to use the boolean value functions. If they aren't transformed, we get type errors/ unseen failures, e.g. #902

Possible solution

If we want to drop Jaxen, we'd probably need to transform the faulty comparisons before feeding the expression to Saxon. #1243 could be a way to do that

Source

The faulty source is here:

public String getStringValue() {
if (stringValue != null) {
return stringValue;
}
Object v = this.value;
if (this.value == null) {
v = getValue();
}
stringValue = v == null ? "" : String.valueOf(v);
return stringValue;
}

Instead of returning just String.valueOf, this function should be returning a falsy (empty) string for false values, instead of 'false'.

The same happens for properties:

final Object value = e.getValue();
vc.setVariableValue(propName, value != null ? value.toString() : null);

Metadata

Metadata

Assignees

No one assigned

    Labels

    a:bugPMD crashes or fails to analyse a file.in:xpathRelating to xpath support at large, eg Jaxen / Saxon, custom functions, attribute resolutionwas:wontfix

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions