Problem instantiating generic class bean in Spring - spring

I'm trying to instantiate a generic class in Spring, but I get following exception:
Initialization of bean failed; nested exception is
org.springframework.aop.framework.AopConfigException: Could not generate CGLIB subclass of class [class football.dao.jpa.GenericJpaDAO]: Common causes of this problem include using a final class or a non-visible class; nested exception is java.lang.IllegalArgumentException: Superclass has no null constructors but no arguments were given:
This is the XML configuration for Spring container:
<bean id="clubDAO" class="football.dao.jpa.GenericJpaDAO">
<constructor-arg type="EntityManagerFactory" ref="entityManagerFactory"/>
<constructor-arg type="Class" value="football.model.entities.ClubEntity"/>
<constructor-arg type="String" value="ClubEntity"/>
</bean>
This is the generic class:
public class GenericJpaDAO <T extends HavingID> {
private EntityManager em;
private Class entityClass;
private String entityName;
public GenericJpaDAO( Class entityClass, String entityName,
EntityManagerFactory emFactory ) {
this.entityClass = entityClass;
this.entityName = entityName;
em = emFactory.createEntityManager();
}
#Transactional
public void create( T entity ) {
em.persist( entity );
}
// more methods
}
I'm not really sure what could be causing this. I would appreciate any ideas.

This problem is not related to generics, it's a limitation of Spring AOP.
If aspects (including #Transactional aspect) are applied to the class using CGLIB proxy (this happens if target class doesn't implement any interfaces or if AOP is configured with proxy-target-class = "true"), no-argument constructor is required:
public class GenericJpaDAO <T extends HavingID> {
...
public GenericJpaDAO() {}
public GenericJpaDAO( Class entityClass, String entityName,
EntityManagerFactory emFactory ) { ... }
...
}
See also:
7.6 Proxying mechanisms

Related

Failed to instantiate [..]: No default constructor found;

I'm getting:
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.mz.server.rest.braintree.webhooks.SubscriptionWebhook]: No default constructor found; nested exception is java.lang.NoSuchMethodException: com.mz.server.rest.braintree.webhooks.SubscriptionWebhook.<init>()
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:85)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1098)
... 22 more
Even though I have defined this constructor in my applicatioContext-restapi.xml file:
<bean id="subscriptionWebhook" class="com.mz.server.rest.braintree.webhooks.SubscriptionWebhook">
<constructor-arg ref="dslContext" />
</bean>
Any idea why?
#RestController
public class SubscriptionWebhook {
private final static Logger LOGGER = Logger.getLogger(SubscriptionWebhook.class.getName());
private AdminService adminService;
public SubscriptionWebhook(DSLContext ctx) {
this.adminService = new AdminService(ctx);
}
}
Since Spring 3(ish) you can configure your container by applying #Component annotations to classes. #Controller annotation is defined as follows:
#Target(value=TYPE)
#Retention(value=RUNTIME)
#Documented
#Component
public #interface Controller
Which means classes annotated by it are going to get picked up, too. And RestController is just Controller and ResponseBody put together.
Anyway as you admitted in the comments you have enabled component scanning, and the configuration in xml is not going to get picked up in this case.
What you could do is convert the xml configuration to annotation-based injection, like that:
#RestController
public class SubscriptionWebhook {
private final static Logger LOGGER = Logger.getLogger(SubscriptionWebhook.class.getName());
private AdminService adminService;
public SubscriptionWebhook(#Qualifier("dslContext") DSLContext ctx) {
this.adminService = new AdminService(ctx);
}
}
Qualifier annotation is going to look in the container for a bean with name/id dslContext and inject it in the constructor. Alternatively you can use the javax.inject Named annotation, or if this is the only bean with that type, Spring's #Autowired or JSR-330's #Inject.
Annotation #RestController is autodetected by spring. Spring will create a bean for you so you shouldn't add bean definition in the xml, because it would create a second bean. If you want to inject another bean into the controller just use #Autowired. So the solution in your case is:
Remove "subscriptionWebhook" bean definition from the xml
Add #Autowired on SubscriptionWebhook constructor

Spring: Autowired is null in ejb class

