[ https://issues.apache.org/jira/browse/JXPATH-10?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]
Matt Benson resolved JXPATH-10. ------------------------------- Resolution: Fixed Hi Paul, I have committed to SVN HEAD a TypeConverter implementation that bypasses the Pointer conversions introduced in version 1.2 . In order to use it, you must first execute the following: TypeUtils.setTypeConverter(new JXPath11CompatibleTypeConverter()); And I think that's the best I'll be able to do for you. > [jxpath] JXPath 1.1 code using custom functions failing when run in 1.2 > onwards > ------------------------------------------------------------------------------- > > Key: JXPATH-10 > URL: https://issues.apache.org/jira/browse/JXPATH-10 > Project: Commons JXPath > Issue Type: Bug > Affects Versions: 1.2 Final > Environment: Operating System: other > Platform: PC > Reporter: Paul Parisi > Priority: Blocker > Fix For: 1.3 > > > We have recently attempted to upgrade from a 1.1 release of jxpath > to 1.2 and found a great deal of our jxpath code fails to run correctly. > We isolated the problem to relating to the use of Custom Extension > Functions and have included sample junit test case snippets that should > demonstrate the issue clearly. > The background on what we are trying to do with jxpath is as follows > (included so its clear on what we are trying to use jxpath to achieve): > Within our project, we make extensive use of Custom Extension Functions in > JXPath. > We also use JXPath variables significantly, in combination with these > functions, > that often take a JXPath variable as an argument(s) to the function. > We now rely heavily on the use of the ExpressionContext interface as the > first > argument to many of our functions. The reason for this is that we need a > convienient way to obtain access to 'original' object references within the > context invoked by the function (as you would expect). > However, we have also begun using a very useful combination of features, which > the API supports in version 1.1, where the first argument always defines the > ExpressionContext interface (which isn't really part of the method signature - > from a caller perspective), and a 2nd argument as 'Object' type. Within body > of > the function, we then cast the object of the 2nd argument as a NodeSet (or > define the NodeSet type within the method signature - either appears to work), > which provides us with access to the pointers for the object. > As previously mentioned, a jxpath variable is passed from the caller of the > function (received via the 2nd argument in the method signature), which is > automatically resolved, by jxpath, to the object itself. > The benefit of casting the object to NodeSet (interface) enables us to > retrieve > the first pointer in the NodeSet list. The first pointer concerns us, as it > refers to the String value passed to the argument of the function which we > need > access to. The object reference itself is of little concern in this case, as > once we have access to the variable name sent to the function, we can access > the > object via the ExpressionContext. > This all works fine in jxpath 1.1, however, in version 1.2 this functionality > is > now broken, since our objects are no longer being cast to NodeSet (previously > achieved via the internal implementation of jxpath NodeSet using a > SimpleNodeSet > - as per inspecting jxpath 1.1 source code). > Note on the use of ExpressionContext: For those methods that declare the > ExpressionContext interface (which must be the first argument, if used), as > part > of the argument list, the method signature from the caller perspective, > excludes > it from the argument list, as it is implied by jxpath. In other words, there > will be one less argument from the caller when the interface is used. In the > case where this interface was the only argument, which is common, then the > caller would be invoking a zero-argument method. This is behaviour we expect. > Here is a simplified example of one of our functions using the techniques > discussed:- > public static void deleteSomeObject(ExpressionContext expContext, Object obj) > { > // create a local jxpath context to retrieve values for jxpath variables > JXPathContext localContext = expContext.getJXPathContext(); > // Nodeset of the object passed to method > NodeSet nodeset = (NodeSet)obj; > // Retrieve variable name passed to function > String declaredVariable = nodeset.getPointers().get(0).toString(); > Object objectToDelete = null; > // If this method was passed the $obj1 var to delete, then retrieve 'Object > Type > 1' via $obj1 variable > if (declaredVariable.equals("$obj1")) { > objectToDelete = (ObjectType1)localContext.getValue("$obj1"); > } > // If this method was passed the $obj2 var to delete, then retrieve > 'Object > Type 2' via $obj2 variable > if (declaredVariable.equals("$obj2")) { > objectToDelete = (ObjectType2)localContext.getValue("$obj2"); > } > collectionOfSomeObjects.delete(objectToDelete); > } > Which would be used (called) in the following way:- > ... > // add to collection > ObjectType1 objectType1 = new ObjectType1(); > ObjectType2 objectType2 = new ObjectType2(); > CollectionOfSomeObjects.add(objectType1); > CollectionOfSomeObjects.add(objectType2); > // add collection to jxpath context > JXPathContext context = JXPathContext.newContext(collectionOfSomeObjects); > // define jxpath variables > context.getVariables().declareVariable("obj1", objectType1); > context.getVariables().declareVariable("obj2", objectType2); > // call jxpath Custom Extension Function > String method2Invoke; > method2Invoke = "ftn:deleteSomeObject($obj1)" > context.getValue(method2Invoke); // ß invoke function & return value (for > non-void methods) > method2Invoke = "ftn:deleteSomeObject($obj2)" > context.getValue(method2Invoke); // ß invoke function & return value (for > non-void methods) > In addition to the above example, I have prepared a suite of JUnit tests (& > functions) that work against JXPath version 1.1, > but fail against version 1.2. These code snippets can simply be dropped into > the appropriate classes and executed. > Also, I would like to note that the JXPath user guide is a little unclear with > respect to the use of NodeSet's. > After looking at many of the existing JUnit tests for JXPath, many > un-documented > features became evident & existing features became a little obscure, such as > 'Collections as NodeSets'. > The code examples provided should give you our perspective on it's use. > CODE SNIPPETS BELOW TO INSERT INTO EXISTING JXPATH TEST SUITE: > Below you will find two sections:- > (1) JUnit Tests to test Extension Functions > (2) Additional Extension Functions for these new tests > --------------------------------------------------------------------------------------------------------- > 3 JUnit Tests to add to 'ExtensionFunctionTest.java" (in package > org.apache.commons.jxpath.ri.compiler) : > /** > * To test the use of NodeSet to retrieve String value passed to argument > of > method > */ > public void testMyTestNodeSetOnly() { > > context.getVariables().declareVariable("obj1", new String("$12345.00")); > assertXPathValue( > context, > "test:myTestNodeSetOnly($obj1)", > "$obj1"); > > } > /** > * To test the use of ContextExpression & NodeSet Combined > */ > public void testMyTestContextExpressionAndNodeSetCombined() { > HashMap map = new HashMap(); > map.put("1",new String("Item 1")); > map.put("2",new String("Item 2")); > map.put("3",new String("Item 3")); > > context.getVariables().declareVariable("obj2", map); > assertXPathValue( > context, > "test:myTestContextExpressionAndNodeSetCombined($obj2)", > "$obj2"); > > } > > /** > * To test the use of ContextExpression & NodeSet Combined with additional > arguments > */ > public void testMyTestContextExpressionAndNodeSetCombinedExtraArgs() { > HashMap map = new HashMap(); > map.put("1",new String("Item 1")); > map.put("2",new String("Item 2")); > map.put("3",new String("Item 3")); > HashMap map2 = new HashMap(); > map2.put("another collection",map); > map2.put("a bean",new TestBean()); > TestBean testBean = new TestBean(); > Map beanMap = testBean.getMap(); > context.getVariables().declareVariable("obj1", beanMap); > context.getVariables().declareVariable("obj2", map2); > context.getVariables().declareVariable("obj3", testBean); > context.getVariables().declareVariable("obj4", new Integer(10)); > assertXPathValue( > context, > > "test:myTestContextExpressionAndNodeSetCombinedExtraArgs($obj1, > $obj2, $obj3, $obj4)", > "$obj1"); > > } > > --------------------------------------------------------------------------------------------------------- > 3 Additional Functions to add to 'TestFunctions.java' (in package > org.apache.commons.jxpath.ri.compiler) : > > > public static String myTestNodeSetOnly(NodeSet obj) { > // Nodeset of the object passed to method > NodeSet nodeset = (NodeSet)obj; > > // Retrieve variable name passed to function > String declaredVariable = ""; > declaredVariable = nodeset.getPointers().get(0).toString(); > > // for (int i=0; i < nodeset.getPointers().size();i++ ) { > // declaredVariable = > nodeset.getPointers().get(i).toString(); > // System.out.println(" declaredVariable Name = > "+declaredVariable+" > value ="+nodeset.getNodes().get(i)); > // > // } > // System.out.println(" declaredVariable Name = "+declaredVariable); > > > return declaredVariable; > } > public static String > myTestContextExpressionAndNodeSetCombined(ExpressionContext expContext, Object > obj) { > // create a local jxpath context to retrieve values for jxpath variables > JXPathContext localContext = expContext.getJXPathContext(); > // Nodeset of the object passed to method > NodeSet nodeset = (NodeSet)obj; > > // Retrieve variable name passed to function > String declaredVariable = > nodeset.getPointers().get(0).toString(); > > // System.out.println(" declaredVariable Name = "+declaredVariable); > HashMap object = (HashMap)localContext.getValue(declaredVariable); > // System.out.println(" declaredVariable reference to object via > context > = "+object); > > > return declaredVariable; > } > public static String > myTestContextExpressionAndNodeSetCombinedExtraArgs(ExpressionContext > expContext, > Object obj1, Object obj2, Object obj3, Object obj4 ) { > // create a local jxpath context to retrieve values for jxpath variables > JXPathContext localContext = expContext.getJXPathContext(); > // Nodesets of the object(s) passed to method > NodeSet nodeset1 = (NodeSet)obj1; > NodeSet nodeset2 = (NodeSet)obj2; > NodeSet nodeset3 = (NodeSet)obj3; > NodeSet nodeset4 = (NodeSet)obj4; > > // Retrieve variable name passed to function > String declaredVariable = > nodeset1.getPointers().get(0).toString(); > > // System.out.println(" declaredVariable 1 Name = "+declaredVariable); > HashMap object = (HashMap)localContext.getValue(declaredVariable); > // System.out.println(" declaredVariable reference to object via > context > = "+object); > > return declaredVariable; > } -- This message is automatically generated by JIRA. - If you think it was sent incorrectly contact one of the administrators: https://issues.apache.org/jira/secure/Administrators.jspa - For more information on JIRA, see: http://www.atlassian.com/software/jira --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]