Spring auto-wire dependency which has constructor argument - java

I have my mailing service with has constructor argument and implements an interface
public class MailServiceImpl implements MailService {
private MailBo mail;
public MailBO getMail() {
return Mail;
}
public void setMail(MailBO Mail) {
this.Mail = Mail;
}
public MailServiceImpl(MailBo mail) {
throw exception if from and to address is not here
this.mail = mail;
}
public void sendMail(){
use mail object to send mail here
}
}
so now i am trying to write a test which i want to create Mailserviceimpl instance autowired with constructor argument passed in it.
i followed this link to autowire object with constructor, but i am getting below exception
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.model.MailBO] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}
my test class
public class MailServiceImplTest {
#Autowired
private MailService mailServiceImpl;
#Test
public void testSendValidMail(){
//test
}
}
EDIT:-
adding spring context
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
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.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.service" />
</beans>
EDIT 2:-
i want my mailbo loaded with some values and inject as constructor object to mailserviceimpl

I assume that MailServiceImpl and MailBO are Spring Beans. Then just annotate MailServiceImpl constructor by #Autowired and Spring will automatically injects constructor dependency

Related

Dependency of autowire failes

public class PartnershipMaintenanceFunction
{
final Logger logger = LoggerFactory.getLogger( PartnershipMaintenanceFunction.class );
#Autowired
PartnershipMaintenanceController partnershipMaintenanceServiceController;
public RetrievePartnershipResponse retrievePartnership( Message<RetrievePartnershipRequest> messageRequest )
{
RetrievePartnershipRequest retrievePartnershipRequest = messageRequest.getPayload();
MessageHeaders header = messageRequest.getHeaders();
return partnershipMaintenanceServiceController.retrievePartnership( retrievePartnershipRequest );
}
}
controller class
#RestController
#Api( "Partnership Maintainence" )
public class PartnershipMaintenanceController
{
final Logger logger = LoggerFactory.getLogger( PartnershipMaintenanceController.class );
#Autowired
PartnershipService partnershipService;
public void setPartnershipService( PartnershipService partnershipService )
{
this.partnershipService = partnershipService;
}
#GET
#Path( "/retrievePartnershipRequest" )
#ApiOperation( "Retrieve Partnership" )
public RetrievePartnershipResponse retrievePartnership( RetrievePartnershipRequest request )
{
return partnershipService.retrievePartnership( request );
}
}
public class PartnershipMaintenanceFunction
{
final Logger logger = LoggerFactory.getLogger( PartnershipMaintenanceFunction.class );
#Autowired
PartnershipMaintenanceController partnershipMaintenanceServiceController;
}
controller class
#RestController
#Api( "Partnership Maintainence" )
public class PartnershipMaintenanceController
{
final Logger logger = LoggerFactory.getLogger( PartnershipMaintenanceController.class );
#Autowired
PartnershipService partnershipService;
public void setPartnershipService( PartnershipService partnershipService )
{
this.partnershipService = partnershipService;
}
Error creating bean with name 'partnershipMaintenanceController':
Injection of autowired dependencies failed; nested exception is
org.springframework.beans.factory.BeanCreationException: Could not
autowire field:
com.cgi.bkifs.bso.prime.partnership.maintainence.service.PartnershipService
com.cgi.bkifs.rest.service.controller.PartnershipMaintenanceController.partnershipService;
nested exception is
org.springframework.beans.factory.NoSuchBeanDefinitionException: No
qualifying bean of type
[com.cgi.bkifs.bso.prime.partnership.maintainence.service.PartnershipService]
found for dependency: expected at least 1 bean which qualifies as
autowire candidate for this dependency. Dependency annotations:
{#org.springframework.beans.factory.annotation.Autowired(required=true)}
Probably you forgot to making PartnershipService as Spring Bean.
#Component
public class PartnershipService{}
If the bean ( PartnershipService ) is Normal bean then you can use #Component
If the bean (PartnershipService ) is service bean ( Service layer ) then you can use #service
Information about #Component, #Service, #Controller, and #Repository
annotation do in Spring Framework: #Component is a generic stereotype
for any Spring-managed component or bean. #Repository is a stereotype
for the persistence layer. #Service is a stereotype for the service
layer. #Controller is a stereotype for the presentation layer
(spring-MVC).
The error messages says:
Could not autowire field:
com.cgi.bkifs.bso.prime.partnership.maintainence.service.PartnershipService
Assuming that you already declared a class PartnershipService and it has the #Service annotation it is likely that you did not define the component scan.
Either add
#ComponentScan(basePackages = "com.cgi.bkifs.bso.prime.partnership") or in older versions use the xml file to define the scope of component scan:
<?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-3.0.xsd">
<context:component-scan base-package="com.cgi.bkifs.bso.prime.partnership"/>
</beans>

Spring configuration problem after Spring AOP implementation

I'm trying to implement Spring AOP in multiple layers application and make advice for #Service and #Controller classes.
Everything works fine without aspect class. When I add that part of code it causes Spring configuration problem.
#Aspect class:
#Aspect
#Component
public class ApplicationMonitor {
private static final Logger logger = Logger.getLogger(ApplicationMonitor.class);
#Pointcut(value = "execution(* hr.mycompany.controller.impl.MyCompanyController.update(*)) && args(obj)")
public void updateMC(Object obj){}
#Before(value="updateMC(obj)")
public void beforeUpdateMC(JoinPoint jp, Object obj) {
Object obj = jp.getArgs()[0];
logger.info("beforeUpdateMC " + obj);
}
}
Spring XML aspect configuration:
<aop:aspectj-autoproxy proxy-target-class="true"/>
Application #Controller and #Service classes:
#Controller
public class MyCompanyController implements IMyCompanyController{
#Autowired
private IMyComapnyService myCompanyService;
}
#Service
public class MyCompanyService implements IMyComapnyService {
#Autowired
private IGenericHibernateDao<Object, Integer> vwObjectDao;
}
Error:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [hr.mycompany.dao.IGenericHibernateDao] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
09:11:27,871 ERROR [org.apache.catalina.core.ContainerBase.[jboss.web].[default-host].[/BasicData-portlet]] (http--0.0.0.0-8083-2) StandardWrapper.Throwable: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'MyCompanyService': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private hr.mycompany.dao.IGenericHibernateDao hr.mycompany.services.impl.MyCompanyService.vwObjectDao; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [hr.mycompany.dao.IGenericHibernateDao] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
Where the problem is?
EDIT:
Part of class with Hibernate methods:
#Transactional(readOnly = true)
public abstract class GenericHibernateDao<T, PK extends Serializable> implements IGenericHibernateDao<T, PK> {
private static final Logger log = LoggerFactory.getLogger(GenericHibernateDao.class);
#Autowired
#Qualifier(value = "hibernateSessionFactory")
protected SessionFactory sessionFactory;
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
public SessionFactory getSessionFactory() {
return sessionFactory;
}
#SuppressWarnings("unchecked")
#Transactional(readOnly = false)
public PK save(T entity) {
Assert.notNull(entity, "Argument entity cannot be null in a call to GenericHibernateDao.save !");
Session session = getSessionFactory().getCurrentSession();
return (PK) session.save(entity);
}
...
}
EDIT (22-02-2019):
When I change this line of code:
<aop:aspectj-autoproxy proxy-target-class="true"/>
like this:
<aop:aspectj-autoproxy />
Error disapears, but aspect does not work.
I found solution.
I change this line of code in Spring XML config file:
<aop:aspectj-autoproxy proxy-target-class="true"/>
I set proxy-target-class to false:
<aop:aspectj-autoproxy proxy-target-class="false"/>
I deleted this dependency from pom.xml file:
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2</version>
</dependency>
I set the same spring-aop vesion like Spring version I use in Spring XML config file.
I changed this:
http://www.springframework.org/schema/aop/spring-aop.xsd
like this:
http://www.springframework.org/schema/aop/spring-aop-4.0.xsd

Why does the Injection of autowired dependencies failed in Spring web-service?

I started to work in a simple Spring web-service and getting the following errors provided below,
org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'blogEntryController':
Injection of autowired dependencies failed; nested exception
is org.springframework.beans.factory.BeanCreationException:
Could not autowire field: private core.services.BlogEntryService
rest.mvc.BlogEntryController.service; nested exception is
org.springframework.beans.factory.NoSuchBeanDefinitionException:
No qualifying bean of type [core.services.BlogEntryService] found for
dependency: expected at least 1 bean which
qualifies as autowire candidate for this dependency. Dependency
annotations:
{#org.springframework.beans.factory.annotation.Autowired(required=true)}
The project structure is as following,
Spring MVC project structure
I have the following service code,
package core.services;
import core.entities.BlogEntry;
public interface BlogEntryService {
public BlogEntry find(Long id); // Returns the BlogEntry or null if it can't be found
public BlogEntry delete(Long id); // Deletes the found BlogEntry or returns null if it can't be found
public BlogEntry update(Long id, BlogEntry data);
}
and, the following Controller code,
#Controller
#RequestMapping("/rest/blog-entries")
public class BlogEntryController {
#RequestMapping("/")
public String test(){
return "view";
}
public BlogEntryController() {
}
#Autowired
private BlogEntryService service;
public BlogEntryController(BlogEntryService service)
{
this.service = service;
}
#RequestMapping(value="/{blogEntryId}",
method = RequestMethod.GET)
public ResponseEntity<BlogEntryResource> getBlogEntry(
#PathVariable Long blogEntryId) {
BlogEntry entry = service.find(blogEntryId);
if(entry != null)
{
BlogEntryResource res = new BlogEntryResourceAsm().toResource(entry);
return new ResponseEntity<BlogEntryResource>(res, HttpStatus.OK);
} else {
return new ResponseEntity<BlogEntryResource>(HttpStatus.NOT_FOUND);
}
}
}
Update: Dispatcher Servlet.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
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.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="rest.mvc"/>
<mvc:annotation-driven/>
<bean id="jspViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
</beans>
I created the empty constructure as it was asked by the debugger earlier. I cant even see the view.jsp file returned from the test method. What should I do now ?
As I stated in my first comment beneath your question, you are missing the implementation class of the interface. An implementation class could be the one below, however you have to provide the functionality of the methods:
#Service
public class BlogEntryServiceImpl implements BlogEntryService {
public BlogEntry find(Long id) {
//Do your stuff here
}
public BlogEntry delete(Long id) {
//Do your stuff here
}
public BlogEntry update(Long id, BlogEntry data) {
//Do your stuff here
}
}
#Autowired
private BlogEntryService service;
Above lines says you are having class BlogEntryService annotated
with #Service or mentioned in bean tag or as component scan(package) in dispatcher-servlet xml.
If you are missing mentioning in any of one place you will get the exception No qualifying bean of type [core.services.BlogEntryService] found for dependency:
So your BlogEntryService interface should be
#Service
public interface BlogEntryService {
Update : In dispathcer-servlet.xml you have to mention the packages to scan for beans.In your case it is rest.mvc.Since it's an Interface you should have the implemented class(annotated with #Service),which will have definition of interface methods.
<context:component-scan base-package="Your Service layer Package" />
It looks that BlogEntryService bean class is not provided. Do you have some implementation class annotated wit #Service?
Either you provide an implementation class for your interface and annotate it with #service, OR make the BlogEntryService interface extend CrudRepository and Spring will provide you with the proper implementation for your cruds :save, getAll, find...
It looks like an implementation of your service is missing.
Just annotating an interface with #Service is not enough for Spring to generate a bean unless you are extending your interface with some of the specific Spring Data interface (CrudRepository, Repository ...). In that specific case and if you respect sone convention Spring will be able to automatically generate the implementation for you.
Please have a look to the documentation: http://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories

Spring factory bean with #Autowired in superclass

I've implemented a factory bean in Spring to instantiate different subclasses of a superclass. The problem I have is that superclass properties aren't being #Autowired (I guess due to the new command in the factory methods). This is my code:
#Component
public class ConfigBeanImpl implements ConfigBean{
#Override
public String expandParam(String param) {
return String.format("expanded %s", param);
}
}
public abstract class FactoryBean {
#Autowired
protected ConfigBean configBean;
private String property;
protected FactoryBean() {
this.property = configBean.expandParam("property");
}
public abstract String getProperty();
public static FactoryBean GET(int id) {
return new FactoryBeanGet(id);
}
public static FactoryBean POST(String param){
return new FactoryBeanPost(param);
}
}
public class FactoryBeanGet extends FactoryBean {
private int id;
protected FactoryBeanGet(int id) {
this.id = id;
}
#Override
public String getProperty() {
return Integer.toString(id);
}
}
public class FactoryBeanPost extends FactoryBean {
private String param;
protected FactoryBeanPost(String param) {
this.param = param;
}
#Override
public String getProperty() {
return param;
}
}
public class Main {
public static void main(String[] args) {
ApplicationContext context =
new ClassPathXmlApplicationContext(new String[] {"applicationContext.xml"});
FactoryBean bean = (FactoryBean) context.getBean("factoryBeanGet", 12);
System.out.println(bean.getProperty());
bean = (FactoryBean) context.getBean("factoryBeanPost", "test param");
System.out.println(bean.getProperty());
}
}
And the 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-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd">
<context:component-scan base-package="com.spring" />
<bean id="factoryBeanGet" scope="prototype" class="com.spring.bean.FactoryBean"
factory-method="GET">
</bean>
<bean id="factoryBeanPost" scope="prototype" class="com.spring.bean.FactoryBean"
factory-method="POST">
</bean>
The protected ConfigBean configBean property in abstract class FactoryBean isn't being #Autowired and hence is null and the constructor throws a NullPointerException. If I place it inside each of the subclasses, it works fine, but it'd be duplicated code. Is there a way to solve this or am I doing something wrong?
Put yourself in Spring's shoes. It must instantiate FactoryBean, and then initialize its configBean field. So, the first thing it will do is call the constructor. And then, once the object exists, it will initialize the object's field. It obviously can't initialize the field if the object doesn't exist yet. So, at the time the constructor is called, the field is still null.
Use constructor injection, or use a method annotated witb #PostConstruct to call the configBean.
That said, the private property field that you're trying to initialize is not used anywhere, so you could as well remove it, and remove the configBean field as well.

How to write JUnit test with Spring Autowire?

Here are the files that I use:
component.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:jee="http://www.springframework.org/schema/jee"
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-3.0.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd">
<context:component-scan
base-package="controllers,services,dao,org.springframework.jndi" />
</beans>
ServiceImpl.java
#org.springframework.stereotype.Service
public class ServiceImpl implements MyService {
#Autowired
private MyDAO myDAO;
public void getData() {...}
}
ServiceImplTest.java
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration("classpath*:conf/components.xml")
public class ServiceImplTest{
#Test
public void testMyFunction() {...}
}
Error:
16:22:48.753 [main] ERROR o.s.test.context.TestContextManager - Caught exception while allowing TestExecutionListener [org.springframework.test.context.support.DependencyInjectionTestExecutionListener#2092dcdb] to prepare test instance [services.ServiceImplTest#9e1be92]
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'services.ServiceImplTest': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private services.ServiceImpl services.ServiceImplTest.publishedServiceImpl; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [services.ServiceImpl] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:287) ~[spring-beans.jar:3.1.2.RELEASE]
Make sure you have imported the correct package. If I remeber correctly there are two different packages for Autowiring. Should be :org.springframework.beans.factory.annotation.Autowired;
Also this looks wierd to me :
#ContextConfiguration("classpath*:conf/components.xml")
Here is an example that works fine for me :
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "/applicationContext_mock.xml" })
public class OwnerIntegrationTest {
#Autowired
OwnerService ownerService;
#Before
public void setup() {
ownerService.cleanList();
}
#Test
public void testOwners() {
Owner owner = new Owner("Bengt", "Karlsson", "Ankavägen 3");
owner = ownerService.createOwner(owner);
assertEquals("Check firstName : ", "Bengt", owner.getFirstName());
assertTrue("Check that Id exist: ", owner.getId() > 0);
owner.setLastName("Larsson");
ownerService.updateOwner(owner);
owner = ownerService.getOwner(owner.getId());
assertEquals("Name is changed", "Larsson", owner.getLastName());
}
I've done it with two annotations for test class: #RunWith(SpringRunner.class) and #SpringBootTest.
Example:
#RunWith(SpringRunner.class )
#SpringBootTest
public class ProtocolTransactionServiceTest {
#Autowired
private ProtocolTransactionService protocolTransactionService;
}
#SpringBootTest loads the whole context, which was OK in my case.
A JUnit4 test with Autowired and bean mocking (Mockito):
// JUnit starts with spring context
#RunWith(SpringRunner.class)
// spring loads context configuration from AppConfig class
#ContextConfiguration(classes = AppConfig.class)
// overriding some properties with test values if you need
#TestPropertySource(properties = {
"spring.someConfigValue=your-test-value",
})
public class PersonServiceTest {
#MockBean
private PersonRepository repository;
#Autowired
private PersonService personService; // uses PersonRepository
#Test
public void testSomething() {
// using Mockito
when(repository.findByName(any())).thenReturn(Collection.emptyList());
Person person = new Person();
person.setName(null);
// when
boolean found = personService.checkSomething(person);
// then
assertTrue(found, "Something is wrong");
}
}
For Spring 5.x and JUnit 5, writing unit tests is quite different.
We have to use #ExtendWith to register Spring extensions (SpringExtension). This brings Spring into play which activates part of the application context (instantiates and manages beans from selected configuration classes).
Note that this is different from the effect of #SpringBootTest which loads the full application context (and IMHO cannot be considered a unit test).
For example, let's create a configuration class FooConfig which produces a bean named foo1:
#Configuration
public class FooConfig
{
#Bean
public String foo1() { return "Foo1"; }
}
Now, let's write a JUnit 5 test case which injects foo1:
import static org.junit.jupiter.api.Assertions.*;
// ... more imports ...
#ExtendWith(SpringExtension.class)
#ContextConfiguration(classes = {
helloworld.config.FooConfig.class,
})
class FooTests
{
#BeforeAll
static void setUpBeforeClass() throws Exception {}
#AfterAll
static void tearDownAfterClass() throws Exception {}
#BeforeEach
void setUp() throws Exception {}
#AfterEach
void tearDown() throws Exception {}
#Autowired
private String foo1;
#Test
void test()
{
assertNotNull(foo1);
System.err.println(foo1);
}
}
In Spring 2.1.5 at least, the XML file can be conveniently replaced by annotations.
Piggy backing on #Sembrano's answer, I have this. "Look ma, no XML".
It appears I to had list all the classes I need #Autowired in the #ComponentScan
#RunWith(SpringJUnit4ClassRunner.class)
#ComponentScan(
basePackageClasses = {
OwnerService.class
})
#EnableAutoConfiguration
public class OwnerIntegrationTest {
#Autowired
OwnerService ownerService;
#Test
public void testOwnerService() {
Assert.assertNotNull(ownerService);
}
}
I think somewhere in your codebase are you #Autowiring the concrete class ServiceImpl where you should be autowiring it's interface (presumably MyService).
You should make another XML-spring configuration file in your test resource folder or just copy the old one, it looks fine, but if you're trying to start a web context for testing a micro service, just put the following code as your master test class and inherits from that:
#WebAppConfiguration
#RunWith(SpringRunner.class)
#ContextConfiguration(locations = "classpath*:spring-test-config.xml")
public abstract class AbstractRestTest {
#Autowired
private WebApplicationContext wac;
}
You can use #Import annotation. It's more readable and shorter than using the #ComponentScan annotation.
import org.springframework.context.annotation.Import;
#Import(value = {MyService.class, MyInjectedService.class})
public class JUnitTest {
#Autowired
private MyService service;
// ...
}

Categories

Resources