I have the following situation:
#Controller
public class myController {
#Autowired
private IProxy service;
public ModelAndView init(HttpServletRequest request, HttpServletResponse response) throws Exception {
List<String> list = service.getName();
}
}
Then my Service is define as follow:
public interface IProxy {
public List<String> getName();
}
Proxy class is responsible for the lookup to the remote bean
#Service("service")
public class Proxy implements IProxy {
...
public List<String> getName() {
return myClass.getName();
}
And the implementation is the following:
#Interceptors(interceptor.class)
#Stateless
#Resource(name = "java:/db")
#Remote(MyClassRemote.class)
public class MyClassImpl extends MyEjb implements MyClassRemote{
#PersistenceContext(unitName = "db")
private EntityManager em;
#Resource
private SessionContext sctx;
#Autowired
public IMyRepo myRepo;
#Override
public List<String> getName() {
try {
return myRepo.getName(em);
}
catch (Exception ex) {
ex.printStackTrace();
throw ex;
}
finally {}
}
So, the problem is that here myRepo is null. I don't know why because IMyRepo and his implementation are always located within the path scanned by Spring.
Just one clarification: MyRepo class that implements IMyRepo is annotated with #Repository.
Any idea?
you can inject spring beans in EJB using Spring interceptors, as explained here in the official documentation. Basically you'll need to adjust your class as follows:
// added the SpringBeanAutowiringInterceptor class
#Interceptors({ interceptor.class, SpringBeanAutowiringInterceptor.class })
#Stateless
#Resource(name = "java:/db")
#Remote(MyClassRemote.class)
public class MyClassImpl extends MyEjb implements MyClassRemote{
// your code
}
You'll also need to define the context location in a beanRefContext.xml file (with your own application context file):
application-context.xml version
<bean id="context"
class="org.springframework.context.support.ClassPathXmlApplicationContext">
<constructor-arg>
<list>
<value>application-context.xml</value>
</list>
</constructor-arg>
</bean>
Java Configuration version:
<bean id="context"
class="org.springframework.context.annotation.AnnotationConfigApplicationContext">
<constructor-arg>
<list>
<value type="java.lang.Class">com.your.app.Configuration</value>
</list>
</constructor-arg>
</bean>
Spring beans and EJB are two different things, you can't just inject a Spring bean in an EJB, because that EJB is no Spring bean, so Spring doesn't know there is a field which should be injected by Spring (unless you use some fancy AOP stuff, which can enable injection into non-Spring-managed beans).

Spring autowired annotation with java timertask

Autowired annotation doesn't work. I thought there must be a problem with Timertask or run method. My other classes working fine(I mean Autowired annotation initialize genericService without any problem) but in this class genericService value is null. Is there any idea?
public class UsersUpdateTask extends TimerTask {
#Autowired
GenericService genericService;
#Override
public void run() {
//genericService.save() gives null pointer.
}
}
My applicationContext definition;
<bean id="usersUpdateTask" class="myPackage.UsersUpdateTask">
</bean>
<bean id="genericLogger" class="utilPack.Logger">
</bean>
<bean id="genericService" class="servicePack.GenericService">
This class working perfectly;
public class Logger implements Serializable {
#Autowired
private GenericService genericService; //works fine
.....
}
There is a method in another class to call UsersUpdateTask's run method;
public void updateUsersList(){
timer.schedule(new UsersUpdateTask(), 1000, 60*60*1000);
}
Well there it is
timer.schedule(new UsersUpdateTask(), 1000, 60*60*1000);
you're creating the object yourself. Spring can't autowire objects it doesn't control or process. Use the injected UsersUpdateTask bean.

spring3-annotation-JdbcDaoSupport

Use annotation in dao
#Repository("testDao")
public class TestDaoImpl extends JdbcDaoSupport implements BaseDao{
#Override
public Object addObject(String sqlid, Object obj) {
// TODO Auto-generated method stub
return null;
}
Caused by: java.lang.IllegalArgumentException: 'dataSource' or 'jdbcTemplate' is required
I do not want to use :
<bean id="termsDao" class="com.manage.base.dao.impl.TestDaoImpl">
<property name="jdbcTemplate" ref="jdbcTemplate"/>
</bean>
this code set in xml, and “jdbcTemplate” has been defined in other “spring-xml”。
How to solve this problem by an annotation :“'dataSource' or 'jdbcTemplate' is required”
You can use one of the below approaches. The first one - taking a dataSource is preferred / recommended as you don't expose a SpringFramework class in your public interface. Both will work.
#Repository("testDao")
public class TestDaoImpl extends JdbcDaoSupport implements BaseDao{
#Autowired
TestDaoImpl(DataSource dataSource) {
setDataSource(dataSource);
}
}
Or
#Repository("testDao")
public class TestDaoImpl extends JdbcDaoSupport implements BaseDao{
#Autowired
TestDaoImpl(JDBCTemplate template) {
setJdbcTemplate(template);
}
}
I even feel injecting datasource as a constructor to your DAO is a unnecessary coding step.
Why not inject datasource in Spring config XML into JDBC template and just get jdbctTemplate
object in every DAO.
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
and let your DAO extend JDBCSupport class.
public class PersonDao extends JdbcDaoSupport{
public List<Person> selectAll(){
String selectAllSql = "SELECT * FROM PERSON;";
return getJdbcTemplate().query(selectAllSql, new PersonRowMapper());
........
}
}
Full example :
http://www.studytrails.com/frameworks/spring/spring-jdbc-dao-support.jsp

Enabling AOP breaks my dependency injection for a factory bean that takes a string

Enabling AOP breaks my dependency injection for a factory bean that takes a string.
Here's the fragment from the context file:
<aop:aspectj-autoproxy/>
<bean id="foo"
class="FooFactory"
p:url-ref="url"/>
<bean id="url" class="java.lang.String">
<constructor-arg value="#{ 'localhost:50131'}"/>
</bean>
Here's the factory bean.
public class FooFactory extends AbstractFactoryBean<Foo> {
private String url;
public void setUrl(final String url) {
this.url = url;
}
#Override
public Class<?> getObjectType() {
return Foo.class;
}
#Override
protected Foo createInstance() throws Exception {
Validate.notNull(url, "null URL");
return new FooFactory().createFoo(new String[]{url});
}
}
Here is the only declared aspect:
#Component
#Aspect
public class ProfilerAspect {
#Around("#target(org.springframework.stereotype.Controller) && args(model,..)")
public Object profileController(final ProceedingJoinPoint proceedingJoinPoint, final Model model) throws Throwable {
return proceedingJoinPoint.proceed();
}
}
And this is the exception
java.lang.IllegalStateException: Cannot convert value of type [$Proxy13 implementing java.io.Serializable,java.lang.Comparable,java.lang.CharSequence,org.springframework.aop.SpringProxy,org.springframework.aop.framework.Advised] to required type [java.lang.String] for property 'url': no matching editors or conversion strategy found
It seems, that it has to do with the #target designator in the pointcut expression. I can reproduce the behaviour with a simple setup similar to yours (with only a custom annotation in the pointcut). It works fine with a simple execution() designator though.
Unfortunatly, I have no idea why this causes Spring to proxy the String object.
<aop:aspectj-autoproxy/> doesn't perform proxying without a reason. Perhaps you declared some aspect whose pointcut includes Strings, therefore it have been proxied.

Resources