You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by "Matt Benson (JIRA)" <ji...@apache.org> on 2007/01/05 19:28:27 UTC

[jira] Commented: (JXPATH-10) [jxpath] JXPath 1.1 code using custom functions failing when run in 1.2 onwards

    [ https://issues.apache.org/jira/browse/JXPATH-10?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#action_12462553 ] 

Matt Benson commented on JXPATH-10:
-----------------------------------

Okay... this bug is a little more than a year old, so I'm not sure how the original reporter has fared since its origination, but anyway:

As you may have realized, this regression is an artifact of the feature added with JXPath 1.2 whereby an Object argument signifies that Pointers and NodeSets should be decoded to the objects they represent.  I hope to have a fairly easy workaround completed soon.  More later...

> [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: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org