Details

    • Type: Improvement
    • Status: Resolved
    • Priority: Minor
    • Resolution: Fixed
    • Affects Version/s: 1.1 Final
    • Fix Version/s: None
    • Labels:
      None
    • Environment:

      Operating System: Windows XP
      Platform: PC

    • Bugzilla Id:
      30298

      Description

      It is not clear in the doc comments how to call a function in such a way that
      certain parameters are evaluated as XPath expressions before being passed to
      the method.

      For example, in the PackageFunctions doc comments, it gives the example:

      "util:substring('foo', 1, 2)" is equivalent to "foo".substring(1, 2)

      which is not an especially useful example, as both are inefficient equivalents
      of the expression "fo".

      A more interesting example involve an expression like:

      "util:substring('person/name/middleName', 1, 1)"

      which could be used to get the middle initial of a person. The problem is how
      to indicate that this should be context.getJXPathContext().getValue
      ("person/name/middleName").substring(1, 1) instead
      of "person/name/middleName".substring(1, 1).

      Without the facility to indicate that some parameters are XPath expressions,
      existing methods cannot be used without writing wrapper methods to evaluate
      the XPath expressions.

      If such a facility already exists, the doc comments of PackageFunctions, etc.
      should be updated to describe it.

        Activity

        Show
        dmitri@plotnix.com Dmitri Plotnikov added a comment - The requested behavior is implemented and documented. See http://jakarta.apache.org/commons/jxpath/users-guide.html#Expression%20Context and http://jakarta.apache.org/commons/jxpath/users-guide.html#Collections%20as% 20Arguments
        Hide
        kwongfu@hotmail.com Kevin Wong added a comment -

        I think you have misunderstood me. I don't want to have to write the method:

        public class MyExtenstionFunctions {
        public static Object stringToUpperCase(ExpressionContext context, String
        xpath)

        { String value = (String)context.getJXPathContext().getValue(xpath); return value.toUpperCase(); }

        }

        and and use an expression like "myextenstionfunctions:stringToUpperCase
        ('lastName')".

        I just want to use the expression "toUpperCase('lastName')" and have it
        evaluate to "SMITH" instead of "LASTNAME".

        The references you listed do not indicate how to do this.

        Show
        kwongfu@hotmail.com Kevin Wong added a comment - I think you have misunderstood me. I don't want to have to write the method: public class MyExtenstionFunctions { public static Object stringToUpperCase(ExpressionContext context, String xpath) { String value = (String)context.getJXPathContext().getValue(xpath); return value.toUpperCase(); } } and and use an expression like "myextenstionfunctions:stringToUpperCase ('lastName')". I just want to use the expression "toUpperCase('lastName')" and have it evaluate to "SMITH" instead of "LASTNAME". The references you listed do not indicate how to do this.
        Hide
        dmitri@plotnix.com Dmitri Plotnikov added a comment -

        I am still not sure what the problem is.

        1. First of all, the stringToUpperCase function that you quoted looks mighty
        fine to me - I don't see anything wrong with it.

        2. Why do you need to pass the path as a string in the first place? What would
        be wrong with "myextenstionfunctions:stringToUpperCase
        (lastName)" (note the absense of quotes)? It would in fact first
        evaluate 'lastName', then pass the found value to stringToUpperCase.

        Show
        dmitri@plotnix.com Dmitri Plotnikov added a comment - I am still not sure what the problem is. 1. First of all, the stringToUpperCase function that you quoted looks mighty fine to me - I don't see anything wrong with it. 2. Why do you need to pass the path as a string in the first place? What would be wrong with "myextenstionfunctions:stringToUpperCase (lastName)" (note the absense of quotes)? It would in fact first evaluate 'lastName', then pass the found value to stringToUpperCase.
        Hide
        xdury@hotmail.com Xavier Dury added a comment -

        I noticed some differences between 1.1 and nightly build from 2004-07-29...

        with 1.1, I was able to call regular functions on objects like this:

        JXPathContext context = JXPathContext.newContext(new ArrayList());
        System.out.println(context.getValue("size"));

        which would give 0 (zero) as size.

        now with today's nightly build, I get:

        org.apache.commons.jxpath.JXPathException: Undefined function: size
        at org.apache.commons.jxpath.ri.JXPathContextReferenceImpl.getFunction
        (JXPathContextReferenceImpl.java:645)
        at org.apache.commons.jxpath.ri.axes.RootContext.getFunction
        (RootContext.java:118)
        at org.apache.commons.jxpath.ri.compiler.ExtensionFunction.computeValue
        (ExtensionFunction.java:83)
        at org.apache.commons.jxpath.ri.JXPathContextReferenceImpl.getValue
        (JXPathContextReferenceImpl.java:314)
        at org.apache.commons.jxpath.ri.JXPathContextReferenceImpl.getValue
        ...

        Any chance Kevin was talking about this problem?

        Show
        xdury@hotmail.com Xavier Dury added a comment - I noticed some differences between 1.1 and nightly build from 2004-07-29... with 1.1, I was able to call regular functions on objects like this: JXPathContext context = JXPathContext.newContext(new ArrayList()); System.out.println(context.getValue("size ")); which would give 0 (zero) as size. now with today's nightly build, I get: org.apache.commons.jxpath.JXPathException: Undefined function: size at org.apache.commons.jxpath.ri.JXPathContextReferenceImpl.getFunction (JXPathContextReferenceImpl.java:645) at org.apache.commons.jxpath.ri.axes.RootContext.getFunction (RootContext.java:118) at org.apache.commons.jxpath.ri.compiler.ExtensionFunction.computeValue (ExtensionFunction.java:83) at org.apache.commons.jxpath.ri.JXPathContextReferenceImpl.getValue (JXPathContextReferenceImpl.java:314) at org.apache.commons.jxpath.ri.JXPathContextReferenceImpl.getValue ... Any chance Kevin was talking about this problem?
        Hide
        dmitri@plotnix.com Dmitri Plotnikov added a comment -

        At some point I screwed up the implementation of InitialContext.getValue().
        That's now fixed.

        Show
        dmitri@plotnix.com Dmitri Plotnikov added a comment - At some point I screwed up the implementation of InitialContext.getValue(). That's now fixed.
        Hide
        xdury@hotmail.com Xavier Dury added a comment -

        still getting 'org.apache.commons.jxpath.JXPathException: Undefined function:
        size' with the above example and last build (2004-08-01).

        Show
        xdury@hotmail.com Xavier Dury added a comment - still getting 'org.apache.commons.jxpath.JXPathException: Undefined function: size' with the above example and last build (2004-08-01).
        Hide
        dmitri@plotnix.com Dmitri Plotnikov added a comment -

        Try it with JXPath 1.2. I ran your example verbatim, and it worked fine.

        Show
        dmitri@plotnix.com Dmitri Plotnikov added a comment - Try it with JXPath 1.2. I ran your example verbatim, and it worked fine.
        Hide
        xdury@hotmail.com Xavier Dury added a comment -

        As I'm still having the same problem with 1.2, I've been digging a little
        deeper: it seems that using setFunctions() on a context doesn't allow me to
        use regular functions anymore.

        I'm using the following custom implementation of JXPathContextFactory (which
        worked fine with 1.1):

        /**

        • JXPathContextFactory custom implementation.
        • @author xd
          */
          public class JXPathContextFactoryImpl extends
          JXPathContextFactoryReferenceImpl {

        /** The logger. */
        private static Log log = LogFactory.getLog(JXPathContextFactoryImpl.class);

        /** The function library. */
        private static FunctionLibrary library = new FunctionLibrary();

        static

        { log.trace("Initializing JXPath's TypeUtils."); TypeUtils.setTypeConverter(DefaultTypeConverter.getInstance()); log.trace("Initializing JXPath's DefaultFucntions."); library.addFunctions(new ClassFunctions (DefaultFunctions.class, "default")); }

        /** Default constructor. */
        public JXPathContextFactoryImpl()

        { log.trace("Instantiating custom JXPathContextFactory..."); }

        /**

        • @see org.apache.commons.jxpath.JXPathContextFactory#newContext
          (org.apache.commons.jxpath.JXPathContext,
        • java.lang.Object)
          */
          public JXPathContext newContext(JXPathContext inParentContext, Object
          inContextBean) throws JXPathContextFactoryConfigurationError { JXPathContext context = super.newContext(inParentContext, inContextBean); // The context should return null when accessing a non-existing node // instead of throwing an exception. context.setLenient(true); // Set the factory that will create nodes upon hibernate's metadata. context.setFactory(AbstractFactoryImpl.getInstance()); // Add some default functions. context.setFunctions(library); // THE cause... return context; }

          }

        When I remove the 'context.setFunctions(...)' line, I don't have any problem
        anymore.

            • Break ***

        After searching in CVS logs with a colleague, we found a way to circumvent the
        problem by doing the following:

        library.addFunctions(new PackageFunctions("", null));

        At least, it's working! Thanks for your time, I hope I haven't bothered you
        too much!

        Show
        xdury@hotmail.com Xavier Dury added a comment - As I'm still having the same problem with 1.2, I've been digging a little deeper: it seems that using setFunctions() on a context doesn't allow me to use regular functions anymore. I'm using the following custom implementation of JXPathContextFactory (which worked fine with 1.1): /** JXPathContextFactory custom implementation. @author xd */ public class JXPathContextFactoryImpl extends JXPathContextFactoryReferenceImpl { /** The logger. */ private static Log log = LogFactory.getLog(JXPathContextFactoryImpl.class); /** The function library. */ private static FunctionLibrary library = new FunctionLibrary(); static { log.trace("Initializing JXPath's TypeUtils."); TypeUtils.setTypeConverter(DefaultTypeConverter.getInstance()); log.trace("Initializing JXPath's DefaultFucntions."); library.addFunctions(new ClassFunctions (DefaultFunctions.class, "default")); } /** Default constructor. */ public JXPathContextFactoryImpl() { log.trace("Instantiating custom JXPathContextFactory..."); } /** @see org.apache.commons.jxpath.JXPathContextFactory#newContext (org.apache.commons.jxpath.JXPathContext, java.lang.Object) */ public JXPathContext newContext(JXPathContext inParentContext, Object inContextBean) throws JXPathContextFactoryConfigurationError { JXPathContext context = super.newContext(inParentContext, inContextBean); // The context should return null when accessing a non-existing node // instead of throwing an exception. context.setLenient(true); // Set the factory that will create nodes upon hibernate's metadata. context.setFactory(AbstractFactoryImpl.getInstance()); // Add some default functions. context.setFunctions(library); // THE cause... return context; } } When I remove the 'context.setFunctions(...)' line, I don't have any problem anymore. Break *** After searching in CVS logs with a colleague, we found a way to circumvent the problem by doing the following: library.addFunctions(new PackageFunctions("", null)); At least, it's working! Thanks for your time, I hope I haven't bothered you too much!
        Hide
        dmitri@plotnix.com Dmitri Plotnikov added a comment -

        Oh, yeah. That makes sense. The reason the behavior of JXPath has changed is
        this: a few people requested a way to disable the default PackageFunctions,
        because they presented a security problem. In some uses of JXPath, the XPath
        expressions are coming over an internet connection and therefore can be
        maliciously altered by a hacker. For example, the hacker may send something
        like "java.lang.System.exit(1)". For this reason, folks wanted more control
        over which functions could be called from an expression.

        Show
        dmitri@plotnix.com Dmitri Plotnikov added a comment - Oh, yeah. That makes sense. The reason the behavior of JXPath has changed is this: a few people requested a way to disable the default PackageFunctions, because they presented a security problem. In some uses of JXPath, the XPath expressions are coming over an internet connection and therefore can be maliciously altered by a hacker. For example, the hacker may send something like "java.lang.System.exit(1)". For this reason, folks wanted more control over which functions could be called from an expression.

          People

          • Assignee:
            Unassigned
            Reporter:
            kwongfu@hotmail.com Kevin Wong
          • Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:

              Development