#BeforeAdvise is not working for same method names in Spring BOOT - spring

I am learning Spring AOP and tried to call the #BeforeAdvise for two Different methods in different classes. But the log added in the first call is getting printed only. Please check the code below and let me know what is not correct here.
MainClass
package com.example.aspects;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import com.example.aspects.AopClasses.DemoConfig;
#SpringBootApplication
public class AspectsApplication {
public static void main(String[] args) {
SpringApplication.run(AspectsApplication.class, args);
}
}
AspectClass
package com.example.aspects.Acpects;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
#Aspect
#Component
public class MyLoggingDemo {
private static final Logger logger = LogManager.getLogger(MyLoggingDemo.class);
#Before("execution(public String test())")
public void beforeCheck() {
logger.info("Before Check !!!!!!!!!!!! "+System.currentTimeMillis() );
}
}
ConfigClass
package com.example.aspects.AopClasses;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
#Configuration
#EnableAspectJAutoProxy
#ComponentScan("com.example.aspects")
public class DemoConfig {
}
TestClass- Where the first call is made to the function
package com.example.aspects.AopClasses;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
#RestController
#RequestMapping("/")
public class tesTClass {
private static final Logger logger = LogManager.getLogger(tesTClass.class);
MemberShipDAO dao = new MemberShipDAO();
#RequestMapping(value = "/")
public String test() {
logger.info("Hey I am here");
return "HEy There I am Working !!";
}
#RequestMapping(value ="/test")
public String testing() {
logger.info("MemberShipDAO Call");
return dao.test(); // method with same name called here again
}
}
MemberShipDAO - Declared the test method again here
package com.example.aspects.AopClasses;
import org.springframework.stereotype.Component;
#Component
public class MemberShipDAO {
public String test() {
return "HEy!!";
}
}
Console
2022-01-18 11:37:52.794 INFO 8032 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
2022-01-18 11:37:52.796 INFO 8032 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
2022-01-18 11:37:52.802 INFO 8032 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 5 ms
2022-01-18 11:37:52.811 INFO 8032 --- [nio-8080-exec-1] c.example.aspects.Acpects.MyLoggingDemo : Before Check !!!!!!!!!!!! 1642486072811
2022-01-18 11:37:52.854 INFO 8032 --- [nio-8080-exec-1] c.example.aspects.AopClasses.tesTClass : Hey I am here
2022-01-18 11:37:57.383 INFO 8032 --- [nio-8080-exec-3] c.example.aspects.AopClasses.tesTClass : MemberShipDAO Call

Change this
MemberShipDAO dao = new MemberShipDAO();
to this
#Autowired MemberShipDAO dao;
Spring's magic for the AOP happens only when you use the instance created by Spring. Behind the scene, Spring instantiated your dao and wrapped it with a proxy that makes a call to your aspect.

Related

Why is AOP Logging not working in my project

