web-services coldfusion classpath coldfusion-9 javaloader

web services - Hacer que el servicio web llamado ColdFusion trabaje con objetos cargados con JavaLoader



web-services classpath (1)

¿Es posible usar JavaLoader para que los objetos devueltos por los servicios web llamados CF y los objetos cargados por JavaLoader sean el mismo contexto de classpath? Quiero decir, sin mucha dificultad?

// 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:

  • Detalle: O no hay métodos con el nombre del método y los tipos de argumentos especificados o el método setStatus está sobrecargado con tipos de argumentos que ColdFusion no puede descifrar de manera confiable. ColdFusion encontró 0 métodos que coinciden con los argumentos proporcionados. Si se trata de un objeto Java y ha verificado que existe el método, use la función javacast para reducir la ambigüedad.
  • Mensaje: no se encontró el método setStatus.
  • MethodName setStatus

Aunque la llamada, en la superficie, coincide con una firma de método en el usuario - setStatus (com.geolearning.geonext.webservices.Status) - la clase se encuentra en un contexto diferente de classpath. Es por eso que recibo el error anterior.


Jamie y yo trabajamos en esto fuera de línea y se nos ocurrió una solución creativa :)

(Disculpas por la respuesta larga, pero pensé que se justificaba una pequeña explicación para aquellos que encuentran que los cargadores de clases son tan confusos como yo. Si no estás interesado en el aspecto "por qué", no dudes en saltar al final).

Problema:

El problema es definitivamente debido a los cargadores / rutas de múltiples clases. Aparentemente, los servicios web de CF utilizan un URLClassLoader dinámico (como el JavaLoader). Así es como puede cargar las clases de servicio web generadas sobre la marcha, a pesar de que esas clases no se encuentran en la " ruta de clase " del núcleo CF.

(Basado en mi entendimiento limitado ...) Los cargadores de clases siguen una jerarquía. Cuando hay cargadores de clases múltiples, deben observar ciertas reglas o no jugarán bien juntos. Una de las reglas es que los cargadores de clase para niños solo pueden "ver" objetos cargados por un antecesor (padre, abuelo, etcétera). No pueden ver clases cargadas por un hermano .

Si examina el objeto creado por JavaLoader y el otro por createObject , en realidad son hermanos, es decir, ambos hijos del cargador de clase de arranque CF. Entonces uno no reconocerá los objetos cargados por el otro, lo que explicaría por qué setStatus llamada setStatus .

Dado que un niño puede ver objetos cargados por un padre, la solución obvia es cambiar cómo se construyen los objetos. Estructurar las llamadas para que uno de los cargadores de clase termine como padre del otro. Curiosamente, resultó ser más complicado de lo que parecía. No pude encontrar una manera de hacerlo posible, a pesar de probar varias combinaciones (incluido el uso del método switchThreadContextClassLoader ).

Solución:

Finalmente tuve una loca idea: no cargues ningún tarro. Simplemente use el cargador del servicio web como parentClassLoader . Ya tiene todo lo que necesita en su propio "camino de clase" individual:

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

JavaLoader delegará automáticamente llamadas para clases que no puede encontrar en parentClassLoader , y en bingo, todo funciona. No más conflictos de cargador de clases.

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