I am using Seam to inject beans to my controller using #In annotation. The injected class has a custom annotation, when calling injectedClass.getClass().getAnnotation(annotationClass) it returns null.
When debug I found that Seam passes a proxy instance so getClass() returns InjectedClass_$$_javassist_seam_5 which doesn't have my custom annotation.
How I can get my custom annotation from the proxy class?
Here's how my classes look like:
#CustomAnnotation(value="myvalue")
#Name("myAnnotatedClass")
public class MyAnnotatedClass extends SuperClass {...}
#Scope(ScopeType.SESSION)
#Name("myController")
public class MyController {
#In("#{myAnnotatedClass}")
private MyAnnotatedClass myAnnotatedClass;
public void actionMethod(){
//call another class which call myAnnotatedClass.getClass().getAnnotation(CustomAnnotation.class)
//then do some reflection for MyAnnotatedClass fields
}
}
Good question.
When you call a method by using Seam, it is intercepted by a proxy. And this one enables #In or #Out-jection. But There is an exception to this rule: it does not work when you call an internal method
So try this code
#Name
public class Service {
#In
private MyAnnotatedClass myAnnotatedClass;
public void myInterceptedMethod() {
// internal method bypass interceptor
// So #In or #Out-jection is not enabled
internalMethod();
}
private void internalMethod() {
System.out.println(myAnnotatedClass.getClass().getAnnotation(annotationClass));
}
}
Added to original answer
You want to retrieve an annotation from your bean. But, because of method interceptor, myAnnotatedClass.getClass() returns a proxy object, not the bean class itself.
For each bean class, Seam creates a Component definition, in which is stored in the application context. The name of the attribute follows this pattern: component name plus .component. So if you have a bean like this one
#Name("myBean")
public class MyBean {
}
Its Componet definition is stored in the attribute myBean.component
So inside your method, you can use
Component myBeanComponentDefinition = (Component) Context.getApplicationContext().get("myBean.component");
Now you can call
myBeanComponentDefinition.getBeanClass().getAnnotation(CustomAnnotation.class);
regards,
If you want less "ComponentDefinition" overbloat, you could also use this which also works for CDI and Spring:
Class.forName(myBean.getClass().getCanonicalName().substring(0,myBean.getClass().getCanonicalName().indexOf("$"))).getAnnotation(MyAnnotation.class)
Related
I have a configuration class, which I inject into another class.
Configuration class looks as follows:
#RequestScoped
public class Configuration {
#ConfigProperty(name = "VALUE")
public String value;
public String getValue() {
return value;
}
}
This configuration is injected into the following place:
#ApplicationScoped
public class EndpointImpl implements Endpoint {
private Configuration configuration;
#Inject
public EndpointImpl(Configuration configuration) {
this.configuration = configuration;
System.out.println("configuration.value=" + configuration.value);
System.out.println("configuration.getValue()=" + configuration.getValue());
System.out.println("configuration.value=" + configuration.value);
}
Logs printed after going through constructor:
configuration.value=null
configuration.getValue()=someValue
configuration.value=null
I added postConstructor with the below similar code:
#PostConstruct
public void postConstruct(){
System.out.println("configuration.value="+configuration.value);
System.out.println("configuration.getValue()="+configuration.getValue());
System.out.println("configuration.value="+configuration.value);
}
and the result is the same.
Everything works fine as long as the value is retrieved through the getter method. When I try to retrieve it through the public field it returns null. I thought that, when CDI completes the process of building the bean, the fields inside the class will be set to appropriate values.
Why does it behave in such a way?
This is expected, because your Configuration bean is #RequestScoped. The request scope is one of so-called normal scopes, and whenever you #Inject a normal-scoped bean, you will always get a so-called client proxy.
The client proxy exists to lookup the correct bean instance and forward method invocations to it. In this case, it will lookup the bean instance for current request.
So, when you're accessing fields, you're accessing them on the client proxy -- not on the instance that pertains to the current request.
Whenever you inject a normal-scoped bean, never access fields directly. Always call methods. You may access fields directly on #Singleton and #Dependent beans, because they don't come up with a client proxy.
I have singleton bean in which I inject resource with #Resource annotation. When I try to retrieve that resource in the method called on event, the resource is null. What's going and why resource is not injected? What solution can be found for this? I can't refuse from using observers.
#Singleton
#javax.ejb.Startup
#Stateless
public class ScheduleManager implements IScheduleManager
{
#Resource
private TimerService timerService;
#Override
#Observer(value=EventConstants.SCHEDULE_CHANGE_EVENT)
public void reSchedule(PtSchedulesDTO schedule)
{
Collection<Timer> timers = timerService.getTimers();
//...
}
//...
}
I am not sure what framework or technology you are using but for annotation (#Resource) to work, usually something must be declared to look for that annotation. It could be declared in an xml file, where it gets pick up by the framework. Also you could also check if you have a TimerService class that you need to annotate or create a bean for the framework to be able to inject it in.
I am studying for the Spring Core certification and I have some doubts related to the answer of this question founded on the study material stuff.
Why are you not allowed to annotate a final class with #Configuration
My reasoning is the following one for substantiate this assertion:
Consider the following configuration class:
#Bean
public AccountRepository accountRepository() {
return new JdbcAccountRepository();
}
#Bean
public TransferService transferService() {
TransferServiceImpl service = new TransferServiceImpl();
service.setAccountRepository(accountRepository());
return service;
}
#Bean
public AccountService accountService() {
return new AccountServiceImpl(accountRepository());
}
At first look this situation could appear strange because the first method (accountRepository()) instantiates an JdbcAccountRepository object as a bean having id=AccountRepository that, following the Spring default behavior, is a singleton
The second and the third method call twice more time the accountRepository() method that should instantiate twice more JdbcAccountRepository objects and this is not possibile because it is singleton !!!
So, to solve this situation Spring use the Inheritance-based Proxies strategy that expect to create a child class of my configuration class (the one annoted by #Configuration) and it is does:
For each bean, an instance is cached in the child class
Child class only calls super at first instantiation
So the child class is the entry point because the following behavior is implemented by this child class:
public class AppConfig$$EnhancerByCGLIB$ extends AppConfig {
public AccountRepository accountRepository() {
// if bean is in the applicationContext
// return bean
// else call super.accountRepository() and store bean in context
}
public TransferService transferService() {
// if bean is in the applicationContext, return bean
// else call super.transferService() and store bean in context
}
.....................................................
.....................................................
.....................................................
}
So if I annotate a configuration class with final Spring can't have this behavior because in Java a final class cannot be subclassed
Is it correct?
Using the same reasoning can I also assert that in Spring I can't have a final method annoted with #Bean annotation?
Because, as shown in the previous example, I have that when at startup time is created the child class (the proxy) of my configuration class happens that for each bean, an instance is cached in the child class and if it is final it is not possible (but I am absolutly not sure about this assertion)
Am I missing something? Can you give me the exact explaination?
Tnx
Spring creates dynamic proxies for classes annotated with #Configuration classes. Spring uses CGLIB to extend your class to create proxy. Hence, configuration classes cannot be final.
Regarding accountRepository() being invoked twice:
If you invoke accountRepository() method to create an instance, it is no more a Spring managed bean. Spring will not have any idea of the instances created in this manner. Hence, you will end up with multiple instances of JdbcAccountRepository
You can preserve the singleton behavior if you configure as below:
#Bean
public TransferService transferService(JdbcAccountRepository jdbcAcctRepo) {
TransferServiceImpl service = new TransferServiceImpl();
service.setAccountRepository(jdbcAcctRepo);
return service;
}
#Bean
public AccountService accountService(JdbcAccountRepository jdbcAcctRepo) {
return new AccountServiceImpl(jdbcAcctRepo);
}
I got Object coming in a REST web service controller's web method which is locally initialized.
#RequestMapping(method = RequestMethod.POST,value = "/test",headers="Accept=*/*")
public #ResponseBody ModelAndView computeDetails(#RequestBody RequestObj reqObj, ModelMap model) {
System.out.println(reqObj.getcode());
return new ModelAndView("responsedetails", "object", reqObj);
}
This RequestObj object holds the key code to instantiate dependency using factory.
Different codes classes have been defined which implement BaseCode Interface.
How can I use factory method to instantiate particular code class based on code value coming in as BaseCode type in my service bean?
Any idea? Thanks in advance.
What I usually do in such cases is:
inject the factory into the controller using Spring's bean
create a method getBaseCode(String code) in the factory (please note: String here stands for code type, so use the actual code type if not String
make getBaseCode returning the BaseCode interface while constructing the real implementation
supposing you have an execute method in BaseCode, use the getBaseCode method into the controller to get the real collaborator and then call the execute method to perform the actual action
Ignoring the first point (which I think you can easily looking at any Spring tutorial) the factory will be something like
public class BaseCodeFactory {
public BaseCode getBaseCode(String code) {
if(code.equals("something")) return new ThisBaseCodeImpl();
else //and so on
}
}
while computeDetails becomes similar to:
#RequestMapping(method = RequestMethod.POST,value = "/test",headers="Accept=*/*")
public #ResponseBody ModelAndView computeDetails(#RequestBody RequestObj reqObj, ModelMap model) {
//...
factory.getBaseCode(reqObj.getcode()).execute();
//...
}
As a side note, I will not go for names like the one I choose here, I suggest you to look for something more significative in your domain (BaseCode has no meaning for example), take this snippets just as a directive.
Base on OP comment. If you have ThisBaseCodeImpl which makes use of other Spring bean you can
annotate it with #Configurable so, when you use new ThisBaseCodeImpl(/*args if you like*/) its bean are instantiated by Spring. I don't personally like this solution since, in my opinion, it pollutes the code with hidden Spring's bean. On the other hand is quite flexible, since it allows you to manage both runtime constructor arguments and Spring beans
add ThisBaseCodeImpl to the Spring context and change the factory, so that a collaborator for ThisBaseCodeImpl is injected into it.
1st point example:
#Configurable
public class ThisBaseCodeImpl {
#Resource
private Bean bean;
}
2nd point example:
public class BaseCodeFactory {
#Resource
ThisBaseCodeImpl thisBaseCodeImpl;
public BaseCode getBaseCode(String code) {
if(code.equals("something")) return thisBaseCodeImpl;
else //and so on
}
}
I'm not sure if I understood your problem well, but in general spring dependencies have nothing to do here. Just write custom Factory class and return BaseCode implemetation depending on the reqObj.getcode().
I did it this way -
Make your factory as ServletContextAware in a way to get the currentContext. And define getInstance method as
WebApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext);
ctx.getBean(classNameToBeInstantiated);
Define your bean's inheritance in spring context so that Spring injects its dependencies.
lets say the I have got a bean called with two methods 'foo' and 'goo'
and 'goo' is marked with AOP interception call.
is it possible to write any piece of code inside 'foo' in order to invoke 'goo' method not directly but through the proxy wrapper of the bean in order to activate the AOP part of it?
public Class Pojo{
public void foo(){
//what should I write here in order to activate 'goo' in transactional mode??
}
#Transactional
public void goo(){
}
}
Yes, but you need to access it through the spring proxy:
public Class Pojo{
#Autowired
private Pojo springProxy;
public void foo(){
springProxy.goo();
}
#Transactional
public void goo(){
}
}
I couldn't use the autowired option. Perhaps it is because I am using reflection to invoke goo() (and any other method as well) from foo().
So eventually what solves my problem was to add in foo() code that will lookup for the Pojo's proxy bean class. and invoke the mothd using Sun invokation on the proxy bean
this invoked the AOP call as well.
Couldn't find any better workaround.