Injecting spring bean to an abstract class - spring

I'm trying to inject (autowire) a spring bean to an abstract class but it doesn't seem to work.
public abstract class BaseEntity {
#Autowired(required = true)
protected SecurityProvider securityService;
public BaseEntity() {
}
}
And the injected class:
#Component
public class SecurityService extends SecurityProviderImpl implements SecurityProvider {
#Autowired
public SecurityService(ICipherDescriptor cipherDescriptor) {
super(cipherDescriptor);
}
}
The SecurityService gets initialized just fine (I can see it while debugging) but the class that inherit from BaseEntity cannot use the injected SecurityService since it is null (doesn't get injected for some reason).
I tried doing it via XML as well, defining the BaseEntity as abstract:
<bean id="baseEntity" abstract="true" class="com.bs.dal.domain.BaseEntity">
<property name="securityService" ref="securityService"/>
</bean>
<bean id="securityService" class="com.bs.dal.secure.SecurityService">
<constructor-arg ref="cipherDescriptor" />
</bean>
but still with no success.
Where am I going wrong?

I think I know what's wrong here. I'm trying to inject a spring bean to an entity - which is impossible (unless you use aspectJ weaving) since the entities are not instantiated/managed by Spring. Make sense, isn't it?

If your BaseEntity is also instantiated by spring, you just need to add a parent attribute to the bean definition to link it to your BaseEntity definition like so:
<bean id="baseEntity" abstract="true" class="com.bs.dal.domain.BaseEntity">
<property name="securityService" ref="securityService"/>
</bean>
<bean id="derivedEntity" parent="baseEntity" class="com.bs.dal.domain.DerivedEntity"/>
<bean id="securityService" class="com.bs.dal.secure.SecurityService">
<constructor-arg ref="cipherDescriptor" />
</bean>
In short, the two key parts to such a definition are the abstract attribute on the parent class and the parent attribute on the subclass.

Related

Could not instantiate bean class: Specified class is an interface

I know there are threads similar to this issue. Below is my class and I am configuring it in spring.xml file. Actually HumanResourceService is an interface having only one method.
#Endpoint
public class HolidayEndpoint {
#Autowired
private HumanResourceService humanResourceService;
#Autowired
public HolidayEndpoint(HumanResourceService humanResourceService) throws JDOMException {
this.humanResourceService = humanResourceService;
}
}
My problem is that in my spring.xml file, when I define HumanResourceService as bean, it cannot be instantiated as this is an interface. How can I mention an interface in spring configuration file. My spring.xml file is below
<bean id="holidayEndpoint" class="com.mycompany.hr.ws.HolidayEndpoint" autowire="constructor" >
<property name="humanResourceService" ref="humanResourceService" />
</bean>
<bean id="humanResourceService" class="com.mycompany.hr.service.HumanResourceService" />
You can't, Spring needs something it can make an instance from, the interface isn't enough.
In your spring.xml, the value of the class attribute for your bean with id="humanResourceService" should be the name of your implementation class, not the interface. Spring needs you to tell it what implementation class you want it to use for this.

Mixing declarative beans and annotated beans: org.hibernate.HibernateException No Session found for current thread

I get "No Session found for current thread".
I suppose the problem is in mixing declarative xml beans and annotated beans.
Following, I'll resume my config.
MyLibrary Project
Spring 3.1.4
Hibernate 4
applicationContext.xml
<tx:annotation-driven transaction-manager="transactionManager" />
<context:component-scan
base-package="com.mycompany.dao.core, com.mycompany.services.core,
com.mycompany.permissionEvaluator" />
<import resource="model-core-security.xml" />
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
... (sessionFactory ecc...)
model-core-security.xml
<bean id="expressionHandler"
class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler">
<property name="permissionEvaluator" ref="permissionEvaluator" />
</bean>
<security:global-method-security
pre-post-annotations="enabled">
<security:expression-handler ref="expressionHandler" />
</security:global-method-security>
With component-scan I create beans: AccountService, AccountDAO and PermissionEvaluator.
AccountService.java (com.mycompany.services)
#Service("accountService")
#Transactional
public class AccountServiceImpl implements AccountService {
#Resource
private AccountDAO accountDAO;
...
}
AccountDAO.java (com.mycompany.dao)
#Repository
#Transactional
public class HibernateAccountDAOImpl implements AccountDAO {
...query...
}
(AccountService e AccountDAO are transactional)
Now, within AccountController.java I call accountService.listAccounts() and it's all right!
But, if I inject AccountService into PermissionEvaluator class (following snippet), AccountController gets No Session found for current thread when invokes accountService.listAccounts()
PermissionEvaluator.java (com.mycompany.permissionEvaluator)
Component("permissionEvaluator")
public class PermissionEvaluatorImpl implements PermissionEvaluator {
#Resource
private AccountService accountService;
...
}
I use PermissionEvaluator (with AccountService, AccountDAO) created by component-scan in expressionHandler bean declared in model-core-security.xml.
Might it be the cause of "no session found for currend thread"?
#Transactional
what's ur import package
import org.springframework.transaction.annotation.Transactional; ??
U can try to import "import javax.transaction.Transactional;"

Accessing a Spring Bean from a Servlet

I have a Spring Bean defined in my applicationContext like:
<bean id="spaceReader" class="com.company.SpaceReader">
</bean>
I would like to be able to access this bean in my Application Servlet without having to use:
ApplicationContext context = new ClassPathXmlApplicationContext(CONTEXT_LOCATION);
context.getBean("SpaceReader");
I've tried exporting it using the following:
<bean id="ContextExporter" class="org.springframework.web.context.support.ServletContextAttributeExporter">
<property name="contextExporterAttributes">
<map>
<entry key="SpaceReaderKey">
<ref local="spaceReader" />
</entry>
</map>
</property>
</bean>
but when i inject it into the Servlet, it returns a Null value. Just wondering if there's something i'm missing when i export the Bean or when i try to access it in the Servlet?
You can inject dependencies using annotations even in servlet (there is a special SpringBeanAutowiringSupport helper class for this pourpose):
public class CustomServlet extends HttpServlet {
#Autowired
private ProductService productService;
#Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
// inject productService dependency
SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
}
....
}

