Can't get Spring AOP to log/print in my application - spring

Like the title says, here are my classes (this is just for testing if I can AOP to work):
ApplicationContextConfiguration.kt
package com.fdev.jobby
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
#ComponentScan
#EnableAspectJAutoProxy
class ApplicationContextConfiguration {
#Bean
fun dataSource():DataSource{
return DataSource()
}
}
DataSource.kt
package com.fdev.jobby
open class DataSource {
fun getDataFromDB(): String{
// fetching Data
return "data was loaded"
}
fun insertDataToDB(){
// inserting Data
}
}
LoggingDataSource.kt
package com.fdev.jobby
import mu.KotlinLogging
import org.aspectj.lang.annotation.AfterReturning
import org.aspectj.lang.annotation.AfterThrowing
import org.aspectj.lang.annotation.Aspect
import org.aspectj.lang.annotation.Before
import org.aspectj.lang.annotation.Pointcut
import org.springframework.stereotype.Component
#Aspect
#Component
class LoggingDataSource {
private val logger = KotlinLogging.logger {}
#Pointcut("execution(* com.fdev.jobby.DataSource.*(..))")
fun getAllMethods(){}
#Before("getAllMethods()")
fun startOfAccessToDB(){
logger.error("Starting access to DB")
}
#AfterReturning("getAllMethods()")
fun endOfAccessToDBSuccess(){
println("Successful access to DB..")
}
#AfterThrowing("getAllMethods()")
fun endOfAccessToDBFailure(){
println("Failed access to DB..")
}
}
AOPController.kt
package com.fdev.jobby
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController
#RestController
#RequestMapping("aop")
class AOPController(#Autowired val dataSource: DataSource) {
#GetMapping("testing")
fun aopTesting(): String{
val data = dataSource.getDataFromDB()
return data
}
}
So when I call localhost:8080/aop/testing it shows the string "data was loaded" but it wont log or print my advices. What am I doing wrong? I have been reading here but the docs seem very unintuitive and not helpful at all. Please help :(
Edit: my gradle dependencies look like this
dependencies {
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
implementation("org.jetbrains.kotlin:kotlin-reflect")
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
implementation("org.springframework.boot:spring-boot-starter")
implementation("org.springframework.boot:spring-boot-starter-aop")
implementation("io.github.microutils:kotlin-logging-jvm:2.1.20")
testImplementation("org.springframework.boot:spring-boot-starter-test")
}

Related

#RestControllerAdvice not scanned

i have looked at 5 tutorials; more than 10 stackoverflow or similar answers but i still haven't resolved that (apparently common) problem.
All i want to achieve is to set a custom JSON upon when exception are thrown on my API. But the Controller advice is never even instantiated (watch breakpoint never crossed.)
Here are the relevant files:
Main class:
package com.bancarelvalentin.plaxdmin
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
#SpringBootApplication(scanBasePackages = ["com.bancarelvalentin.*"])
class Main
fun main(args: Array<String>) {
runApplication<Main>(*args)
}
Sample controller:
package com.bancarelvalentin.plaxdmin.controller
import com.bancarelvalentin.plaxdmin.playground.CustomException
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController
#RestController
#RequestMapping("/")
class DummyCtrl : PlController() {
#GetMapping
fun throwError(): ResponseEntity<Any> {
throw CustomException()
}
}
Error handler:
package com.bancarelvalentin.plaxdmin.playground;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.ExceptionHandler;ExceptionHandler
import org.springframework.web.bind.annotation.RestControllerAdvice;RestControllerAdvice
import org.springframework.web.servlet.configjava.annotationlang.EnableWebMvc;Exception
#RestControllerAdvice
public class GlobalExceptionHandler {
#ExceptionHandler
public Exceptionfun handleException(Exception ce: Exception): Exception {
return ce;
}
}
application.properties
spring.datasource.url=jdbc:mysql://localhost:3306/plaxdmin
spring.datasource.username=root
spring.datasource.password=root
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
spring.jpa.hibernate.ddl-auto=update
Here is what i tried:
Adding other anotation to the main and/or the ErrorHandler class (#EnableWebMvc, #Component, some others i don't remember)
Putting the 3 above files in the same package
turning in and off the white label page
add a scanBasePackages attributes in my main class annotaation

Can I invoke a local bean into a ear file from a Javax-WS into a war file- apache-tomee-plus-1.7.4

I am using Eclipse Mars 2, maven 3.3.9 and apache-tomee-plus-1.7.4.
I have 2 projects (A and B)
Project A is a Web Service compiled like a WAR using maven 3.3.9 and deployed into TOMEE_HOME/webapps
Project B is an EJB module compiled like a EAR using maven 3.3.9 and deployed into TOMEE_HOME/apps (this project include other project with ejb clasess and compiled like a jar file)
These projects do not depend on each other in the pom.xml but I need to lookup an EJB in project A from project B.
---------- Project B Implementation -----------
Local Bean Interface in project B:
package co.edu.uniquindio.model.ejb.interfaces;
import javax.ejb.Local;
import org.springframework.context.support.ClassPathXmlApplicationContext;
#Local
public interface IReporte {
public Object generate1();
public Object generate2();
public void setContext(ClassPathXmlApplicationContext context);
}
Implement local bean interface in project B:
package co.edu.uniquindio.model.ejb;
import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import co.edu.uniquindio.model.ejb.interfaces.IReporte;
#Stateless
#EJB(beanInterface = IReporte.class, beanName="ReporteEJB", name="IReporte")
public class ReporteEJB implements IReporte{
private ClassPathXmlApplicationContext context;
#Override
#TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
public Object generate1(){
// do somthing amazing
}
#Override
#TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
public Object generate2(){
// do somthing amazing
}
#Override
public void setContext(ClassPathXmlApplicationContext context) {
this.context = context;
}
}
---------- Project A Implementation -----------
The way that I develop lookup is:
package co.swatit.rest.services;
import java.util.Properties;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import co.edu.uniquindio.model.ejb.interfaces.IReporte;
#Path("/ReporteWS")
public class ReporteWS {
#POST
#Path("generate1and2")
#Produces(MediaType.APPLICATION_JSON)
#Consumes({ MediaType.APPLICATION_JSON} )
public Response generate1and2() {
Properties props = new Properties();
props.put(Context.INITIAL_CONTEXT_FACTORY, "org.apache.openejb.client.LocalInitialContextFactory");
try {
Context ctx = new InitialContext(props);
// I do not know if use IReporte or ReporteEJB to cast. and I do not know how to import it.
IReporte ejbLocal = (IReporte) ctx.lookup("java:global/Sac-report-ear-1.0.0/co.swatit-Sac-report-ejb-1.0.0/ReporteEJB");
ejbLocal.generate1();
ejbLocal.generate2();
} catch (Exception exception) {
exception.printStackTrace()
}
return Response.status(Status.OK)
.entity(ejbLocal).build();
}
}
I do not know if it is possible import the local bean in project A to lookup that bean:
import co.edu.uniquindio.model.ejb.interfaces.IReporte
I do not know if use IReporte or ReporteEJB to cast, and I do not know how to import it.
Thank you for your help.

Kotlin Can't create #Autowired field in Class that are annotated with #Configuration #EnableWebMvc

Autowired field is null when initializing the project:
package com.lynas.config
import org.springframework.stereotype.Component
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse
#Component
open class InterceptorConfig : HandlerInterceptorAdapter() {
override fun preHandle(request: HttpServletRequest, response: HttpServletResponse, handler: Any?): Boolean {
return true
}
}
package com.lynas.config
import org.springframework.beans.factory.annotation.Autowired
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.InterceptorRegistry
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter
#Configuration
#EnableWebMvc
#ComponentScan("com.lynas")
open class WebConfig() : WebMvcConfigurerAdapter() {
// this field show null
#Autowired
lateinit var interceptorConfig: InterceptorConfig
override fun addInterceptors(registry: InterceptorRegistry) {
registry.addInterceptor(interceptorConfig)
}
}
lateinit var interceptorConfig: InterceptorConfig is null when I run the application. How to fix this?
full code https://github.com/lynas/kotlinSpringBug
try #field:Autowired lateinit var interceptorConfig or #set:Autowired which will tell kotlin compiler to put annotations explicitly on field/setter. by default it places them on "property" which is kotlin-only construct and Java may have problems accessing it. refer to kotlin docs here

Unable to inject dependency in Junit test

Having some trouble injecting a dependency in one of my JUnit test classes.
I believe the TestApplication is not package scanning or is not being loaded.
Code below:
package com.mitto.repositories;
import static org.junit.Assert.*;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
import org.springframework.test.context.transaction.TransactionalTestExecutionListener;
import com.github.springtestdbunit.DbUnitTestExecutionListener;
import com.github.springtestdbunit.annotation.DatabaseSetup;
import com.mitto.MittoApplicationTests;
import com.mitto.domain.User;
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration( classes= { MittoApplicationTests.class } )
#TestExecutionListeners({DependencyInjectionTestExecutionListener.class,
TransactionalTestExecutionListener.class,
DbUnitTestExecutionListener.class})
#DatabaseSetup("UserRepositoryTest.xml")
public class UserRepositoryTest {
#Autowired
UserRepository repository;
private static final long FACEBOOK_ID = 1234567;
#Test
public void getUserById() {
User user = repository.findOne(1L);
assertNotNull(user);
assertEquals( user.getFacebookId(), FACEBOOK_ID );
}
}
MittoApplicationTests.java
package com.mitto;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
#RunWith(SpringRunner.class)
#SpringBootTest
public class MittoApplicationTests {
#Test
public void contextLoads() {
}
}
UserRepository.java
package com.mitto.repositories;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.stereotype.Repository;
import com.mitto.domain.User;
#Repository
public interface UserRepository extends PagingAndSortingRepository<User, Long>{
User findByFacebookId( long facebookId );
User findByAuthToken( String token );
}
I can't see anything wrong with this.
Sometimes, a working example is better than fixes.
Here is a working example:
First, in your configuration class
#SpringBootApplication
#ComponentScan(value = "com.mitto")
#EnableJpaRepositories(value = "com.mitto")
#EntityScan(basePackages = {"com.mitto.domain"}, basePackageClasses = {Jsr310JpaConverters.class})
public class MittoApplicationTests {
}
Second, in your test class
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest(classes = MittoApplicationTests.class) // replace the #ContextConfiguration with #SpringBootTest
// rest of of your annotations ...
public class UserRepositoryTest {
#Autowired
UserRepository repository;
// your test cases
}
A Spring Boot application is just a Spring ApplicationContext, so nothing very special has to be done to test it beyond what you would normally do with a vanilla Spring context. One thing to watch out for though is that the external properties, logging and other features of Spring Boot are only installed in the context by default if you use SpringApplication to create it.
Spring Boot provides a #SpringBootTest annotation which can be used as an alternative to the standard spring-test #ContextConfiguration annotation when you need Spring Boot features. The annotation works by creating the ApplicationContext used in your tests via SpringApplication.
Please read the documentation for more details:
SpringBootTest annotation
boot-features-testing

