Adding Aspect bean definition in java config is not letting create other beans - spring

I am kind of new to spring and trying to add a simple advice to a simple method join point using #Aspect annotation in Spring.
I have used a simple interface and an implementing method
package aspect;
public interface Module {
public void getModuleName();
}
package aspect;
import org.springframework.stereotype.Component;
#Component
public class MyModule implements Module {
#Override
public void getModuleName() {
long t = System.nanoTime();
System.out.println("My Module.");
long t1 = System.nanoTime()-t;
System.out.println("Execution time : "+t1);
}
}
One simple advice as below
package aspect;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
#Aspect
public class MyDefinedAspectLogging {
#Pointcut("execution(* aspect.MyModule.getModuleName(..))")
public void dummy() {}
#Before("dummy()")
public void beforeLog()
{
System.out.println("Log Before entering service");
}
#After("dummy()")
public void AfterLog()
{
System.out.println("Log After returning from service");
}
}
My context config file is as below
package aspect;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
#Configuration
#EnableAspectJAutoProxy
#ComponentScan(basePackageClasses= {MyModule.class})
public class ConfigJava {
#Bean
public MyDefinedAspectLogging getMyDefinedAspectLogging() {
return new MyDefinedAspectLogging();
}
}
And I have implemented a simple class for testing as below
package aspect;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Mainer {
public static void main(String[] args) {
ApplicationContext context = new
AnnotationConfigApplicationContext(ConfigJava.class);
MyModule m = context.getBean(MyModule.class);
m.getModuleName();
((ConfigurableApplicationContext)context).close();
}
}
When I run this I am getting error as below
Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [aspect.MyModule] is defined
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:371)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:331)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:968)
at aspect.Mainer.main(Mainer.java:12)
As per my understanding MyModule class should be created using component scan.
Inorder to test this I have commented my advice bean definition in java config as below
package aspect;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
#Configuration
#EnableAspectJAutoProxy
#ComponentScan(basePackageClasses= {MyModule.class})
public class ConfigJava {
/* #Bean
public MyDefinedAspectLogging getMyDefinedAspectLogging() {
return new MyDefinedAspectLogging();
}*/
}
And after this I ran Main method of Mainer class and got below output
Mar 16, 2018 7:17:35 PM org.springframework.context.annotation.AnnotationConfigApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext#5fa7e7ff: startup date [Fri Mar 16 19:17:35 IST 2018]; root of context hierarchy
My Module.
Execution time : 101664
Mar 16, 2018 7:17:36 PM org.springframework.context.annotation.AnnotationConfigApplicationContext doClose
INFO: Closing org.springframework.context.annotation.AnnotationConfigApplicationContext#5fa7e7ff: startup date [Fri Mar 16 19:17:35 IST 2018]; root of context hierarchy
What Am I missing here. Howcome defining advice bean is stopping the implementation bean creation in Spring context.
Some point I have tried but didn't get any success:
I have used basePackages instead of basePackageClasses for value of #ComponentScan annotaion
I have used #ComponentScan without any vaue
I have tried defining MyModule bean inside java config instead of component scan.
Update:
I have tried using Module instead of MyModule in pointcut expression
#Pointcut("execution(* aspect.Module.getModuleName(..))")
public void dummy() {}

Related

Spring boot #RestController test code error