Can't use #Qualifier along with #Inject and autowire="byType"

I have the bean config:
<bean id="PostLoginUpdater" class="xyz.auth.PostLoginUpdater" autowire="byType" />
and
public class PostLoginUpdater implements PostLoginStatePersonalizer {
//#Qualifier("CustomerManager")
#Inject
//#Resource(name = "CustomerManager")
private CustomerManager customerManager;
public void setCustomerManager(CustomerManager customerManager)
{
this.customerManager = customerManager;
}
}
Because there are two beans that implement CustomerManager I get this error:
No unique bean of type [CustomerManager] is defined: expected single
matching bean but found 2
As you can see, I'v tried several combinations (#Inject along with #Qualifier, #Ressource, only #Qualifier) But I don't get rid of this error message.
According to Spring In Depth, #Qualifier can be used along with #Inject. Can't I used them together if I defined autowire="byType" in bean config?
And I don't use <context:annotation-config /> or <context:component-scan />
You should be able to use a combination of '#Inject' and '#Qualifier', if you have multiple beans of the same type. Here is how to configure it -
<bean id="PostLoginUpdater" class="xyz.auth.PostLoginUpdater" autowire="byType" />
<bean id="firstManager" class="xyz.manager.CustomerManager" autowire="byType" >
<qualifier>first</qualifier>
</bean>
<bean id="secondManager" class="xyz.manager.CustomerManager" autowire="byType" >
<qualifier>second</qualifier>
</bean>
If you had two beans of type 'CustomerManager' as shown above, you could use the snippet shown below for injection -
public class PostLoginUpdater implements PostLoginStatePersonalizer {
#Inject
#Qualifier("first")
private CustomerManager customerManager;
public void setCustomerManager(CustomerManager customerManager)
{
this.customerManager = customerManager;
}
}
Also, on a side note -
If you keep using one of the beans more often than another you could use the 'primary' attribute.
For example, in the above example, if you always tend to use 'firstManager', you could mark it as primary as shown below.
<bean id="PostLoginUpdater" class="xyz.auth.PostLoginUpdater" autowire="byType" />
<bean id="firstManager" class="xyz.manager.CustomerManager" autowire="byType" primary="true" >
</bean>
<bean id="secondManager" class="xyz.manager.CustomerManager" autowire="byType" >
<qualifier>second</qualifier>
</bean>
If you have above configuration, the following code will always injects 'firstManager' when no qualifier is used -
public class PostLoginUpdater implements PostLoginStatePersonalizer {
#Inject
private CustomerManager customerManager;
public void setCustomerManager(CustomerManager customerManager)
{
this.customerManager = customerManager;
}
}
It doesn't make any sense to try to autowire by type, and simultaneously specify a name. Choose one approach or the other.
I have also had trouble in the past trying to use #Qualifier with #Inject. One thing to note is that there are two annotations with that name, one in Spring and one in Java:
org.springframework.beans.factory.annotation.Qualifier
javax.inject.Qualifier
However, if using the spring framework one, then the suggested usage is to explicitly name your component via #Component or #Named [#Component("beanName")] (if annotated), or in the <bean> definition. Be aware that autowiring wants the bean name, not the Class name as in your example (i.e. do not use "CustomerManager"). For example, if you have two bean definitions like in Sashi's example:
<bean id="firstManager" class="xyz.manager.CustomerManager" autowire="byType" >
<qualifier>first</qualifier>
</bean>
<bean id="secondManager" class="xyz.manager.CustomerManager" autowire="byType" >
<qualifier>second</qualifier>
</bean>
then declare the field like this:
#Inject
#Qualifier("firstManager")
private CustomerManager customerManager;

Spring Instantiation using a none-static factory method

I have got a situation where I would like to create bean2 in Spring config:
beans.xml:
<bean id="bean1" class="...">
<property name="..." ref="..." />
</bean>
bean2 = bean1.foo()
Would appreciate any help,
Thanks,
Behzad
You can use instance factory method. See corresponding chapter in Spring documentation.
<bean id="bean2" factory-bean="bean1" factory-method="foo"/>
If you are using annotations you can use:
#Configuration
public class AppConfig {
#Bean
#Lazy
public Bean1 getBean1(){
return Bean1.getInstance();
}
#Bean
public Bean2 getBean2() {
return this.getBean1().newBean2(); //in your example is this.getBean1().foo();
}
}

Resources