I'm trying to implement a custom java Spring JPA repository, as described in the Spring documentation.
It seems that my spring config insists on creating the repositories in the standard way, instead of using the given MyRepositoryFactoryBean, giving me
Caused by: org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [com.myapp.repository.impl.DocumentRepositoryImpl]: No default constructor found; nested exception is java.lang.NoSuchMethodException: com.myapp.repository.impl.DocumentRepositoryImpl.<init>()
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:83)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1006)
... 43 more
Caused by: java.lang.NoSuchMethodException: com.myapp.repository.impl.DocumentRepositoryImpl.<init>()
at java.lang.Class.getConstructor0(Class.java:2730)
at java.lang.Class.getDeclaredConstructor(Class.java:2004)
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:78)
I'm using Spring 3.2.2-RELEASE and spring-data-jpa-1.3.2-RELEASE, which is the latest if I'm correct. Here's my spring config:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.2.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.2.xsd">
<import resource="spring-repository-config.xml"/>
<import resource="spring-security-config.xml"/>
<context:component-scan base-package="com.myapp.web.controller"/>
<context:component-scan base-package="com.myapp.webservice.controller"/>
And here's the spring-repository-config.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/data/jpa"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.3.xsd">
<repositories base-package="com.myapp.repository"
factory-class="com.myapp.repository.impl.MyRepositoryFactoryBean"/>
<!-- entity-manager-factory-ref="entityManagerFactory" transaction-manager-ref="transactionManager" -->
If've added debug breakpoints in all the methods of the com.myapp.repository.impl.MyRepositoryFactoryBean class, but these were not called.
The basic interface, just like in the example
package com.myapp.repository.impl;
#NoRepositoryBean
public interface MyRepository<T, ID extends Serializable> extends JpaRepository<T, ID> {
The base implementation:
package com.myapp.repository.impl;
#NoRepositoryBean
public class MyRepositoryImpl<T, ID extends Serializable> extends SimpleJpaRepository<T, ID> implements MyRepository<T, ID> {
private EntityManager entityManager;
public MyRepositoryImpl(Class<T> domainClass, EntityManager entityManager) {
super(domainClass, entityManager);
// This is the recommended method for accessing inherited class dependencies.
this.entityManager = entityManager;
}
public void sharedCustomMethod(ID id) {
// implementation goes here
}
}
And the factory:
package com.myapp.repository.impl;
import java.io.Serializable;
import javax.persistence.EntityManager;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.support.JpaRepositoryFactory;
import org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean;
import org.springframework.data.repository.core.RepositoryMetadata;
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
public class MyRepositoryFactoryBean<R extends JpaRepository<T, I>, T, I extends Serializable> extends JpaRepositoryFactoryBean<R, T, I> {
protected RepositoryFactorySupport createRepositoryFactory(EntityManager entityManager) {
return new MyRepositoryFactory(entityManager);
}
private static class MyRepositoryFactory<T, I extends Serializable> extends JpaRepositoryFactory {
private EntityManager entityManager;
public MyRepositoryFactory(EntityManager entityManager) {
super(entityManager);
this.entityManager = entityManager;
}
protected Object getTargetRepository(RepositoryMetadata metadata) {
return new MyRepositoryImpl<T, I>((Class<T>) metadata.getDomainType(), entityManager);
}
protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {
// The RepositoryMetadata can be safely ignored, it is used by the JpaRepositoryFactory
// to check for QueryDslJpaRepository's which is out of scope.
return MyRepositoryImpl.class;
}
}
}
My repositories interfaces are defines as:
package com.myapp.repository;
public interface DocumentRepository { // extends MyRepository<Document, Long>
public Document findByDocumentHash(String hashCode);
public Document findById(long id);
}
And the implementation is
package com.myapp.repository.impl;
import java.io.Serializable;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
public class DocumentRepositoryImpl<Document, ID extends Serializable> extends MyRepositoryImpl<Document, Serializable> {
private static final long serialVersionUID = 1L;
public DocumentRepositoryImpl(Class<Document> domainClass, EntityManager entityManager) {
super(domainClass, entityManager);
}
And I use these repositories as autowired refernces in my controllers:
package com.myapp.web.controller;
#Controller
#RequestMapping(value = "/documents")
public class DocumentController {
#Autowired
private DocumentRepository documentRepository;
#RequestMapping(method = RequestMethod.GET)
public ModelAndView list(HttpServletRequest request) {
this.documentRepository. ...
}
I've looked at various resources on the web like this one, but I can't tell the difference with my code. Any hints are more than welcome!
You need default constructor for com.myapp.repository.impl.DocumentRepositoryImpl
public DocumentRepositoryImpl(){}
Spring first instantiate the beans that you declare in the app context (in your case) by calling the default constructor( no parameters ) and than uses setters to inject other beans.
Related
While refactoring an application and implementing injection via Spring it would be helpful to get hold of autowired objects within the instantiation phase. I cannot get it work (and would understand if it does not work at all; instatiation would be very tricky) but nevertheless want ot ask the question here to make sure.
For testing purposes I created this bean:
import org.springframework.stereotype.Repository;
#Repository
public class MyService {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
which is meant to become injected to this component:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import de.sample.spring.service.MyService;
#Component
public class MyComponent {
#Autowired
private MyService myService;
public MyComponent() {
System.out.println("MyService during instantiation="+myService);
showInternallyMyService();
}
#Autowired
private void setMyService(MyService myService) {
System.out.println("MyService during instantion via setter="+myService);
}
private void showInternallyMyService() {
System.out.println("MyService during instantiation via constructor call="+myService);
}
public void showWhenExternalCalledMyService() {
System.out.println("MyService when show has been called after instatiation="+myService);
}
}
The associated applicationContext is:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<!-- enable autowire -->
<context:annotation-config />
<context:component-scan base-package="de.sample.spring.service" />
<context:component-scan base-package="de.sample.spring.component" />
</beans>
The stuff is then run by:
import java.io.IOException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import de.sample.spring.component.MyComponent;
public class Start {
private static final Logger LOGGER = LoggerFactory.getLogger(Start.class);
private final static String contextPath = "/context/applicationContext.xml";
public static void main(String[] args) throws IOException {
ApplicationContext context = null;
try {
context = new ClassPathXmlApplicationContext(contextPath);
} catch (Exception e) {
LOGGER.error("",e);
}
MyComponent myComponent = (MyComponent) context.getBean("myComponent");
myComponent.showWhenExternalCalledMyService();
}
}
The resulting log shows then these messages
MyService during instantiation=null
MyService during instantiation via constructor call=null
MyService during instantiation via setter=de.sample.spring.service.MyService#2ea227af
MyService when show has been called after instantiation=de.sample.spring.service.MyService#2ea227af
As can be seen the "Autowired" object is null in the constructor phase, only in the running phase it is instantiated. As already said - I think this is the way it is meant to work, but still I hope I'm wrong and can manage to get it work to access the autowired in the constructor. I know, I could use the constructor with properties - this would solve my problem but I wonder if it could be managed with another approach.
Beans get autowired after the constructor has been executed...per default.
If you want to autowire it at construction time you have to #autowire it at the constructor:
#Autowired
public MyComponent(MyService myService) {
System.out.println("MyService during intantiation="+myService);
showInternallyMyService();
}
You can try the way #watchme mentioned but take note that using this way will make it kind of immutable object but ensure that required dependencies are not null.
Also With #Autowired on a field you don't need a setter method for it and once your bean's constructor is done with allocating/creating the object,
Spring will scan for this annotation and would inject the object instances that you annotated.
This works as designed. During the initialization phase, beans are initialized and the dependency injection is done.
If you want to guarantee all dependencies have been injected, you should implement your logic in an initialization callback. Use the #PostConstruct annotation:
#Component
public class MyComponent {
#Autowired
private MyService myService;
public MyComponent() {
System.out.println("MyService during intantiation="+myService);
}
#Autowired
private void setMyService(MyService myService) {
System.out.println("MyService during instantion via setter="+myService);
}
#PostConstruct
private void showInternallyMyService() {
System.out.println("MyService during initialization="+myService);
}
}
I am trying to integrate Jersey with Spring using maven webapp-archetype. When I get the object form the ApplicationContext I see my code executing, but when I try to use #Autowired it throws me NullPointerException. Following are the code snippets:
applicationContext.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<context:annotation-config />
<context:component-scan base-package="com.pack.resource" />
<bean id="person" class="com.pack.resource.Person">
<property name="name" value="SomeNamexxxx" />
</bean>
Person.java
package com.pack.resource;
public class Person {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Person() {
}
}
Hello.java
package com.pack.resource;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import org.springframework.beans.factory.annotation.Autowired;
import javax.ws.rs.core.MediaType;
import org.springframework.stereotype.Component;
#Component
#Path("/hello")
public class Hello {
#Autowired
Person person;
#GET
#Produces(MediaType.TEXT_PLAIN)
public String getName() {
return person.getName();
}
}
But when I use ApplicationContext.getBean("person").getName() it gives me the actual value inside the bean property.
Why is #Autowired annotation not working as it should. Kindly help me.
TIA!
i get NPE(null pointer exception) each time when i try to insert data into database. help me to resolve this issue. i have import all the necessary libraries which are requried for spring.
this is my applicationContext.xml file where i have configure all the beans.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<bean id="personService" class="com.ecommerce.assignment.service.PersonService">
<property name="personDAO" ref="personDAO" />
</bean>
<bean id="personBean" class="com.ecommerce.assignment.bean.PersonBean" />
<bean id="personDAO" class="com.ecommerce.assignment.dao.PersonDAO" />
</beans>
this is interface of person DAO.
public interface IPersonDAO {
public void addPerson(Person instance);
}
this personDAO class implementing IpersonDAO interface and its unimplemented methods.
public class PersonDAO implements IPersonDAO {
#Override
public void addPerson(Person instance) {
Session session = HibernateUtil.getSessionFactory().openSession();
session.beginTransaction().begin();
session.saveOrUpdate(instance);
session.getTransaction().commit();
session.close();
}
}
this is interface personService.
public interface IPersonService {
public void addPerson(Person instance);
}
public class PersonService implements IPersonService,Serializable {
private IPersonDAO personDAO;
public IPersonDAO getPersonDAO() {
return personDAO;
}
public void setPersonDAO(IPersonDAO personDAO) {
this.personDAO = personDAO;
}
#Override
public void addPerson(Person instance) {
getPersonDAO().addPerson(instance);
}
}
public class PersonBean implements Serializable {
private static final long serialVersionUID = 1L;
private String emailAddress;
private String password;
private String username;
#ManagedProperty(value = "#{personService}")
private IPersonService iPersonService;
public void addPerson(){
try{
Person person = new Person();
person.setUsername(getUsername());
person.setEmailAddress(getEmailAddress());
person.setPassword(getPassword());
iPersonService.addPerson(person);
}
catch(Exception ex){
ex.printStackTrace();
}
}
}
As your person bean is managed by Spring, you should use #Autowired annotation to make dependency injection, or inject it via XML, as you did for PersonService. You can as well declare the bean as #Component and #Scope.
You error is in injecting service in a bean by using JSF's #ManagedProperty annotation that works solely within JSF context, that is, with JSF managed beans, annotated with #ManagedBean, or declared via XML.
I use Spring with Hibernate and get always a NPE for the sessionFactory Object.
My config file:
#Configuration
public class HibernateConfiguration {
#Bean
public AnnotationSessionFactoryBean sessionFactory() {
Properties props = new Properties();
props.put("hibernate.dialect", MySQL5InnoDBDialect.class.getName());
props.put("hibernate.format_sql", "true");
props.put("hibernate.connection.driver_class", "com.mysql.jdbc.Driver");
props.put("hibernate.connection.password", "xxx");
props.put("hibernate.connection.url", "jdbc:mysql://localhost/Market");
props.put("hibernate.connection.username", "philipp");
AnnotationSessionFactoryBean bean = new AnnotationSessionFactoryBean();
bean.setAnnotatedClasses(new Class[] { xxx.class, xxx.class, xxx.class });
bean.setHibernateProperties(props);
bean.setSchemaUpdate(true);
return bean;
}
#Bean
public HibernateTransactionManager transactionManager() {
return new HibernateTransactionManager(sessionFactory().getObject());
}
#Bean
public PersistenceExceptionTranslationPostProcessor persistenceExceptionTranslationPostProcessor() {
return new PersistenceExceptionTranslationPostProcessor();
}
}
My DAOImpl class:
#Repository("xxx")
public class xxxDAOImpl implements xxxDAO {
private SessionFactory sessionFactory;
#Autowired
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
private Session currentSession() {
return sessionFactory.getCurrentSession();
}
...
Testcase:
#ContextConfiguration
#RunWith(SpringJUnit4ClassRunner.class)
public class TestxxxDAOImpl {
#Test
#Transactional
public void testInsertxxx() throws Exception {
xxxDAO xxxDAO = new xxxDAOImpl();
xyz xyz = new xyz();
xxxDAO.insert(xyz);
assertNotNull(xyz.getId());
}
}
app-context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xsi:schemaLocation="
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<tx:annotation-driven transaction-manager="transactionManager" />
<context:component-scan base-package="xxx.config" />
<context:component-scan base-package="xxx.dao" />
<context:annotation-config></context:annotation-config>
test-context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xsi:schemaLocation="http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<import resource="classpath:/META-INF/spring/app-context.xml" />
I get always an NPE from the currentSession when the test calls the insert method.
public void insert(xxx xxx) {
currentSession().save(xxx);
}
private Session currentSession() {
return sessionFactory.getCurrentSession();
}
The very first thing to understand when working with Spring is that Spring dependency injection only works for beans obtained from the application context, not for beans created with new.
In Spring-enabled unit tests you configure application context using #ContextConfiguration, for example, as follows (works in Spring 3.1, in previous versions #ContextConfiguration doesn't take #Configuration classes directly, therefore you'll have to create XML configuration file):
#Configuration
public class HibernateConfiguration {
// Add your DAO to application context
#Bean
public xxxDAO xxxDAO() {
return new xxxDAOImpl();
}
...
}
// Configure application context using the given #Configuration class
#ContextConfiguration(classes = HibernateConfiguration.class)
#RunWith(SpringJUnit4ClassRunner.class)
public class TestxxxDAOImpl {
// Obtain DAO from the application context
#Autowired xxxDao xxxDao;
...
}
Instead of sessionFactory.getCurrentSession() in currentSession() function of xxxDAOImpl class, use sessionFactory.openSession().
Since in your first call there would not be any current session in the session factory so you need to open the session.
Hope this helps you. Cheers.
Can spring framework override Annotation-based configuration with XML-based configuration? I need to change a dependency of a bean which is already defined via annotations and i am not the author of the bean.
i did not know that spring can mix configurations. here is the detailed and very useful example.
Bean1 is the actual bean we're configuring.
package spring;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
#Component
public class Bean1 {
private String naber;
#Autowired
#Qualifier("FireImpl1")
private Fire fire;
#PostConstruct
public void init() {
System.out.println("init");
getFire().fire();
}
#PreDestroy
public void destroy() {
System.out.println("destroy");
}
public void setNaber(String naber) {
this.naber = naber;
}
public String getNaber() {
return naber;
}
public void setFire(Fire fire) {
this.fire = fire;
}
public Fire getFire() {
return fire;
}
}
Fire is dependency interface
package spring;
public interface Fire {
public void fire();
}
and dummy implementation 1
package spring;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
#Component
#Qualifier("FireImpl1")
public class FireImpl1 implements Fire {
public void fire() {
System.out.println(getClass());
}
}
and dummy implementation 2
package spring;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
#Component
#Qualifier("FireImpl2")
public class FireImpl2 implements Fire {
public void fire() {
System.out.println(getClass());
}
}
config.xml
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context" xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
<context:component-scan base-package="spring" />
<bean id="bean1" class="spring.Bean1">
<property name="naber" value="nice" />
<property name="fire" ref="fireImpl2" />
</bean>
</beans>
and main class
package spring;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Spring {
public static void main(String[] args) {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("/spring/config.xml");
applicationContext.registerShutdownHook();
Bean1 bean = (Bean1) applicationContext.getBean("bean1");
System.out.println(bean.getNaber());
}
}
here is the output
init
class spring.FireImpl2
nice
destroy
Although annotation resolves dependency to FireImpl1, xml config overrided with FireImpl2.
very nice.
This should be OK. A Spring bean context allows you to redefine beans, with "later" definitions overriding "earlier ones". This should apply to XML-defined beans as well as annotation-defined beans, even if they're mixed.
For example, if you have
#Configuration
public class MyAnnotatedConfig {
#Bean
public Object beanA() {
...
}
}
<bean class="com.xyz.MyAnnotatedConfig"/>
<bean id="beanA" class="com.xyz.BeanA"/>
In this case, the XML definition of beanA should take precedence.