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/11 00:19:27 UTC

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