Acquisition of the ColdFusion Web Service for Working with JavaLoader Loaded Objects

Is it possible to use JavaLoader to retrieve objects returned by CF-called web services, and objects loaded by JavaLoader into the same pathpath context? I mean, without much difficulty?

// get a web service ws = createObject("webservice", local.lms.wsurl); // user created by coldfusion user = ws.GenerateUserObject(); /* user status created by java loader. ** this api provider requires that you move the stubs ** (generated when hitting the wsdl from CF for the first time) ** to the classpath. ** this is one of the stubs/classes that gets called from that. */ UserStatus = javaLoader.create("com.geolearning.geonext.webservices.Status"); // set user status: classpath context clash user.setStatus(UserStatus.Active); 

Error:

  • In detail: either there are no methods with the specified method name and argument types or the setStatus method is overloaded with an argument that ColdFusion cannot reliably decrypt. ColdFusion found 0 methods that match the supplied arguments. If it is a Java object and you have confirmed that the method exists, use the javacast function to reduce the ambiguity.
  • Message: method setStatus not found.
  • Username setStatus

Despite the fact that the call on the surface matches the method signature on the user - setStatus (com.geolearning.geonext.webservices.Status) - the class is in a different pathpath context. That is why I got the error above.

+4
source share
1 answer

Jamie and I worked on this off-line and came up with a creative solution :)

(Apologies for the long answer, but I thought a little explanation was justified for those who thought the cool downloaders were just as confusing as I. If you are not interested in the β€œwhy” aspect, feel free to skip to the end).

Question:

The problem is certainly related to several class loaders / paths. Apparently CF web services use a dynamic URLClassLoader (like JavaLoader). Thus, it can load created web service classes on the fly, although these classes are not part of the base class class path .

(Based on my limited understanding ...) class loaders follow the hierarchy. When multiple class loaders are involved, they must abide by certain rules or they interact poorly with each other. One of the rules is that child class loaders can only "see" objects loaded by their ancestor (parent, grandfather, etc.). They cannot see classes loaded by sibling.

If you examine the object created by JavaLoader and the other, createObject , they really are siblings, that is, both children of the bootstrap CF class loader. This way, one will not recognize objects loaded by the other, which explains why the setStatus call failed. Child and Parent class loader of the two objects

Given that the child can see the objects loaded by the parent, the obvious solution is to change the way the objects are constructed. Make calls so that one of the class loaders appears in the role of the parent of the other. Curiously, it turned out to be harder than it sounded. I could not find a way to do this, despite trying a number of combinations (including the switchThreadContextClassLoader method).

Decision:

Finally, I thought: do not load cans. Just use the web services loader as parentClassLoader . He already has everything he needs in his own individual β€œclass path”:

  // display class path of web service class loader dynamicLoader = webService.getClass().getClassLoader(); dynamicClassPath = dynamicLoader.getURLS(); WriteDump("CLASS PATH: "& dynamicClassPath[1].toString() ); 

JavaLoader automatically delegates calls to classes that it cannot find in parentClassLoader - and bingo - everything works. The classloader no longer conflicts.

  webService = createObject("webservice", webserviceURL, webserviceArgs); javaLoader = createObject("component", "javaloader.JavaLoader").init( loadPaths = [] // nothing , parentClassLoader=webService.getClass().getClassLoader() ); user = webService.GenerateUserObject(); userStatus = javaLoader.create("com.geolearning.geonext.webservices.Status"); user.setStatus(userStatus.Active); WriteDump(var=user.getStatus(), label="SUCCESS: user.getStatus()"); 
+5
source

All Articles