Pregunta

La pregunta de IMY se refiere al comportamiento del lanzamiento de tipo con proxy dinámico y genéricos Java. Más específicamente, quiero instrumentar un objeto Servelet usando proxy dinámico. Para una mejor reutilización, adopté alguna plantilla de código genérico para crear objetos proxy como se muestra a continuación.

@SuppressWarnings("unchecked")
public static <T> T instrument(final T aT) {
    T proxy = (T) Proxy.newProxyInstance(aT.getClass().getClassLoader(), new Class[]{MyServelet.class}, new InvocationHandler() {
        @Override
        public Object invoke(Object aProxy, Method aMethod, Object[] aArgs) throws Throwable {
        ..... instrumentation logic goes here
        }
    });
     System.out.println("proxy class " + proxy.getClass());
     System.out.println("input class " + aT.getClass());
     return proxy;
}

Aquí está mi clase de implementación de servelet concreto que implementa la interfaz MyServelet. Sin embargo, si ejecuto el método anterior, se imprime

proxy class class com.sun.proxy.$Proxy0
input class class MyServeletImplementation

Así que me pregunto qué pasó con la declaración de casting de tipo en el fragmento de código. Parece que falló en silencio ya que el proxy no fue lanzado a MyServeletimplementation, pero tampoco lanzó ClassCastException. ¿Alguien puede arrojarme algo de luz sobre esto? ¡Gracias!

¿Fue útil?

Solución

Ningún elenco tuvo lugar en el bytecodo compilado real del método, debido a Tipo de borrado.

Al generar bytecode, el compilador trata cualquier variable de un tipo de parámetro que tiene el mismo tipo que el límite superior del tipo de parámetro, o Object Si el tipo está ilimitado. Así que si T en tu método tenía la restricción <T extends MyServelet>, el compilador habría tratado proxy Como una variable de tipo MyServelet, e insertó un elenco. Sin embargo, como T está ilimitado, se trata como una variable de tipo Object - Por lo tanto, no hay elenco.

Otros consejos

El punto del proxy dinámico es que no le importa la clase real del proxy que se está devuelta. Solo le importa que implementa todas las interfaces deseadas y especificadas.

Los javadocs para newProxyInstance estado:

Devoluciones:

Una instancia proxy con el controlador de invocación especificado de una clase proxy que está definida por el cargador de clase especificado y que implementa las interfaces especificadas

Asi que, newProxyInstance devolvió una instancia de com.sun.proxy.$Proxy0 (sea lo que sea, realmente no nos importa), pero también se aseguró de que sea un MyServelet. Deberías poder lanzarlo MyServelet sin un ClassCastException, porque newProxyInstance creó la clase para implementar esa interfaz, y usted especificó que debería pasar new Class[]{MyServelet.class}.

Para que el tipo de casting no haya fallado, Java Genély debe haber inferido que T es MyServelet, no MyServeletImplementation. Quizás cuando llamaste instrument, lo hiciste así:

MyServelet proxy = YourClass.instrument(new MyServeletImplementation());

Entonces el elenco era MyServelet que debería tener éxito y no MyServeletImplementation, que debería fallar.

La razón por la que necesitabas agregar @SuppressWarnings("unchecked") es porque el compilador estaba tratando de advertirte que estabas haciendo algo mal. Al agregar la supresión, le dijo al compilador que no le importaba porque sabía lo que estaba haciendo. ¿Quizás no deberías haber agregado la anotación si no Uderstanding por qué recibías la advertencia en primer lugar?

Sugerencia: el elenco genérico T proxy = (T) se convierte en Object proxy = (Object) por el compilador. ("Escriba borrado" como se menciona en otra respuesta).

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top