NPE when starting actuator on distinct port [duplicate] - spring-boot

This question already has an answer here:
Bean 'x' of type [TYPE] is not eligible for getting processed by all BeanPostProcessors
(1 answer)
Closed 2 years ago.
upon configuring actuator to start up on a distinct port, the app fails with the following stacktrace:
java.lang.NullPointerException: null
at org.springframework.web.filter.GenericFilterBean.init(GenericFilterBean.java:241) ~[spring-web-5.2.8.RELEASE.jar:5.2.8.RELEASE]
at org.apache.catalina.core.ApplicationFilterConfig.initFilter(ApplicationFilterConfig.java:270) ~[tomcat-embed-core-9.0.37.jar:9.0.37]
at org.apache.catalina.core.ApplicationFilterConfig.<init>(ApplicationFilterConfig.java:106) ~[tomcat-embed-core-9.0.37.jar:9.0.37]
at org.apache.catalina.core.StandardContext.filterStart(StandardContext.java:4528) [tomcat-embed-core-9.0.37.jar:9.0.37]
aop issues the following info warning:
2020-08-16 10:01:11.240 INFO 83848 --- [ main] o.s.aop.framework.CglibAopProxy : Unable to proxy interface-implementing method [public final void org.springframework.web.filter.GenericFilterBean.init(javax.servlet.FilterConfig) throws javax.servlet.ServletException] because it is marked as final: Consider using interface-based JDK proxies instead!
here are my gradle dependencies:
plugins {
id 'org.springframework.boot' version '2.3.3.RELEASE'
...
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-validation'
implementation 'org.springframework.boot:spring-boot-starter-actuator'
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.security.oauth.boot:spring-security-oauth2-autoconfigure:2.1.5.RELEASE'
implementation 'org.springframework.security:spring-security-jwt:1.0.10.RELEASE'
we do have one #Aspect annotated class:
...
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.security.web.firewall.RequestRejectedException;
import org.springframework.stereotype.Component;
...
#Aspect
#Component
#Slf4j
public class MyFilter {
#Around("execution(public void org.springframework.security.web.FilterChainProxy.doFilter(..))")
public void handleRequestRejectedException (ProceedingJoinPoint pjp) throws Throwable {
try {
pjp.proceed();
} catch (RequestRejectedException exception) {
...
}
}
}
i have found a few issues discussing this problem, having something to do with aop, but i have as of yet failed to find a solution.
any/all help appreciated.
james

After the OP has updated the question with some sample code, I see that the problem is not a pointcut which is too generic, capturing too many classes like in the other question I linked to in my comment but something else:
James, you are targeting method FilterChainProxy.doFilter(..), i.e. directly a Spring framework class. The problem is, as you can also see in the error message you get in your log:
o.s.aop.framework.CglibAopProxy:
Unable to proxy interface-implementing method [
public final void org.springframework.web.filter.GenericFilterBean.init(javax.servlet.FilterConfig)
throws javax.servlet.ServletException
]
because it is marked as final:
Consider using interface-based JDK proxies instead!
The problem is that the target class is derived from GenericFilterBean where the init(..) method is marked as final. CGLIB works via subclassing and overriding non-private methods, but a final method cannot be overridden. Thus, Spring AOP complains.
The error message also hints you towards a solution for the problem: Instead of using a CGLIB proxy for the target, you could use a JDK proxy which works by implementing interfaces. Luckily, doFilter is an interface method, more precisely an implementation of JavaEE method Filter.doFilter(..).
Now the next problem is that you are not using plain vanilla Spring but Spring Boot, which is known for having a combination of presets which seem to make it impossible to switch to JDK proxies, even though in plain Spring that is even the default. But Boot wants to be too user-friendly and smart, leaving you in this trap. I do not remember the Spring Boot ticket dealing with this problem, but last time I checked it was unresolved.
One way to avoid the whole situation is to use full AspectJ instead of just Spring AOP for your aspect, thus freeing you of the proxy-based "AOP lite" approach and enabling you to directly modify the target class or to alternatively weave your aspect not into the target class but into all calling classes instead via call() pointcut (not supported by Spring AOP).
Another solution would be to hook into another, less problematic target class/method with your aspect, not directly into a Spring framework class with final methods.
P.S.: I am not a Spring user, I just happen to know a few details from answering AOP-related questions here. Actually, I am surprised that CGLIB proxying as implemented by Spring is not more lenient with regard to final methods, just ignoring them and logging a warning instead of trying to override them and producing an error. Maybe there is some configuration option for that, but I leave it up to the Spring folks to answer that question, I have no clue here.
I cannot answer more precisely because I would need to see a full MCVE, ideally a Maven or Gradle project on GitHub, in order to further analyse your situation. I just wanted to explain some basics here.

Related

Spring AOP pointcut execution not working

I'm working on a Spring Boot project that uses Spring Cloud (io.awspring.cloud:spring-cloud-aws-dependencies:2.4.2) to produce and consume AWS SQS messages. I have several message producers and several message consumers, and all is working fine from that perspective.
I now have a cross cutting concern where I need to set a header on all messages being produced/sent; and to read that header on all messages being consumed (correlationId), and AOP seems like a good fit.
My aspect for handling (receiving) a message works fine:
#Before("execution(* org.springframework.messaging.handler.invocation.AbstractMethodMessageHandler.handleMessage(..))")
fun beforeHandleMessage(joinPoint: JoinPoint) {
The class and method that it is targeting is:
package org.springframework.messaging.handler.invocation;
...
public abstract class AbstractMethodMessageHandler<T>
implements MessageHandler, ApplicationContextAware, InitializingBean {
...
#Override
public void handleMessage(Message<?> message) throws MessagingException {
As mentioned, this works great.
However, I can't get my pointcut for sending a message working. This is my aspect:
#Before("execution(* org.springframework.messaging.support.AbstractMessageChannel.send(..))")
// #Before("execution(* io.awspring.cloud.messaging.core.QueueMessageChannel.send(..))")
fun beforeSendMessage(joinPoint: JoinPoint) {
And the class and method that I'm trying to target is this:
package org.springframework.messaging.support;
...
public abstract class AbstractMessageChannel implements MessageChannel, InterceptableChannel, BeanNameAware {
...
#Override
public final boolean send(Message<?> message) {
But it doesn't seem to work. I've also tried writing the pointcut to target the concrete implementation class (as commented out above), but that also does nothing.
I can't see what the difference is between my working pointcut for beforeHandleMessage and beforeSendMethod, other than the pointcut for beforeSendMethod is targeting a final method. Is that relevant?
Any pointers to get this working would be very much appreciated;
Thanks
Spring AOP uses dynamic proxies, i.e. it works by subclassing (CGLIB proxy) or by implementing interfaces (JDK proxies). In your case, you are targeting a class method rather than an interface method. The class method is final, which explains why it cannot work that way, because you cannot override a final method in a CGLIB proxy. What you should do instead is to
target the interface method MessageChannel.send(Message) and
make sure to use JDK proxies, i.e. not the "proxy target class" (CGLIB) mode. In Spring core, JDK proxy mode is the default, in Spring Boot CGLIB mode. So in Boot, you need to manually reconfigure the framework to permit for JDK proxies, which is only possible there via config file, not via annotations (they come too late in the bootstrapping process for Boot).
More specifically, you need this in src/main/resources/application.properties for Spring Boot:
# This works, now we can create JDK interface proxies. The seemingly equivalent alternative
# #EnableAspectJAutoProxy(proxyTargetClass = false)
# where 'false' is even the default, does *not* work in Spring Boot.
spring.aop.proxy-target-class=false
I found the answer from this other SO answer: Spring AOP ignores some methods of Hessian Service
I know that Spring AOP won't intercept local method calls. I.e. the proxy which is applied doesn't intercept the calls if the same object calls its own method, even if it matches the pointcut expression.
The problem was that the send method I was targeting was called by a number of other methods in the class.
Looking at the call stack I found a different method that was the first method called in the class. Changing the pointcut to target that method has worked.

Spring #Transactional - synchronize via AspectJ

I am trying to synchronize declarative transactions (i.e. methods annotated with #Transactional) using AspectJ like so:
...
import org.aspectj.lang.annotation.Aspect;
...
#Component
#Aspect
public class TransactionMonitor extends TransactionSynchronizationAdapter {
#Before("execution(#org.springframework.transaction.annotation.Transactional * *.*(..))")
private void registerTransactionSynchronizationOnAnnotation(JoinPoint joinPoint) {
TransactionSynchronizationManager.registerSynchronization(this);
}
}
This currently fails with java.lang.IllegalStateException: Transaction synchronization is not active which indicates that the synchronization is not run inside the transaction execution, but before. I want to ensure that this is the other way round, of course.
I found this answer, however #Order(Ordered.LOWEST_PRECEDENCE) had no effect, and
#DeclarePrecedence(
"org.springframework.transaction.aspectj.AnnotationTransactionAspect, xxx.xxx.TransactionMonitor, *"
)
led to this during startup:
java.lang.IllegalArgumentException: DeclarePrecedence not presently supported in Spring AOP
I have the feeling this is AOP and AspectJ not being happy with each other, but I am not sure. I am thankful for any ideas.
EDIT: I have to use #EnableTransactionManagement(proxyTargetClass = true), can this be related to the issue?
For #DeclarePrecedence you need to switch to native AspectJ. Spring AOP is just "AOP lite" and technologically has little in common with AspectJ other than its syntax which is basically an AspectJ subset. The Spring manual describes how to use native AspectJ in Spring via LTW (load-time weaving). Precedence declaration for Spring components rather works using #Order, BTW.
I am not a Spring user at all, but as for declarative transaction management, it already knows proxy-based Spring AOP versus native AspectJ mode, see EnableTransactionManagement.mode and the enum constants in AdviceMode. Besides, EnableTransactionManagement also has an order property. Reading Javadoc and the Spring manual helps, I guess.

Spring boot aspectj gradle compile time weaving issue

I have a spring book application, which works fine. I would like to send email notifications to me if there are exceptions thrown from my application. I think aspectj is a good fit.
First, I tried to use Spring AOP runtime weaving, which works OK for public methods. However, I would like to get notified on private methods as well, and I have scheduled tasks. According to Spring AOP doc, runtime weaving won't work for scheduled tasks and private methods. Thus I have decided to use aspectj compile time weaving in my boot application.
I found the official aspectj gradle plugin here:
https://plugins.gradle.org/plugin/at.jku.isse.gradient-gradle
My boot application has this dependency:
compile group: 'org.springframework.boot', name: 'spring-boot-configuration-processor', version:'1.5.14.RELEASE'
My project compiles fine if I use default compiler. But if I use AspectJ compiler, it always complains:
[ant:iajc] warning Field value processing of #ConfigurationProperty meta-data is not supported
[ant:iajc] warning Hibernate JPA 2 Static-Metamodel Generator 4.3.11.Final
[ant:iajc] error at (no source information available)
D:\work\proj\build\classes\java\main\com\abc\dao\entity\Channel_.java:0::0 Internal compiler error: java.lang.Exception: java.lang.NoClassDefFoundError: org/springframework/boot/configurationprocessor/metadata/JsonMarshaller at org.aspectj.org.eclipse.jdt.internal.compiler.apt.dispatch.RoundDispatcher.handleProcessor(RoundDispatcher.java:169)
If I remove that dependency, aspectj compiles ok, I get the jar file. But then when I run my code, I got this:
Caused by: org.springframework.aop.framework.AopConfigException: Advice must be declared inside an aspect type: Offending method 'public void com.proj.aop.AspectConfiguration.afterThrowing(org.aspectj.lang.JoinPoint,java.lang.Throwable)' in class [com.proj.aop.AspectConfiguration]
And this is my Advice class:
package com.proj.aop;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.context.annotation.Configuration;
#Aspect
#Configuration
public class AspectConfiguration {
#AfterThrowing (pointcut="execution(* org.hibernate..*.*(..)) || execution(* com.proj..*.*(..))", throwing="excep")
public void afterThrowing(JoinPoint joinPoint, Throwable excep){
System.out.println("inafterthrowing");
}
}
and my appconfig has annotation #EnableAspectJAutoProxy added.
If I replace #Configuration with #Component in my Advice class, I can run my application but the afterthrowing method is not called. Same if I remove #Configuration.
So my questions are:
Why I get the java.lang.NoClassDefFoundError: org/springframework/boot/configurationprocessor/metadata/JsonMarshaller if I have spring-boot-configuration-processor as dependency when compiled by AspectJ?
What is the correct way to use AspectJ in spring boot application and build with gradle? (use #Configuration or #Component? and why my afterthrowing is not called if I use #Component or, why I get exception if I use #Configuration?)
Thanks

NullPointerException in AbstractRememberMeService after upgrading to Spring Boot 1.4

After upgrading from Spring Boot 1.3.8 to Spring Boot 1.4.4 I get a NullPointerException in AbstractRememberMeServices because the logger isn't instantiated successfully.
A NullPointerException is thrown on this Line.
I write a custom RememberMeService which extends AbstractRememberMeServices. This service is registered as a bean as you can see in the following code snipped:
#Bean
RememberMeServices rememberMeServices(UserDetailsService userDetailsService, UserRepository userRepository, RememberMeTokenRepository rememberMeTokenRepository, RandomService randomService) {
String key = env.getProperty("security.rememberme.key");
RememberMeService rememberMeService = new RememberMeService(key, userDetailsService, userRepository, rememberMeTokenRepository, randomService);
rememberMeService.setAlwaysRemember(true);
return rememberMeService;
}
This error seems related to this SO question. Additionally JHipster has a similar issue.
Does anyone know why the logger isn't instantiated successfully?
I know this is an old question but I just encountered the same thing in a library's custom RememberMeServices impl. You may find an indication of the problem mentioned in the Spring startup logs. For instance:
2018-04-11 07:32:07.311 INFO 1 --- [ost-startStop-1] o.s.a.f.CglibAopProxy : Final method [public final org.springframework.security.core.Authentication org.springframework.security.web.authentication.rememberme.AbstractRememberMeServices.autoLogin(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)] cannot get proxied via CGLIB: Calls to this method will NOT be routed to the target instance and might lead to NPEs against uninitialized fields in the proxy instance.
In this case, the subclass must have some feature that requires proxying by CGLIB, such as #Transactional on a method. If no such features were present, CGLIB wouldn't be necessary and the subclass would behave as expected.
Also got this error. When I debug, I find out the properties of AbstractRememberMeServices almost all null. Then I think, maybe the inject of spring not work. So I changed my code to this:
.rememberMe()
.rememberMeServices(new MyRememberMeServices(env, userDetailsService, userRepo, tokenRepo))
.and();
It works. But I don't understand why...

Am I allowed to declare a lifecycle interceptor on an interceptor?

I have my business bean defined thus:
#Local
#Interceptors(BusinessInterceptor.class})
public class MyBean implements SomeBean { ... }
And then I want my BusinessInterceptor to be configured with Spring's SpringBeanAutowiringInterceptor:
#Interceptors(SpringBeanAutowiringInterceptor.class)
public class BusinessInterceptor {
#Autowired
private SomeSpringBean someSpringBean;
}
Is this allowed/legal? I'm getting errors (NPEs, mostly) suggesting that the fields in BusinessInterceptor have not been initialized properly.
I doubt this can work. If I understand well your scenario, you have basically two DI containers, one is Spring and the other the app. server itself. Each one manages different elements. The BusinessInterceptor is created by the app. server which is unaware of Spring -- the #Autowired bean is then not set.
( Note that Spring and EJB3 have become quite similar now. You can have the same functionalities as EJB with Spring. Spring has indeed declarative transactions, dependency injection and AOP facilities similar to EJB3 interceptors (these are the main managed features). On the other hand, EJB3 is now so lightweight that there isn't really a compelling reason to use Spring with with EJB3. See Future of enterprise Java: full stack Spring or full stack Java EE. But this does not answer the question, and is just a little digression of mine :)

Resources