I'm wasting a lot of time right now with AOP logging setup.
I don't know why AOP isn't working in my project.
I think I've done all the settings I can.
Please let me know if you guys have a solutions.
Thank you.
application.java
#EnableAspectJAutoProxy
#SpringBootApplication
#ComponentScan(basePackages = "com.demo.apiservice")
#MapperScan("com.demo.apiservice.mapper")
public class ApiServiceApplication extends SpringBootServletInitializer {
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(ApiServiceApplication.class);
}
public static void main(String[] args) {
SpringApplication.run(ApiServiceApplication.class, args);
}
#Bean
public ModelMapper modelMapper() {
return new CustmizedModelMapper();
}
#Bean
public AopLoggingConfig loggingAspect(){
return new AopLoggingConfig();
}
}
build.gradle
configurations {
all {
exclude group: 'org.springframework.boot', module: 'spring-boot-starter-logging'
}
}
dependencies {
//implementation 'org.springframework.boot:spring-boot-starter-security:2.5.5'
implementation 'org.springframework.boot:spring-boot-starter-web:2.5.5'
implementation 'org.springframework.boot:spring-boot-starter-log4j2:2.5.5'
implementation 'org.springframework.boot:spring-boot-starter-mail:2.5.5'
implementation 'org.springframework.boot:spring-boot-starter-aop:2.5.5'
implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:2.1.3'
testImplementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter-test:2.1.3'
implementation 'org.springframework.boot:spring-boot-starter-data-rest:2.5.5'
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.projectlombok:lombok:1.18.8'
implementation 'org.modelmapper:modelmapper:2.3.8'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa:2.5.5'
implementation 'org.springframework.boot:spring-boot-starter-jdbc:2.5.5'
implementation 'com.h2database:h2:1.4.200'
implementation 'org.springframework.boot:spring-boot-configuration-processor:2.5.5'
implementation 'org.springframework.security:spring-security-core:5.4.2'
implementation 'com.fasterxml.jackson.core:jackson-core:2.12.3'
implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.12.3'
implementation 'com.fasterxml.jackson.core:jackson-databind:2.12.3'
implementation 'org.apache.httpcomponents:httpclient:4.5.13'
implementation 'com.nimbusds:nimbus-jose-jwt:9.7'
implementation 'io.springfox:springfox-swagger2:3.0.0'
implementation 'io.springfox:springfox-swagger-ui:2.9.2'
implementation 'joda-time:joda-time:2.10.10'
implementation 'io.jsonwebtoken:jjwt-api:0.11.1'
implementation 'javax.inject:javax.inject:1'
implementation 'com.googlecode.json-simple:json-simple:1.1'
implementation 'de.mkammerer:argon2-jvm:2.7'
implementation 'org.bouncycastle:bcprov-jdk15on:1.68'
implementation 'org.apache.maven.plugins:maven-surefire-plugin:2.22.0'
implementation 'javax.validation:validation-api:2.0.1.Final'
implementation 'org.postgresql:postgresql:42.1.4'
implementation 'org.hibernate:hibernate-gradle-plugin:5.6.1.Final'
implementation 'com.jayway.jsonpath:json-path:2.6.0'
compileOnly 'org.projectlombok:lombok:1.18.8'
testCompileOnly 'org.projectlombok:lombok:1.18.8'
runtimeOnly 'org.springframework.boot:spring-boot-devtools:2.5.5'
annotationProcessor 'org.projectlombok:lombok:1.18.8'
testAnnotationProcessor 'org.projectlombok:lombok:1.18.8'
testImplementation 'org.springframework.boot:spring-boot-starter-test:2.5.5'
testImplementation 'org.springframework.security:spring-security-test:5.5.2'
}
AopLoggingComponent.java
package com.demo.apiservice.config;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
#Component
#Aspect
public class AopLoggingConfig {
Logger logger = LoggerFactory.getLogger(AopLoggingConfig.class);
static String name = "";
static String type = "";
/**
* AspectJ is applied only to a specific class/method in package.
*/
#Around("execution(* com.demo.apiservice.customer.*Controller.*(..))")
public Object logPrint(ProceedingJoinPoint joinPoint) throws Throwable {
type = joinPoint.getSignature().getDeclaringTypeName();
if (type.indexOf("Controller") -1) {
name = "Controller \t: ";
}
else if (type.indexOf("Service") -1) {
name = "ServiceImpl \t: ";
}
else if (type.indexOf("DAO") -1) {
name = "DAO \t\t: ";
}
logger.debug(name + type + ".######################### " + joinPoint.getSignature().getName() + "()");
return joinPoint.proceed();
}
}
controller.java
package com.demo.apiservice.customer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import com.demo.apiservice.constant.Constants;
import com.demo.apiservice.customer.service.CustomerService;
import com.demo.apiservice.customer.service.impl.CustomerServiceImpl;
import com.demo.apiservice.request.CustomerRequest;
import com.demo.apiservice.request.LoginRequest;
import com.demo.apiservice.response.GetCustomerResponse;
import com.demo.apiservice.response.SuccessResponse;
import com.demo.apiservice.utils.ResponseHandler;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
import lombok.extern.slf4j.Slf4j;
import java.util.List;
import javax.validation.Valid;
#Slf4j
#RestController
#Api(tags = "Customers APIs")
#RequestMapping("/apiservice/v1/customers")
public class CustomerController {
#Autowired
private CustomerService customerService;
#GetMapping
#ApiOperation(value = "List of Customers API")
#ApiResponses(value = {
#ApiResponse(code = 400, message = Constants.BAD_REQUEST),
#ApiResponse(code = 403, message = Constants.ACCESS_DENIED)})
public ResponseEntity<Object retrieveAll() {
log.info("Start of CustomerController::retrieveAll method");
return customerService.retrieveAll();
}
}
application.yml
logging:
level:
org:
springframework.web: DEBUG
hibernat: DEBUG
com:
atoz_develop:
mybatissample:
repository: TRACE
mybatis:
mapper-locations: classpath:/mappers/*.xml
type-aliases-package: com.demo.apiservice.entity
configuration:
map-underscore-to-camel-case: 'true'
debug: 'true'
spring:
datasource:
driver-class-name: org.postgresql.Driver
username: postgres
url: jdbc:postgresql://localhost:5432/postgres
platform: postgres
password: postgres
jpa:
generate-ddl: 'false'
properties:
hibernate:
dialect: org.hibernate.dialect.PostgreSQL10Dialect
format_sql: 'true'
hibernate:
ddl-auto: update
show-sql: 'true'
stack trace log
2021-11-17 16:05:19.992 DEBUG 23300 --- [nio-8080-exec-8] o.s.w.s.DispatcherServlet : GET /apiservice/v1/customers, parameters={} 2021-11-17 16:05:19.992 DEBUG 23300 --- [nio-8080-exec-8] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to com.demo.apiservice.customer.CustomerController#retrieveAll()
2021-11-17 16:05:19.993 INFO 23300 --- [nio-8080-exec-8] c.l.a.c.CustomerController : Start of CustomerController::retrieveAll method
2021-11-17 16:05:19.993 INFO 23300 --- [nio-8080-exec-8] c.l.a.c.s.i.CustomerServiceImpl : Inside of the CustomerServiceImpl :: retrieveAll method
2021-11-17 16:05:19.996 INFO 23300 --- [nio-8080-exec-8] c.l.a.c.s.i.CustomerServiceImpl : End of the CustomerServiceImpl :: retrieveAll method
2021-11-17 16:05:19.996 DEBUG 23300 --- [nio-8080-exec-8] o.s.w.s.m.m.a.HttpEntityMethodProcessor : Using application/xhtml+xml, given [text/html, application/xhtml+xml, image/avif, image/webp, image/apng, application/xml;q=0.9, application/signed-exchange;v=b3;q=0.9, */*;q=0.8] and supported [application/json, application/*+json, application/json, application/*+json, application/xml;charset=UTF-8, text/xml;charset=UTF-8, application/*+xml;charset=UTF-8, application/xml;charset=UTF-8, text/xml;charset=UTF-8, application/*+xml;charset=UTF-8]
2021-11-17 16:05:19.996 DEBUG 23300 --- [nio-8080-exec-8] o.s.w.s.m.m.a.HttpEntityMethodProcessor : Writing [{data=[Customer(email=test1#test.com, password=null, customerId=null, storeName=eos, firstname=test1 (truncated)...]
2021-11-17 16:05:19.998 DEBUG 23300 --- [nio-8080-exec-8] o.s.w.s.DispatcherServlet : Completed 200 OK
Your aspect is triggered. I added an explicit controller method call in order to check:
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(ApiServiceApplication.class, args);
context.getBean(CustomerController.class).retrieveAll();
}
Then I fixed some typos in your code like the one mentioned in my previous comment.
Probably your problem was that you simply did not see the log output because you forgot the log configuration for your application package com.demo.apiservice:
logging:
level:
org:
springframework.web: DEBUG
hibernate: DEBUG
com:
atoz_develop:
mybatissample:
repository: TRACE
demo.apiservice: DEBUG
BTW, I also corrected your typo hibernat to hibernate, but that is unrelated to the problem at hand.
Then I see this in the log:
[ restartedMain] o.s.b.w.e.t.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
[ restartedMain] c.d.a.ApiServiceApplication : Started ApiServiceApplication in 5.101 seconds (JVM running for 6.117)
[ restartedMain] c.d.a.c.AopLoggingConfig : Controller : com.demo.apiservice.customer.CustomerController.######################### retrieveAll()
[ restartedMain] c.d.a.c.AopLoggingConfig : Controller : com.demo.apiservice.customer.CustomerController.######################### retrieveAll()
[ restartedMain] c.d.a.c.CustomerController : Start of CustomerController::retrieveAll method
Do you see the problem? You get duplicate logging, because the aspect is picked up once by component scan and instantiated one more time as a bean in your application configuration. So you need to remove this part from ApiServiceApplication:
#Bean
public AopLoggingConfig loggingAspect() {
return new AopLoggingConfig();
}
Now the duplicate logging is gone.
Next, maybe you want to simplify your aspect a bit and simply log joinPoint or joinPoint.getSignature(). You also want to make name and type local variables, because the static fields are not thread-safe. Instead, probably you want a static logger in the aspect.
#Component
#Aspect
public class AopLoggingConfig {
private static Logger logger = LoggerFactory.getLogger(AopLoggingConfig.class);
#Around("execution(* com.demo.apiservice.customer.*Controller.*(..))")
public Object logPrint(ProceedingJoinPoint joinPoint) throws Throwable {
String type = joinPoint.getSignature().getDeclaringTypeName();
String name = "";
if (type.contains("Controller")) {
name = "Controller \t: ";
}
else if (type.contains("Service")) {
name = "ServiceImpl \t: ";
}
else if (type.contains("DAO")) {
name = "DAO \t\t: ";
}
logger.debug(name + joinPoint.getSignature());
return joinPoint.proceed();
}
}
The log line becomes:
Controller : ResponseEntity com.demo.apiservice.customer.CustomerController.retrieveAll()
But actually, both the package name and the class name indicate that we are dealing with a controller, DAO or service. So why bother with the if-else stuff in the first place? Why make a simple matter complicated and the aspect slower? Besides, if you only want to log something and not influence the control flow, the method parameters or the return value, a simple #Before advice would do, the expensive #Around is unnecessary.
#Component
#Aspect
public class AopLoggingConfig {
private static Logger logger = LoggerFactory.getLogger(AopLoggingConfig.class);
#Before("execution(* com.demo.apiservice.customer.*Controller.*(..))")
public void logPrint(JoinPoint joinPoint) {
logger.debug(joinPoint.getSignature().toString());
}
}
The log line becomes:
ResponseEntity com.demo.apiservice.customer.CustomerController.retrieveAll()
Isn't that enough?
Or even simpler:
logger.debug(joinPoint.toString());
Log:
execution(ResponseEntity com.demo.apiservice.customer.CustomerController.retrieveAll())
Keep it simple!
The following should work:
package com.demo.apiservice.config;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
#Component
#Aspect
public class AopLoggingConfig {
Logger logger = LoggerFactory.getLogger(AopLoggingConfig.class);
static String name = "";
static String type = "";
#Pointcut("within(#org.springframework.web.bind.annotation.RestController *)")
public void controllerClassMethods() {}
#Around("controllerClassMethods()")
public Object logPrint(ProceedingJoinPoint joinPoint) throws Throwable {
type = joinPoint.getSignature().getDeclaringTypeName();
if (type.indexOf("Controller") -1) {
name = "Controller \t: ";
}
else if (type.indexOf("Service") -1) {
name = "ServiceImpl \t: ";
}
else if (type.indexOf("DAO") -1) {
name = "DAO \t\t: ";
}
logger.debug(name + type + ".######################### " + joinPoint.getSignature().getName() + "()");
return joinPoint.proceed();
}
}
This will match all the methods in all classes annotated with #RestController.

API (Spring Boot - SwaggerHub Generated) results with 404, despite being mapped properly

I was using SwaggerHub recently and tried to upgrade the spring-boot version (1.5.22.RELEASE to 2.3.3.RELEASE) in the generated Spring-Boot api, because of the access management (Keycloak).
Upgrading spring-boot version to 2.0.1.RELEASE does fix the issues using Keycloak, results in 404 error for every path of the api though. Summarily, no path can be accessed, despite being mapped according to the log.
Issues with the Versions:
1.5.22.RELEASE: API-Path can be accessed - Getting NoClassDefFoundError: WebServerFactoryCustomizer
2.0.0.RELEASE - 2.0.9.RELEASE: API-Paths are being mapped, but no access - No Error with Keycloak at startup.
2.1.0.RELEASE - 2.3.3.RELEASE: API-Paths don't get mapped - No Error with Keycloak at startup.
This is a section of the log using 2.0.1.RELEASE:
2020-10-05 10:46:47.012 INFO 25040 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/getIcnByNumber],methods=[GET],produces=[application/json]}" onto public org.springframework.http.ResponseEntity<java.util.List<io.swagger.model.ModelConfiguration>> io.swagger.api.GetIcnByNumberApiController.getIcnByNumber()
2020-10-05 10:46:47.015 INFO 25040 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/getMyConfigurations],methods=[GET],produces=[application/json]}" onto public org.springframework.http.ResponseEntity<java.util.List<io.swagger.model.ModelConfiguration>> io.swagger.api.GetMyConfigurationsApiController.callConfiguration()
2020-10-05 10:46:47.017 INFO 25040 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/getMyProjects],methods=[GET],produces=[application/json]}" onto public org.springframework.http.ResponseEntity<java.util.List<io.swagger.model.ProjectModel>> io.swagger.api.GetMyProjectsApiController.getMyProjectsGet()
2020-10-05 10:46:47.020 INFO 25040 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/getProjectConfiguration/{projectId}],methods=[GET],produces=[application/json]}" onto public org.springframework.http.ResponseEntity<io.swagger.model.ProjectConfiguration> io.swagger.api.GetProjectConfigurationApiController.getProjectConfigurationProjectIdGet(java.lang.String)
2020-10-05 10:46:47.021 INFO 25040 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/getRequestOverview],methods=[GET],produces=[application/json]}" onto public org.springframework.http.ResponseEntity<java.util.List<io.swagger.model.RequestOverview>> io.swagger.api.GetRequestOverviewApiController.getRequestOverview()
Code-Example:
/getMyConfigurations - Interface:
/**
* NOTE: This class is auto generated by the swagger code generator program (3.0.21).
* https://github.com/swagger-api/swagger-codegen
* Do not edit the class manually.
*/
package io.swagger.api;
import io.swagger.model.ModelConfiguration;
import io.swagger.annotations.*;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.bind.annotation.CookieValue;
import javax.validation.Valid;
import javax.validation.constraints.*;
import java.util.List;
import java.util.Map;
#javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2020-09-14T09:55:45.552Z[GMT]")
#Api(value = "getMyConfigurations", description = "the getMyConfigurations API")
public interface GetMyConfigurationsApi {
#ApiOperation(value = "searches inventory", nickname = "callConfiguration", notes = "By passing in the appropriate options, you can search for available inventory in the system ", response = ModelConfiguration.class, responseContainer = "List", tags={ "developers", })
#ApiResponses(value = {
#ApiResponse(code = 200, message = "search results matching criteria", response = ModelConfiguration.class, responseContainer = "List"),
#ApiResponse(code = 400, message = "bad input parameter") })
#RequestMapping(value = "/getMyConfigurations",
produces = { "application/json" },
method = RequestMethod.GET)
ResponseEntity<List<ModelConfiguration>> callConfiguration();
}
/getMyConfigurations - Controller:
package io.swagger.api;
import io.swagger.model.ModelConfiguration;
import io.swagger.model.Originator;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.swagger.annotations.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.CookieValue;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.multipart.MultipartFile;
import javax.validation.constraints.*;
import javax.validation.Valid;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
#javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2020-08-28T09:14:46.542Z[GMT]")
#Controller
public class GetMyConfigurationsApiController implements GetMyConfigurationsApi {
private static final Logger log = LoggerFactory.getLogger(GetMyConfigurationsApiController.class);
private final ObjectMapper objectMapper;
private final HttpServletRequest request;
#org.springframework.beans.factory.annotation.Autowired
public GetMyConfigurationsApiController(ObjectMapper objectMapper, HttpServletRequest request) {
this.objectMapper = objectMapper;
this.request = request;
}
public ResponseEntity<List<ModelConfiguration>> callConfiguration() {
ArrayList<ModelConfiguration> mcList = new ArrayList<>();
return new ResponseEntity<List<ModelConfiguration>>(mcList,HttpStatus.OK);
}
}
EDIT (05.10.2020): Styling for better overview.
Tried to access the path on localhost:8080/TEST/API/1.0.0/getMyConfigurations which was functioning with version 1.5.33.RELEASE.
Seems like the server.contextPath attribute on application.properties is ignored in versions higher than 2.x.x.RELEASE. So it turned out that the path has to be called without server.contextPath (localhost:8080/getMyConfigurations).
Edit:
The property was moved from server.contextPath (or server.context-path) to server.servlet.context-path as described here
#martinspielmann thank you for the comment.

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

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

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() {}