embedded tomcat valve spring boot

I'm trying to configure the LogbackValve for getting access logs in case my Spring Boot based web application is running from embedded Tomcat. Following is the code for configuration:
import javax.servlet.Servlet;
import org.apache.catalina.startup.Tomcat;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import ch.qos.logback.access.tomcat.LogbackValve;
#Configuration
public class EmbeddedTomcatConfigurator {
#Bean
#ConditionalOnClass({ Servlet.class, Tomcat.class })
#ConditionalOnBean(value = LogbackValve.class)
public TomcatEmbeddedServletContainerFactory tomcatEmbeddedServletContainerFactory(LogbackValve logbackValve) {
TomcatEmbeddedServletContainerFactory factory = new TomcatEmbeddedServletContainerFactory();
factory.addContextValves(logbackValve);
return factory;
}
#Bean
#ConditionalOnProperty(name = "embedded.tomcat.logback.access.config.path")
public LogbackValve logbackValve(#Value("${embedded.tomcat.logback.access.config.path:}") String fileName) {
LogbackValve logbackValve = new LogbackValve();
logbackValve.setFilename(fileName);
return logbackValve;
}
}
However, everytime I start the application using "mvn spring-boot:run" in debug mode, I see logs saying, "LogbackValve not found" when trying to create instance of "tomcatEmbeddedServletContainerFactory" bean. However, another log statement indicates creation of this bean. Due to this, it always initializes the bean defined in the auto-configuration class "org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration".
For now, I've modified my class as :
import javax.servlet.Servlet;
import org.apache.catalina.startup.Tomcat;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import ch.qos.logback.access.tomcat.LogbackValve;
#Configuration
public class EmbeddedTomcatConfigurator {
#Bean
#ConditionalOnClass({ Servlet.class, Tomcat.class })
#ConditionalOnProperty(name = "embedded.tomcat.logback.access.config.path")
public TomcatEmbeddedServletContainerFactory tomcatEmbeddedServletContainerFactory(#Value("${embedded.tomcat.logback.access.config.path:}") String logbackAccessPath) {
TomcatEmbeddedServletContainerFactory factory = new TomcatEmbeddedServletContainerFactory();
factory.addContextValves(getLogbackValve(logbackAccessPath));
return factory;
}
private LogbackValve getLogbackValve(String fileName) {
LogbackValve logbackValve = new LogbackValve();
logbackValve.setFilename(fileName);
return logbackValve;
}
}
I've already asked this question on Git and it has been resolved. But, here, the point I'm trying to bring up is, why the #ConditionalOnBean(value = LogbackValve.class) isn't detecting the bean, which has been defined as well.

Resources