I created a test code for #RestController on the spring boot and this error occurs.
java.lang.IllegalStateException: Failed to load ApplicationContext
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:132)
---------------------------------------------------------------------------
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'memberController' defined in file [C:\dev\react\Kculter\target\classes\com\prac\react\controller\MemberController.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.prac.react.service.MemberService' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
--------------------------------------------------------------------------------------------------
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.prac.react.service.MemberService' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
I see this problem even though I added #Service annotations to the MemberService class and #RestController annotations to the MemberController class.
How can I solve it?
I'll show my Test code, MemberCotroller, MemberService code below
MemberControllerTest.java
package com.prac.react.controller;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.prac.react.model.dto.Member;
import com.prac.react.service.MemberServiceTest;
#WebMvcTest(MemberController.class)
public class MemberControllerTest {
#Autowired
MockMvc mvc; // 가상의 http request를 테스트 할때 만들기 위해서 사용하는 인스턴스
#Autowired
ObjectMapper obm;
Logger logger = LoggerFactory.getLogger(MemberServiceTest.class);
#Test
#DisplayName("로그인 테스트 1 ") // 회원이 존재할때를 가장했을때를 위한 테스트 코드
void testSignInMember() throws Exception {
// given
Member mb = new Member(1, "hankgood95#gmail.com", "이욱재", true);
String requestBody = obm.writeValueAsString(mb);
mvc.perform(post("/member")
.content(requestBody)
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk()) //status가 200이고
.andExpect(content().string(".com")) //content안에 .com이 있다면
.andDo(print()); //요청받은것들으 print 해라
}
}
MemberController.java
package com.prac.react.controller;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import com.prac.react.model.dto.Member;
import com.prac.react.service.MemberService;
/* 이파일은 회원가입,로그인,회원정보수정 등등
회원 정보와 관련된 일을 할때 들어올 Controller 입니다 */
#RestController
public class MemberController {
//로그를 찍어보기 위해서 만든 인스턴스
Logger logger = LoggerFactory.getLogger(MemberController.class);
//MemberService 의존성 주입을 위해 사용할 인스턴스
MemberService ms;
public MemberController(MemberService ms){
this.ms = ms; //의존성 주입
}
#PostMapping("member")
public Member SignInMember(#RequestBody Member member){
if(ms.checkMember(member.getEmail()) > 0){ //이미 우리 회원일때 접근
//이미 우리 회원이라면 여기서 얻은 Member 정보를 가지고 메인페이지로 이동을 해야한다.
member.setCheckMember(true);
return member;
}else{//처음 가입할때 접근
//우리 회원이 아니라면 이제 회원가입 페이지로 이동을 해야한다.
member.setCheckMember(false);
return member;
}
}
}
MemberService.java
package com.prac.react.service;
import org.springframework.stereotype.Service;
import com.prac.react.model.dao.MemberDao;
#Service
public class MemberService {
MemberDao md;
//MemberDao 인스턴스의 의존성 주입을 위해 생성자 안에서 집어 넣어주었습니다.
//여기서 주의해야할점은 의존성 주입이 하나 이상일땐 #Autowired 어노테이션을 꼭 넣어줘야만 합니다.
public MemberService(MemberDao md){
this.md = md;
}
public int checkMember(String email){
return md.checkMember(email);
}
}
When you using the test slice #WebMvcTest:
Regular #Component and #ConfigurationProperties beans are not scanned when the #WebMvcTest annotation is used.
This means your class annotated with #Service is also not configured.
You can use #MockBean to create a mock for this service.
Reference with Example: Spring Boot Reference

Bean Creation or defining is failing in springboot

Main Class
package com.prac.sdp;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import com.prac.sdp.pdf.PdfGenerator;
#SpringBootApplication
public class SdpApplication {
public static void main(String[] args) {
ApplicationContext ctx=SpringApplication.run(SdpApplication.class, args);
PdfGenerator pdg=ctx.getBean(PdfGenerator.class);
pdg.pdfgenerate();
}
}
PdfGenerator.java
package com.prac.sdp.pdf;
import java.io.FileNotFoundException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfPage;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.kernel.pdf.canvas.PdfCanvas;
import com.itextpdf.layout.Document;
#Component
public class PdfGenerator {
#Autowired
PdfWriter writer; <------ Autowiring is not working here I don't know why.
}
Issue -- Consider defining a bean of type 'com.itextpdf.kernel.pdf.PdfWriter' in your
configuration.
Resolution tried:
Used #ComponentScan("com.itextpdf") --> Started getting Exception in thread "main"
org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type
'com.prac.sdp.pdf.PdfGenerator' available.
Let me know how this issue can be fixed I am stuck at this. Thanks in advance.
create bean with #Bean annotation tag , as this is from third party library , you need to define by Method.
#Bean
public PdfWriter writer(){
return new PdfWriter();
}
Add above method to your SdpApplication class.

Spring boot: #Repository class not found to inject

This is my Spring boot application related code:
#ComponentScan({"net.gencat.transversal.espaidoc.scheduler", "net.gencat.transversal.espaidoc.backoffice"})
public class SchedulerApplication {//...}
By other hand, I've a repository on package net.gencat.transversal.espaidoc.backoffice.dao:
#Repository
public interface DocumentDAO extends CrudRepository<Document, String> {
}
So, I've a service with a DocumentDAO dependency:
#Service
public class DocumentServiceBackOffice {
private DocumentDAO documentDAO;
public DocumentServiceBackOffice(DocumentDAO documentDAO) {
this.documentDAO = documentDAO;
}
}
However, I'm getting this message:
NoSuchBeanDefinitionException: No qualifying bean of type 'net.gencat.transversal.espaidoc.backoffice.dao.DocumentDAO' available
I've also tried adding #EnableJpaRepositories, but it still doesn't work.
Any ideas?
EDIT
This is my SpringApplication class:
package net.gencat.transversal.espaidoc;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Import;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.scheduling.annotation.EnableScheduling;
import net.gencat.transversal.espaidoc.common.config.FrontOfficeProperties;
import net.gencat.transversal.espaidoc.common.config.RedisConfiguration;
#SpringBootApplication(exclude = JmxAutoConfiguration.class)
#EnableConfigurationProperties({
FrontOfficeProperties.class
})
#Import(RedisConfiguration.class)
#EnableScheduling
// #ComponentScan("net.gencat.transversal.espaidoc")
//#EnableJpaRepositories
public class SchedulerApplication {
public static void main(String[] args) {
SpringApplication.run(SchedulerApplication.class, args);
}
}
EDIT2:
I've just realized on spring logs that there's some issue related with DocumentDAO:
--- [ main] .RepositoryConfigurationExtensionSupport : Spring Data JPA - Could not safely identify store assignment for repository candidate interface net.gencat.transversal.espaidoc.backoffice.dao.DocumentDAO.
Try adding the following:
#EnableJpaRepositories(basePackages="net.gencat.transversal.espaidoc.backoffice.dao")
public class SchedulerApplication

