NoSuchMethodError para tarros de versión diff

Hay un jar que tiene 2 versiones en la versión 1, principalmente 2 clases

Class A
Class B

Class A has a constructor as
A(X,B)

en la versión 2 hay principalmente 2 clases y una interfaz

Class A
Interface C
Class B implements C

Class A has a constructor as
A(X,C)

En mi clase util llamo al constructor de A

A a= new A(x,new B());

El código anterior es ant build usando jar 1, que se construye bien.

Ahora en producción env el jar en classpath es de la versión 2. y recibo un error como

NoSuchMethodError A.<init>(x;B)

No puedo entender que en la versión 2 jar B es la implementación de C, ¿por qué este error? Por favor ayudame a entender

Respuesta 1

Se debe al hecho de que está cambiando la firma de la función de un constructor . Si verifica el bytecode de su Utilclase, verá que está usando invokespecial, no invokevirtualopcode (los constructores y los métodos privados se llaman víainvokespecial ). invokespeciales realmente especial en el sentido de que hace enlace estático. Para una explicación más larga, sugiero leer esto: artículo

Invokespecial difiere de invokevirtual principalmente en que invokespecial selecciona un método basado en el tipo de referencia en lugar de la clase del objeto. En otras palabras, realiza un enlace estático en lugar de un enlace dinámico. En cada una de las tres situaciones en las que se utiliza invokespecial, el enlace dinámico no produciría el resultado deseado.

Con ese cambio de versión que realiza después de la compilación, en realidad está borrando el único constructor al que puede llamar su clase Util, y esta vez no puede confiar en el enlace dinámico.

Respuesta: 2

Mi apuesta es que la versión 1 todavía está al acecho en algún lugar de su classpath de producción junto con la versión 2 y es la primera que encuentra su cargador de clases.

De hecho, deberías tratar esto como una bendición porque de lo contrario tienes un pequeño error silencioso que nunca causará estragos hasta un momento aleatorio en el futuro cuando tu cargador de clase te dé v1 (sucede en mi compañía anterior y la producción se detiene por completo) semana).

Esto es a menudo difícil de depurar porque la versión 1 puede ser inyectada por otro frasco, guerra, por el contenedor, transitivamente por maven, accidentalmente al empacar el frasco / guerra, paquete de osgi, o peor: por un cargador de clases deshonesto (buena suerte con esto)

Si te lleva una eternidad resolver esto, cambiaría el nombre de A versión 2 a A2 si puedo para que tenga un nombre determinísticamente diferente (sí, esta es una solución fea).

Otra causa común es que JBoss no se limpia entre múltiples redespliegues. Entonces, cuando implementa la versión de la aplicación 567, classpath todavía tiene basura de la versión 566. Por lo general, esto se puede resolver haciendo una implementación limpia (elimine el proceso JBoss, elimine la carpeta temporal, vuelva a iniciarla)

Respuesta: 3

En primer lugar, soy nuevo en Java y Eclipse. En Visual Basic, agregaron una función que le permitía presionar el botón Ctrl para que el contenido de la ayuda sea transparente de forma temporal. Esto te permitió ...

Necesito analizar una expresión xpath para recuperar el nombre de nodo / atributo / predicado / etc. de la expresión para su posterior procesamiento. No me dirijo a un archivo xml específico. Para el xpath / root / nodeA [...

Estoy teniendo este extraño problema con Swing. Tengo un JPanel principal al que estoy agregando un JTabbedPane. Dentro de este JTabbedPane, estoy agregando otro panel: myTabbedPane.add (innerPanel, "Title", 0); ...

Los niños agregados solían ser visibles en todas mis subclases, como en el ejemplo aquí. Debido a algunos cambios recientes que hice (en una gran transferencia de código SWING de Java muy antiguo), los niños todavía son visibles en ...