Getting ColdFusion-Called Web Service to Work with JavaLoader-Loaded Objects

纵饮孤独 提交于 2019-11-28 02:03:20

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

(Apologies for the long answer, but I thought a bit of an explanation was warranted for those who find class loaders as confusing as I do. If you are not interested in the "why" aspect, feel free to jump to the end).

Issue:

The problem is definitely due to multiple class loaders/paths. Apparently CF web services use a dynamic URLClassLoader (just like the JavaLoader). That is how it can load the generated web service classes on-the-fly, even though those classes are not in the core CF "class path".

(Based on my limited understanding...) Class loaders follow a hierarchy. When multiple class loaders are involved, they must observe certain rules or they will not play well together. One of the rules is that child class loaders can only "see" objects loaded by an ancestor (parent, grandparent, etcetera). They cannot see classes loaded by a sibling.

If you examine the object created by the JavaLoader, and the other by createObject, they are indeed siblings ie both children of the CF bootstrap class loader. So the one will not recognize objects loaded by the other, which would explain why the setStatus call failed.

Given that a child can see objects loaded by a parent, the obvious solution is to change how the objects are constructed. Structure the calls so that one of the class loaders ends up as a parent of the other. Curiously that turned out to be trickier than it sounded. I could not find a way to make that happen, despite trying a number of combinations (including using the switchThreadContextClassLoader method).

Solution:

Finally I had a crazy thought: do not load any jars. Just use the web service's loader as the parentClassLoader. It already has everything it needs in its 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() );

The JavaLoader will automatically delegate calls for classes it cannot find to parentClassLoader - and bingo - everything works. No more more class loader conflict.

    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()");
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!