¿Cómo funcionan las anotaciones como @Override internamente en Java?

9 minutos de lectura

avatar de usuario
chirag dasani

¿Alguien puede explicarme cómo funcionan las anotaciones internamente en Java?

Sé cómo podemos crear anotaciones personalizadas usando la biblioteca java.lang.annotation en java. Pero todavía no entiendo cómo funciona internamente, por ejemplo, la anotación @Override.

Estaré muy agradecido si alguien pudiera explicar eso en detalle.

  • ¿A qué te refieres con “trabajar internamente”? El compilador? ¿El tiempo de ejecución?

    – chrylis -cautelosamente optimista-

    12 de agosto de 2013 a las 14:45

  • @chrylis Work internamente significa cómo se identifica automáticamente que este método es un método de anulación o este no es un método de anulación. Es trabajo en ambos tiempos. como anular el trabajo de anotación en tiempo de compilación y la anotación del controlador de primavera funciona en tiempo de ejecución

    – Chirag Dasani

    13 de agosto de 2013 a las 6:45

La primera distinción principal entre los tipos de anotación es si se usan en tiempo de compilación y luego se descartan (como @Override) o colocado en el archivo de clase compilado y disponible en tiempo de ejecución (como Spring’s @Component). Esto está determinado por el @Retencion política de la anotación. Si está escribiendo su propia anotación, debe decidir si la anotación es útil en tiempo de ejecución (quizás para la configuración automática) o solo en tiempo de compilación (para verificación o generación de código).

Al compilar código con anotaciones, el compilador ve la anotación del mismo modo que ve otros modificadores en los elementos fuente, como los modificadores de acceso (public/private) o final. Cuando encuentra una anotación, ejecuta un procesador de anotaciones, que es como una clase de complemento que dice que está interesada en una anotación específica. El procesador de anotaciones generalmente usa la API de Reflection para inspeccionar los elementos que se están compilando y puede simplemente ejecutar controles en ellos, modificarlos o generar código nuevo para compilar. @Override es un ejemplo del primero; utiliza la API de Reflection para asegurarse de que puede encontrar una coincidencia para la firma del método en una de las superclases y utiliza el Messager para causar un error de compilación si no puede.

Hay varios tutoriales disponibles sobre cómo escribir procesadores de anotaciones; aquí hay uno útil. Mire a través de los métodos en la Processor interfaz para saber cómo el compilador invoca un procesador de anotaciones; la operación principal tiene lugar en el process método, que se llama cada vez que el compilador ve un elemento que tiene una anotación coincidente.

  • sería bueno señalarnos exactamente cómo el procesador de anotaciones de Spring analiza el @Componente e inyecta la clase en su contenedor

    -Junchen Liu

    18 mayo 2016 a las 14:32

  • @shanyangqu Eso está fuera de tema para la pregunta, que no es específica de Spring. Puede leer las clases del posprocesador usted mismo.

    – chrylis -cautelosamente optimista-

    18 mayo 2016 a las 14:39

avatar de usuario
eugenio

Además de lo que otros sugirieron, te recomiendo que escribas una anotación personalizada y su procesador desde cero para ver cómo funciona la anotación.

En el mío, por ejemplo, he escrito una anotación para verificar si los métodos están sobrecargados en tiempo de compilación.

En primer lugar, cree una anotación llamada Overload. Esta anotación se aplica al método, así que la anoto con @Target(value=ElementType.METHOD)

package gearon.customAnnotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Target;

@Target(value=ElementType.METHOD)
public @interface Overload {

}

A continuación, cree el procesador correspondiente para manejar los elementos anotados por la anotación definida. Para el método anotado por @Overload, su firma debe aparecer más de una vez. O se imprime el error.

package gearon.customAnnotation;

import java.util.HashMap;
import java.util.Map.Entry;
import java.util.Set;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic.Kind;

@SupportedAnnotationTypes("gearon.customAnnotation.Overload")

public class OverloadProcessor extends AbstractProcessor{

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        // TODO Auto-generated method stub
        HashMap<String, Integer> map = new HashMap<String, Integer>();

        for(Element element : roundEnv.getElementsAnnotatedWith(Overload.class)){
            String signature = element.getSimpleName().toString();
            int count = map.containsKey(signature) ? map.get(signature) : 0;
            map.put(signature, ++count);
        }

        for(Entry<String, Integer> entry: map.entrySet()){
            if(entry.getValue() == 1){
                processingEnv.getMessager().printMessage(Kind.ERROR, "The method which signature is " + entry.getKey() +  " has not been overloaded");
            }
        }
        return true;
    }
}

Después de empaquetar la anotación y su proceso en un archivo jar, cree una clase con @Overload y use javac.exe para compilarlo.

import gearon.customAnnotation.Overload;

public class OverloadTest {
    @Overload
    public static void foo(){
    }

    @Overload
    public static void foo(String s){

    }

    @Overload
    public static void nonOverloadedMethod(){

    }
} 

Ya que nonOverloadedMethod() en realidad no se ha sobrecargado, obtendremos el resultado como se muestra a continuación:

ingrese la descripción de la imagen aquí

  • La información anterior es muy buena con respecto a JDK6 (+1 para eso), pero ¿cómo lograr lo mismo usando JDK5 también? Usando JDK6 SupportedAnnotationTypes, la clase AbstractProcessor se volvió más simple, pero ¿cómo sucedió lo mismo en el pasado (como Spring FrameWork 2.5 en jdk5)? ¿Cómo JVM detecta el procesador de anotaciones como la clase en jdk5? ¿Puede guiarse editando la respuesta en 2 secciones (una para JDK5, la versión actual es para Jdk6 +)?

    – prajitgandhi

    29 de enero de 2017 a las 19:12

  • En tu clase OverloadProcessor::process porque es entry.getValue() == 1? No es necesario agregar una anotación en la clase/interfaz principal, por lo que roundEnv.getElementsAnnotatedWith(Overload.class) no obtendrá la clase/interfaz principal, ¿verdad?

    – VimNing

    16 de octubre de 2019 a las 2:51

  • Estoy confundido en esta parte, pero creo que su respuesta es muy útil.

    – VimNing

    16 de octubre de 2019 a las 2:54

  • @s̮̦̩e̝͓c̮͔̞ṛ̖̖e̬̣̦t̸͉̥̳̼ Si un método se trata como sobrecarga, debe haber al menos otro método con el mismo nombre definido en la clase.

    – Eugenio

    16 de octubre de 2019 a las 3:11

  • @Raining para que un método diga Sobrecargado, debe aparecer más de una vez en la misma clase, pero si es ` == 1`, entonces es un error.

    – KrishPrabakar

    17 de junio de 2020 a las 14:02

Aquí está @Override: http://www.docjar.com/html/api/java/lang/Override.java.html.

No tiene nada especial que lo diferencie de una anotación que podría escribir usted mismo. Las partes interesantes están en el consumidores de las anotaciones. Para una anotación como @Overrideeso estaría en el propio compilador de Java, o en una herramienta de análisis de código estático, o en su IDE.

  • Conozco el código fuente de la anotación Anular. Pero cómo funciona internamente. ¿Cómo se puede identificar que este método no es un método de anulación o este es un método de anulación? ¿O puedo crear mi anotación de anulación personalizada? y debería funcionar exactamente con el mismo comportamiento que la anotación de anulación de Java

    – Chirag Dasani

    13 de agosto de 2013 a las 6:31

  • Como dije en mi respuesta, el comportamiento no es parte de la anotación. La interpretación está en las cosas que consumen la anotación. Por eso, a menos que cambie el consumidor, prácticamente no puede crear su propia versión personalizada de @Override (u otras anotaciones estándar).

    – bola mate

    13 de agosto de 2013 a las 13:55

Básicamente, las anotaciones son solo marcadores que lee el compilador o la aplicación. Según su política de retención, están disponibles solo en tiempo de compilación o se pueden leer en tiempo de ejecución mediante la reflexión.

Muchos marcos utilizan la retención en tiempo de ejecución, es decir, comprueban reflexivamente si algunas anotaciones están presentes en una clase, método, campo, etc. y hacen algo si la anotación está presente (o no). Además, los miembros de las anotaciones se pueden usar para pasar más información.

avatar de usuario
Ruchira Gayan Ranaweera

Sigue esto Enlace. Esto proporcionará una respuesta cercana a su problema. Si nos centramos en las anotaciones en Java, las anotaciones se introdujeron en Java 5 y no son específicas de Spring. En general, las anotaciones le permiten agregar metadatos a una clase, método o variable. Una anotación puede ser interpretada por el compilador (por ejemplo, la anotación @Override) o por un marco como Spring (por ejemplo, la anotación @Component).

Además estoy agregando más referencias.

  1. http://www.codeproject.com/Articles/272736/Understanding-Annotations-in-Java
  2. http://docs.oracle.com/javase/7/docs/api/java/lang/annotation/package-summary.html
  3. http://www.coderanch.com/how-to/java/AnnotationsExample

  • @LuiggiMendoza java 1.7 documento de anotaciones agregado

    – Ruchira Gayan Ranaweera

    12 de agosto de 2013 a las 16:44

  • @Ruchira abrí todos los enlaces pero aún no tengo claro cómo funciona. ¿Puedes explicarme en detalles como considerar como anotaciones de primavera? Puedo hacer todas las cosas usando anotaciones sin escribir ninguna configuración en el archivo spring.xml. ¿Se vincula internamente la anotación a la configuración xml?

    – Chirag Dasani

    13 de agosto de 2013 a las 6:50

  • @ChiragDasani echa un vistazo a esto. esto puede ayudarte static.springsource.org/spring/docs/3.0.0.M3/reference/html/… y también vea esta publicación SO stackoverflow.com/questions/2798181/…

    – Ruchira Gayan Ranaweera

    13 de agosto de 2013 a las 6:53


avatar de usuario
Kusum

Incluso yo estaba buscando la respuesta de la misma pregunta. el siguiente enlace proporcionó las cosas buenas consolidadas para obtener el interior de las anotaciones. https://dzone.com/articles/how-annotations-work-java
¡Espero eso ayude!

  • @LuiggiMendoza java 1.7 documento de anotaciones agregado

    – Ruchira Gayan Ranaweera

    12 de agosto de 2013 a las 16:44

  • @Ruchira abrí todos los enlaces pero aún no tengo claro cómo funciona. ¿Puedes explicarme en detalles como considerar como anotaciones de primavera? Puedo hacer todas las cosas usando anotaciones sin escribir ninguna configuración en el archivo spring.xml. ¿Se vincula internamente la anotación a la configuración xml?

    – Chirag Dasani

    13 de agosto de 2013 a las 6:50

  • @ChiragDasani echa un vistazo a esto. esto puede ayudarte static.springsource.org/spring/docs/3.0.0.M3/reference/html/… y también vea esta publicación SO stackoverflow.com/questions/2798181/…

    – Ruchira Gayan Ranaweera

    13 de agosto de 2013 a las 6:53


¿Ha sido útil esta solución?