Spring bean getting initialised twice in java configuration

I've created a spring application using spring-security with java based configuration. I've also included a jar file (created by me) in my project.
The problem I am facing is:- i have to write #ComponentScan(basePackages = {"com.mypackage"}) in both the classes (SpringConfig.java and SecurityConfig.java) which leads to initialization of beans twice.
Removing either of #componentscan leads to error:- Error creating bean with name 'securityConfig'.
Below are my java classes.
SpringConfig.java
package com.mypackage.config;
import javax.annotation.PostConstruct;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
#EnableWebMvc
#Configuration
#ComponentScan(basePackages = {"com.mypackage"})
public class SpringConfig extends WebMvcConfigurerAdapter {
private static final Logger logger = LoggerFactory.getLogger(SpringConfig.class);
#PostConstruct
public void init(){
logger.debug("Spring Config initialized");
}
}
SecurityConfig.java
package com.mypackage.config;
import javax.annotation.PostConstruct;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
#Configuration
#EnableWebSecurity
#ComponentScan(basePackages = {"com.mypackage"})
public class SecurityConfig extends WebSecurityConfigurerAdapter{
private static final Logger logger = LoggerFactory.getLogger(SecurityConfig.class);
//This Configuration class is in my jar file.
// with package starting with same name com.mypackage
#Autowired
com.mypackage.frameworks.config.Configuration config;
#PostConstruct
public void init(){
logger.debug("Security config initiaziled");
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) {
try {
auth.inMemoryAuthentication()
.withUser("admin").password("admin").roles("USER");
} catch (Exception e) {
e.printStackTrace();
}
}
}
MyController.java
package com.mypackage.controller;
import javax.annotation.PostConstruct;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
#Controller
public class MyController {
private static final Logger logger = LoggerFactory.getLogger(MyController.class);
#PostConstruct
public void init(){
logger.debug("-------Controller created-------");
}
}
You have configured bean definitions into multiple #Configuration classes. My suggestion is - Aggregating #Configuration classes with #Import into single place.
Now you can able to apply #ComponentScan(basePackages = {"com.mypackage"}) in one place and context also loads bean only one time.
The #Import annotation provides just this kind of support, and it is the direct equivalent of the element found in Spring beans XML files.
Please refer this link - https://docs.spring.io/spring-javaconfig/docs/1.0.0.M4/reference/html/ch04s03.html
Beans will be configured and created twice because both application context scans the same package "com.mypackage". One solution is to separate SpringConfig beans package from SecurityConfig beans package. be as more specific as you can in #ComponentScan package value

spring boot #Value always null

I am using spring boot 1.5.3 and trying to inject the properties from an application-dev.properties file into a Service bean but the value is always coming as null. The value does get loaded in my DevConfiguration class though.
I have a application class as below in my base package
package com.me;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
I have a configuration class as follows in
package com.me.print.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.annotation.PropertySources;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
#Configuration
#Profile("dev")
#PropertySources({
#PropertySource("classpath:application.properties"),
#PropertySource("classpath:application-dev.properties")
})
#ComponentScan(value = {"com.me.print.client"})
public class DevConfiguration {
#Value("${app.service.url}")
private String rootUri;
#Bean
public static PropertySourcesPlaceholderConfigurer placeholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
}
My Service bean that I am trying to load the value into is below
package com.me.print.client;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import com.me.print.model.zitResponse;
#Service
public class zitPrintClient {
private final RestTemplate restTemplate;
#Value("${app.service.url}")
private String rootUri;
public zitPrintClient(RestTemplateBuilder restTemplateBuilder) {
restTemplate = restTemplateBuilder
//.rootUri(rootUri)
.build();
}
public zitResponse getpooltatus(String poolId) {
return restTemplate.getForObject("/pool/{poolId}/#status",
zitResponse.class, poolId);
}
}
In the above class the rootURI is always null. Does anyone have any suggestions as to what I am missing
in my application-dev.properties file I have the following
app.service.url=http://localhost:8080/zitprint/v1
Thanks
UPDATE:
does anyone have any suggestions here as I tried to inject properties into my controller as follows:
#Value("${allowedVendors}") String allowedVendors
and if i put the above into a constructor it finds the value but does not find it otherwise:
public PController(#Value("${allowedVendors}") String allowedVendors) {
}
I cant use the property further in the code as with the constructor I have created two instances of the bean 1 via the constructor and the other created by spring DI. Any ideas why the value doesnt inject without the constructor
Thanks
You need to put it as a parameter in the constructor:
public zitPrintClient(RestTemplateBuilder restTemplateBuilder,
#Value("${app.service.url}") rootUri) {
this.rootUri = rootUri; // if you are only using this once,
// no need to keep this member variable around
restTemplate = restTemplateBuilder
.rootUri(rootUri)
.build();
}
The constructor gets called first when you are creating the object. The member variable, rootUri, would have it's value injected after the object is created. So, rootUri member variable would be null at the time the constructor is called.
(And, imho, for better readability, your class should start with a capital letter, i.e. ZitPrintClient, but it's your code ...)

Resources