Hi all,
we have a legacy webapp running with Spring 6.1.6, which makes use of spring-aop
for validation purpose.
The @Aspect
looks like
package org.example.server.validation;
import org.example.server.domain.AbstractEntity;
import org.example.shared.exception.validation.ValidationException;
import org.example.shared.exception.validation.ValidationException.ValidationError;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.Path;
import jakarta.validation.Path.Node;
import jakarta.validation.ValidatorFactory;
import jakarta.validation.groups.Default;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.Iterator;
import java.util.Set;
@Aspect
public class ValidationAspect
{
private static final Logger logger = LoggerFactory.getLogger(ValidationAspect.class);
private static final String PROPERTY_PATH_SEPERATOR = ".";
@Autowired
private ValidatorFactory validatorFactory;
@Before(value = "execution(* org.example.server..*.*(@jakarta.validation.Valid (org.example.server.domain.AbstractEntity+))) && args(entity)", argNames = "entity")
public void validateDefaultGroup(JoinPoint jp, AbstractEntity entity)
{
validate(entity, Default.class);
}
@Before(value = "execution(* org.example.server..*.*(@jakarta.validation.Valid @Groups (org.example.server.domain.AbstractEntity+))) && args(entity)", argNames = "entity")
public void validateGroups(JoinPoint jp, AbstractEntity entity)
{
Class<?>[] groups = null;
if (jp.getArgs().length == 1 && jp.getSignature() instanceof MethodSignature)
{
final MethodSignature ms = (MethodSignature) jp.getSignature();
if (ms.getMethod().getParameterAnnotations()[0].length == 2
&& ms.getMethod().getParameterAnnotations()[0][1] instanceof Groups)
groups = ((Groups) ms.getMethod().getParameterAnnotations()[0][1]).value();
}
if (groups != null)
validate(entity, groups);
else
{
logger.error("groups: null");
throw new IllegalStateException("groups: null");
}
}
private void validate(AbstractEntity entity, Class<?>... groups)
{
//some code
}
}
and an XML-based configuration for it like
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<aop:aspectj-autoproxy />
<bean class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"
id="validatorFactory" />
<bean class="org.example.server.validation.ValidationAspect" id="validationAspect" />
</beans>
This setup used to work fine with 6.1.6
.
Upgrading to 6.1.7
results in
Caused by: java.lang.IllegalArgumentException: error Type referred to is not an annotation type: Configurable
at org.aspectj.weaver.tools.PointcutParser.parsePointcutExpression(PointcutParser.java:319)
at org.springframework.aop.aspectj.AspectJExpressionPointcut.buildPointcutExpression(AspectJExpressionPointcut.java:228)
at org.springframework.aop.aspectj.AspectJExpressionPointcut.obtainPointcutExpression(AspectJExpressionPointcut.java:199)
at org.springframework.aop.aspectj.AspectJExpressionPointcut.matches(AspectJExpressionPointcut.java:275)
at org.springframework.aop.support.AopUtils.canApply(AopUtils.java:236)
at org.springframework.aop.support.AopUtils.canApply(AopUtils.java:298)
at org.springframework.aop.support.AopUtils.findAdvisorsThatCanApply(AopUtils.java:330)
at org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.findAdvisorsThatCanApply(AbstractAdvisorAutoProxyCreator.java:128)
at org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.findEligibleAdvisors(AbstractAdvisorAutoProxyCreator.java:97)
at org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.getAdvicesAndAdvisorsForBean(AbstractAdvisorAutoProxyCreator.java:78)
at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.wrapIfNecessary(AbstractAutoProxyCreator.java:368)
at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.postProcessAfterInitialization(AbstractAutoProxyCreator.java:320)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsAfterInitialization(AbstractAutowireCapableBeanFactory.java:438)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1791)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:600)
... 63 more
I would expect that in a minor version update, so my question is: Did our legacy code work "by luck" or is there something wrong?
Happy to provide more information, if required.
Comment From: snicoll
Thanks for upgrading and reporting the issue. I believe this is a duplicate of https://github.com/spring-projects/spring-framework/issues/32838.
If you have a chance to test your app with 6.1.8-SNAPSHOT
that would be very much appreciated. 6.1.8
is due this Thursday.
Comment From: rzo1
@snicoll Thanks for the fast response. I can confirm, that it works with the SNAPSHOT.