VRaptor - Pegar um @Component dinamicamente em um interceptor

6 respostas
Rafael_Steil

No vraptor, como fazer para acessar dinamicamente no interceptor a implementação de um determinado @Compnent, sendo que em tempo de compilação não sei qual vai ser ele? Em suma, em runtime acesso determinadas annotations do método ou classe que está sendo executado, e ai preciso delegar a execução ao @Component correspondente.

O uso é mais ou menos assim:

// Componente qualquer que define regras de acesso via uma annotation
@Component
@SecurityConstraint(multiRoles = { AuthenticatedRule.class })
public class UserController {
    // .....
}

AuthenticatedRule.class vai ser a classe que em runtime, no inteceptor, vou precisar da implementação. Ela está definida assim:

@Component
public class AuthenticatedRule implements AccessRule {
    // ....
}

No código do interceptor, pego as annotations e eventualmente descubro que ele tem uma rule apontando para AuthenticatedRule.class (ou qualquer uma outra que tenha sido definida). Neste ponto preciso da instância (seja ela application, request, session scoped etc…).

Como fazer?

6 Respostas

Lucas_Cavalcanti

vc pode criar uma interface, receber essa interface no construtor e usar o .getClass do objeto que veio

Rafael_Steil

No construtor de quem? Do interceptor? Mas isso implica em eu saber quais serão as interfaces que poderão chegar, o que eu não sei. A minha annotation @SecurityConstraint pode receber inúmeras implementações de AccessRule, e além disso qualquer outra pessoa pode extender o sistema para adicionar suas próprias rules.

Se fossem classes simples eu poderia instanciar via reflection, porém tais classes são @Component’s do vraptor.

No vraptor 2 eu tinha resolvido isso acessando o application context do spring pelo interceptor, e ai eu só pedia o bean para ele, mas no vraptor 3 (ainda) não achei como fazer algo similar.

Lucas_Cavalcanti

só receber a interface AccessRule no construtor do interceptor :wink:

ou vc pode receber Container no construtor e fazer um:

Class clazz = this.getClass().getAnnotation(SecurityConstrant.class).value();

container.instanceFor(clazz)
Rafael_Steil

Receber no construtor não funcionaria por as rules (podem ser várias, não apenas uma) são especificadas na annotation @SecurityConstraint, e o interceptor é um genérico que pega as rules da annotation.

De qualquer maneira, creio que era a idéia de receber o Container (não sabia da existencia dele) é a solução que eu estava atrás.

Valeu.

wpivotto

Rafael Steil:
Receber no construtor não funcionaria por as rules (podem ser várias, não apenas uma) são especificadas na annotation @SecurityConstraint, e o interceptor é um genérico que pega as rules da annotation.

De qualquer maneira, creio que era a idéia de receber o Container (não sabia da existencia dele) é a solução que eu estava atrás.

Valeu.

Rafael você pode receber todas as implementações no construtor e simplesmente delegar a execução baseada na annotation:

@Intercepts
@Lazy
public AccessInterceptor implements Interceptor {

   private final List<AcessRule> rules;
 
   MyInterceptor(List<AcessRule> rules) {
      this.rules = rules;
   }

   boolean accepts(ResourceMethod method){
      return method.getDeclaringClass().isAnnotationPresent(SecurityConstraint.class);
   }

    public void intercept(InterceptorStack stack, ResourceMethod method, 
                        Object controller) throws InterceptionException {
        
          for(AccessRule rule : rules) {
	       if(rule.isAppliedTo(controller))
	            rule.handle(method);
	  }

	...  
        
    }
}
Rafael_Steil

Olha que chigue, não sabia que funcionava esse monte de mágica!

Tks!

Criado 19 de novembro de 2011
Ultima resposta 23 de nov. de 2011
Respostas 6
Participantes 3