Spring cannot serve end point

I have a simple Spring back-end. It has a folder that contains controllers.
package com.movieseat.controllers;
// Java imports
import java.util.List;
// Spring imports
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
// Project imports
import com.movieseat.models.Movie;
import com.movieseat.services.MovieService;
#RestController
#RequestMapping("/api/movies")
public class MovieController {
#Autowired
private MovieService movieService;
#RequestMapping(value = "/allMovies", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public List<Movie> getAllMovies() {
return movieService.getAllmovies();
}
}
In my Angular service I have a getAll() method:
public getAll<T>(): Observable<T[]> {
return this.http.get<T[]>('/api/movies/allMovies');
}
When I run the application I get a:
GET http://localhost:8090/api/movies/allMovies 404 ()
I have the server running on port 8090.
The following structure is used:
com
movieseat
Application.java
controllers
MovieController.java
models
MovieModel.java
repositories
MovieRepository.java
services
impl
MovieServiceImpl.java
MovieService.java
See if your controller class is picked up by spring scanning and performs mapping correctly. For example - If you are using Spring Boot, put a #SpringBootApplication on your main class that runs the app. The best way to know if your endpoint is scanned is to look for it when spring launches (in the log). You should look for something like
2017-09-17 14:45:49.522 INFO 2873 --- [main] RequestMappingHandlerMapping : Mapped "{[/allMovies],methods=[GET]}" onto public java.lang.String com.movieseat.controllers.MovieController.getAllMovies...

Resources