4

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

// 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);

错误:

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

即使从表面上看,该调用与用户上的方法签名匹配——setStatus(com.geolearning.geonext.webservices.Status)——该类位于不同的类路径上下文中。这就是为什么我得到上面的错误。

4

1 回答 1

5

Jamie 和我在此离线工作并提出了一个创造性的解决方案 :)

(为冗长的答案道歉,但我认为对于那些发现类加载器和我一样令人困惑的人来说,有必要进行一些解释。如果您对“为什么”方面不感兴趣,请随意跳到最后)。

问题:

问题肯定是由于多个类加载器/路径。显然 CF Web 服务使用动态 URLClassLoader(就像 JavaLoader 一样)。这就是它可以即时加载生成的 Web 服务类的方式,即使这些类不在核心 CF“类路径”中。

(基于我有限的理解......)类加载器遵循层次结构。当涉及多个类加载器时,它们必须遵守一定的规则,否则它们将无法很好地协同工作。规则之一是子类加载器只能“看到”由祖先(父母、祖父母等)加载的对象。他们看不到兄弟姐妹加载的类。

如果您检查由 JavaLoader 创建的对象,另一个由createObject. 因此,一个将无法识别另一个加载的对象,这可以解释setStatus调用失败的原因。 两个对象的子类和父类加载器

鉴于孩子可以看到父母加载的对象,显而易见的解决方案是更改对象的构造方式。对调用进行结构化,以便其中一个类加载器最终成为另一个类加载器的父级。奇怪的是,事实证明这比听起来更棘手。尽管尝试了多种组合(包括使用switchThreadContextClassLoader方法),但我找不到实现这一目标的方法。

解决方案:

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

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

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

    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()");
于 2013-03-23T21:10:08.760 回答