Parâmetro anotado

12 respostas
R

Tem como fazer o parâmetro de um método ser de uma classe qualquer, mas que possua uma determinada anotação? Algo do tipo:

public void bla(Object.has(@AnotacaoX) objetoAnotado)

12 Respostas

T

Hum… você quer ver se, em tempo de execução, você recebeu um parâmetro anotado?

Você pode anotar parâmetros (veja http://java.sun.com/j2se/1.5.0/docs/api/java/lang/annotation/ElementType.html ), mas normalmente o que ocorre é que você analisa a classe à qual pertence o tal método que contém uma anotação no parâmetro, e você vê se está do jeito que você quer. Por exemplo, você poderia ter algo como:

interface Gambiarrable {
    int doGambiarra (byte[] bytes);
}
@Retention (RetentionPolicy.RUNTIME)
@Target (ElementType.PARAMETER)
public @interface ReallyPOG {
    string value();
}
class POG implements Gambiarrable {
    public int doGambiarra (@ReallyPog (value="abc") byte[] bytes);
}

E quando você pegar um objeto de uma classe que implementa Gambiarrable (por exemplo), pode ver se o tal primeiro parâmetro do método tem uma anotação “ReallyPog”.

T

Acho que não dá para anotar uma chamada de método, como isto aqui (continuando meu exemplo):

doGambiarra (@ReallyPog ("xyz") new byte[] {1, 3, 4});
R

Thingol, desculpe mas de cara não consegui entender.

Não importaria a classe do parâmetro, a única coisa que importaria seria que a mesma tivesse uma anotação específica. Me parece uma informação disponível em compile time:

class A...

@AnotacaoX
class B...


class C {
    public String fazAlgo(Object anotadoComAnotacaoX)...

a = new A();
b = new B();
c = new C();

c.fazAlgo(a); // o compilador  que a.class não tem @AnotacaoX, não compila
c.fazAlgo(b); // compila
T

Dei uma acertada no meu exemplo, e realmente constatei que não posso incluir uma annotation em uma chamada de método.

import java.lang.annotation.*;
import java.lang.reflect.*;

interface Gambiarrable {
    int doGambiarra (byte[] bytes);
}
@Retention (RetentionPolicy.RUNTIME)
@Target (ElementType.PARAMETER)
@interface ReallyPOG {
    String value();
}
class POG implements Gambiarrable {
    public int doGambiarra (@ReallyPOG (value="abc") byte[] bytes) {
        return 0;
    }
}

class FastPOG implements Gambiarrable {
    public int doGambiarra (byte[] bytes) {
        return 1;
    }
}


class POGTester {
    public static void printParameterAnnotations (Class<?> klass) {
        System.out.println ("Classe " + klass.getName());
        for (Method m : klass.getDeclaredMethods()) {
            System.out.println (m.getName() + " => " );
            Annotation[][] paramAnns = m.getParameterAnnotations();
            for (int i = 0; i < paramAnns.length; ++i) {
                System.out.print ("    param " + i + " -> ");
                Annotation[] anns = paramAnns[i];
                for (Annotation ann : anns) {
                    System.out.print (ann.toString());
                }                
                System.out.println();
            }
        }
    }
    
    public static void main(String[] args) {
        Gambiarrable g = new FastPOG();
        printParameterAnnotations (g.getClass());
        g = new POG();
        printParameterAnnotations (g.getClass());
        // A seguinte sintaxe realmente não funciona:
        // g.doGambiarra (@ReallyPOG (value="xyz") new byte[]{1, 2, 3});
    }
}
T

Hum, agora entendi o que você quer. Você gostaria que o compilador checasse se determinado parâmetro foi anotado; se não tiver sido, então você gostaria de um erro de compilação.

Talvez você precise de um “Annotation Processor” (procure por apt na documentação do JDK.) Um “annotation processor” é uma forma de você modificar o comportamento do compilador para que ele, por exemplo, possa checar tais anotações.

S

renato3110:
Tem como fazer o parâmetro de um método ser de uma classe qualquer, mas que possua uma determinada anotação? Algo do tipo:

public void bla(Object.has(@AnotacaoX) objetoAnotado)

Não. Mas pode fazer isto :

@ExpectAnnotation(AnotacaoX.class)
public void bla(Object objetoAnotado)

Depois vc pode usar o processador de anotações ou vc pode criar um proxy.
O proxy pode facilmente - via reflection - testar, em runtime se o objeto passado tem a sua classe anotada com a anotação esperada.

R

thingol:
Hum, agora entendi o que você quer. Você gostaria que o compilador checasse se determinado parâmetro foi anotado; se não tiver sido, então você gostaria de um erro de compilação.

Talvez você precise de um “Annotation Processor” (procure por apt na documentação do JDK.) Um “annotation processor” é uma forma de você modificar o comportamento do compilador para que ele, por exemplo, possa checar tais anotações.

Não o parâmetro, mas o tipo da variável.

Sei lá, acho engraçado ter tanta gambiarra e não ter isso. Acho até que seria simples, tipo:

public void umaGambiarraAMaisOutraAMenos(@AnotacaoX parametro)

Ou seja, você estaria dizendo que o tipo do parâmetro é uma subclasse de Object que possua a anotação @AnotacaoX (Object em si não tem é claro), o que pode ser verificado em tempo de compilação.

R

sergiotaborda:
Não. Mas pode fazer isto :

@ExpectAnnotation(AnotacaoX.class)
public void bla(Object objetoAnotado)

Depois vc pode usar o processador de anotações ou vc pode criar um proxy.
O proxy pode facilmente - via reflection - testar, em runtime se o objeto passado tem a sua classe anotada com a anotação esperada.

Eu quero justamente fugir da verificação em runtime. Como funciona o processador de anotações?

T

Uh, mas tem um pequeno problema aí.

Você está afirmando que gostaria que o parâmetro, em vez de pertencer a uma classe que deva IMPLEMENTAR uma determinada interface (ou uma interface que deva estender uma determinada interface), deva pertencer a uma classe ou interface e a classe ou interface é que deve estar anotada com determinada anotação.

Ou seja, o que se pode fazer é algo como:

@ReallyPOG (value="qwerty")
class BiggestPOG {
}

void processPoggableParameter (Object obj) {
    if (obj.getClass().getAnnotation(ReallyPOG.class)) {
        System.out.println ("OK, este parâmetro é realmente pogável");
    } else {
        System.out.println ("Puxa vida, já falei mil vezes que tem de passar um parâmetro pogado");
    }
}
R

Sim thingol, mas isso aí é em runtime, btw eu uso Class.isAnnotationPresent…

R

Postei um bug na Sun…

R

thingol:

interface Gambiarrable

Hahahahah, mais uma pro:

Criado 16 de agosto de 2008
Ultima resposta 16 de ago. de 2008
Respostas 12
Participantes 3