让 ColdFusion 调用的 Web 服务与 JavaLoader 加载的对象一起工作 [英] Getting ColdFusion-Called Web Service to Work with JavaLoader-Loaded Objects

查看:19
本文介绍了让 ColdFusion 调用的 Web 服务与 JavaLoader 加载的对象一起工作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

是否可以使用 JavaLoader 来获取由 CF 调用的 Web 服务返回的对象,并且 JavaLoader 加载的对象是相同的类路径上下文?我的意思是,没有很多困难?

//获取网络服务ws = createObject("webservice", local.lms.wsurl);//coldfusion创建的用户用户 = ws.GenerateUserObject();/* java loader 创建的用户状态.** 此 api 提供程序要求您移动存根**(第一次从 CF 访问 wsdl 时生成)** 到类路径.** 这是从中调用的存根/类之一.*/UserStatus = javaLoader.create("com.geolearning.geonext.webservices.Status");//设置用户状态:类路径上下文冲突user.setStatus(UserStatus.Active);

错误:

  • 详细信息:要么没有具有指定方法名称的方法,要么参数类型或 setStatus 方法被参数重载ColdFusion 无法可靠破译的类型.冷融合 找到 0与提供的参数匹配的方法.如果这是一个 Java 对象并且您验证了该方法存在,请使用 javacast 函数减少歧义.
  • 消息:未找到 setStatus 方法.
  • 方法名设置状态

尽管表面上调用匹配用户上的方法签名--setStatus(com.geolearning.geonext.webservices.Status)--该类位于不同的类路径上下文中.这就是我收到上述错误的原因.

解决方案

Jamie 和我在这个线下工作并想出了一个创造性的解决方案 :)

(对于冗长的回答,我深表歉意,但我认为对于那些发现类加载器和我一样令人困惑的人来说,有必要进行一些解释.如果您对为什么"方面不感兴趣,请随时跳到结束).

问题:

问题肯定是由于多个类加载器/路径造成的.显然 CF Web 服务使用 dynamic 方法).

解决方案:

最后我有一个疯狂的想法:不要加载任何 jars.只需将 Web 服务的加载器用作 parentClassLoader.它已经在自己的类路径"中拥有所需的一切:

//显示 web 服务类加载器的类路径dynamicLoader = webService.getClass().getClassLoader();dynamicClassPath = dynamicLoader.getURLS();WriteDump("类路径:"&dynamicClassPath[1].toString());

JavaLoader 会自动将它找不到的类的调用委托给 parentClassLoader - 并且宾果游戏 - 一切正常.不再有类加载器冲突.

 webService = createObject("webservice", webserviceURL, webserviceArgs);javaLoader = createObject("组件", "javaloader.JavaLoader").init(loadPaths = []//没有, parentClassLoader=webService.getClass().getClassLoader());用户 = webService.GenerateUserObject();userStatus = javaLoader.create("com.geolearning.geonext.webservices.Status");user.setStatus(userStatus.Active);WriteDump(var=user.getStatus(), label="SUCCESS: user.getStatus()");

Is it possible to use JavaLoader to get objects returned by CF-called web services, and JavaLoader-loaded objects to be the same classpath context? I mean, without a lot of 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:

  • Detail: Either there are no methods with the specified method name and argument types or the setStatus method is overloaded with argument types that ColdFusion cannot decipher reliably. ColdFusion found 0 methods that match the provided arguments. If this is a Java object and you verified that the method exists, use the javacast function to reduce ambiguity.
  • Message: The setStatus method was not found.
  • MethodName setStatus

Even though the call, on the surface, matches a method signature on user--setStatus(com.geolearning.geonext.webservices.Status)--the class is on a different classpath context. That's why I get the error above.

解决方案

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()");

这篇关于让 ColdFusion 调用的 Web 服务与 JavaLoader 加载的对象一起工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