In our project we are using some annotations tools from configuration processor at runtime. After recent spring version update (spring-boot-starter-parent 2.3.8 -> 2.5.2) almost everything was fine just at runtime we start getting:
ClassNotFoundException: org.springframework.boot.configurationprocessor.json.JSONException
In our WebSecurityConfigurerAdapter.configure code.
After manually adding spring-boot-configuration-processor-2.5.2.jar into BOOT-INF/lib/ folder of the build jar -> application is working fine (I was sure that previous class not found was due to wrap actual exception - but seems it was original problem).
So right now we are not able to mark this jar not to be deleted from resulted artifact after this change
https://github.com/spring-projects/spring-boot/blob/b65cc4d62f4a818e36be8b99b98eba01a28f6f2a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractDependencyFilterMojo.java#L108
Is it possible to wrap registering of the
filters.addFilter(new JarTypeFilter());
with some flag? by default it would exclude but if it is required for some corner cases like ours we can proceed using it?
Comment From: philwebb
Relates to #22036
Comment From: philwebb
@stepanovdg Using spring-boot-configuration-processor at runtime is quite unusual. Which specific classes do you use from that project and why are they needed at runtime?
Comment From: philwebb
If we do want to make things configurable we could either offer a simple on/off switch or change JarTypeFilter and JarTypeFileSpec so that they can accept a list of the types to exclude?
Interestingly the JarTypeFileSpec does not filter annotation processors. I'm assuming because Gradle has a better annotation processor setup and they don't appear in the first place.
Comment From: stepanovdg
@philwebb Not sure that we really used it directly. Maybe some problem with order.
The place where its failing we are actually using org.reflections to scan methods with our own annotations (like frontendapi, internalapi and etc) together with RequestMapping to group up and apply web security settings and in other place to generate proper open api endpoints.
I was thinking just after major update of spring versions something was broken in configuration or third-party dependency versions and this was just masking actual reason.
But putting jar on classpath resolved all problems.
Comment From: philwebb
@stepanovdg Do you have a full stack-trace that you can add to this issue? Even better would be a sample application that replicates the problem. I'm curious why org.reflections would be needing to read the org.springframework.boot.configurationprocessor.json.JSONException class at all.
Comment From: stepanovdg
2021-08-06 01:34:08 ERROR [ main] [o.s.boot.SpringApplication :843] Application run failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'springSecurityFilterChain' defined in class path resource [org/springframework/security/config/annotation/web/configuration/WebSecurityConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [javax.servlet.Filter]: Factory method 'springSecurityFilterChain' threw exception; nested exception is java.lang.NoClassDefFoundError: org/springframework/boot/configurationprocessor/json/JSONException
at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:658)
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:486)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1334)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1177)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:564)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:524)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:322)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:944)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:918)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:583)
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:145)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:754)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:434)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:338)
at c.v.t.TcpBullseyeApplication.main(TcpBullseyeApplication.java:34)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:49)
at org.springframework.boot.loader.Launcher.launch(Launcher.java:108)
at org.springframework.boot.loader.Launcher.launch(Launcher.java:58)
at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:88)
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [javax.servlet.Filter]: Factory method 'springSecurityFilterChain' threw exception; nested exception is java.lang.NoClassDefFoundError: org/springframework/boot/configurationprocessor/json/JSONException
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:185)
at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:653)
... 27 common frames omitted
Caused by: java.lang.NoClassDefFoundError: org/springframework/boot/configurationprocessor/json/JSONException
at c.v.t.config.security.CommonSecurityConfig.configure(CommonSecurityConfig.java:57)
at org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter.getHttp(WebSecurityConfigurerAdapter.java:217)
at org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter.init(WebSecurityConfigurerAdapter.java:315)
at org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter.init(WebSecurityConfigurerAdapter.java:93)
at c.v.t.config.security.CommonSecurityConfig$$EnhancerBySpringCGLIB$$bd90bedf.init(<generated>)
at org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter$$FastClassBySpringCGLIB$$432a6c3b.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:779)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:750)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:750)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:692)
at c.v.t.config.security.CommonSecurityConfig$$EnhancerBySpringCGLIB$$ce36a12.init(<generated>)
at org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder.init(AbstractConfiguredSecurityBuilder.java:338)
at org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder.doBuild(AbstractConfiguredSecurityBuilder.java:300)
at org.springframework.security.config.annotation.AbstractSecurityBuilder.build(AbstractSecurityBuilder.java:38)
at org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration.springSecurityFilterChain(WebSecurityConfiguration.java:127)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154)
... 28 common frames omitted
Caused by: java.lang.ClassNotFoundException: org.springframework.boot.configurationprocessor.json.JSONException
at java.net.URLClassLoader.findClass(URLClassLoader.java:382)
at java.lang.ClassLoader.loadClass(ClassLoader.java:418)
at org.springframework.boot.loader.LaunchedURLClassLoader.loadClass(LaunchedURLClassLoader.java:151)
at java.lang.ClassLoader.loadClass(ClassLoader.java:351)
... 52 common frames omitted
Actual stacktrace. Error happening at line:
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
specifically pointing to this and().
@Override
@Log(Log.LoggingLevel.INFO)
protected void configure(HttpSecurity http) {
HashSet<String> skipUrls =
new HashSet<>(Arrays.asList("/management/health", "/management/prometheus"));
HttpSecurity httpSecurity = registerSecuredApi(http);
httpSecurity
.csrf()
.disable()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.addFilterBefore(
new AuthenticationFilter(whitelistedIps, skipUrls),
UsernamePasswordAuthenticationFilter.class)
.addFilterBefore(new InitiatedFilter(skipUrls), AuthenticationFilter.class)
.exceptionHandling()
.authenticationEntryPoint(exceptionHandler)
.accessDeniedHandler(exceptionHandler);
}
@Log(Log.LoggingLevel.INFO)
protected HttpSecurity registerSecuredApi(HttpSecurity http) throws Exception {
ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry
expressionInterceptUrlRegistry = http.authorizeRequests();
Map<HttpMethod, List<ApiAnnotationsUtils.MethodPatternPair>> apiAnnotatedWith =
getApiAnnotatedWith(FrontendApi.class);
apiAnnotatedWith
.keySet()
.forEach(
method ->
expressionInterceptUrlRegistry
.antMatchers(
method,
apiAnnotatedWith.get(method).stream()
.map(ApiAnnotationsUtils.MethodPatternPair::getPattern)
.toArray(String[]::new))
.authenticated());
return expressionInterceptUrlRegistry
.antMatchers("/actuator/**")
.permitAll()
.anyRequest()
.permitAll()
.and();
}
@Log(Log.LoggingLevel.INFO)
public static Map<HttpMethod, List<MethodPatternPair>> getApiAnnotatedWith(Class<? extends Annotation> annotation) {
Map<HttpMethod, List<MethodPatternPair>> collect = getRequestMappingStream(annotation)
.flatMap(
request ->
Arrays.stream(request.method())
.map(m -> HttpMethod.resolve(m.toString()))
.flatMap(
m ->
Arrays.stream(request.path())
.map(path -> new MethodPatternPair(m, path))))
.collect(Collectors.groupingBy(MethodPatternPair::getMethod));
return collect;
}
@Log
public static Stream<RequestMapping> getRequestMappingStream(Class<? extends Annotation> annotation) {
return new Reflections("c.v.t.web.api.controller", new MethodAnnotationsScanner())
.getMethodsAnnotatedWith(annotation).stream()
.map(
method ->
Objects.requireNonNull(
AnnotationUtils.getAnnotation(method, RequestMapping.class)));
}
@Data
@AllArgsConstructor
public static class MethodPatternPair {
HttpMethod method;
String pattern;
}
Not sure that will be able to create simple application now.
Comment From: philwebb
I'm at a bit of a loss from the code you've attached what could be causing the problem, especially if CommonSecurityConfig.java:57 is on the .sessionCreationPolicy(SessionCreationPolicy.STATELESS) line.
Have you tried searching your codebase to make sure org.springframework.boot.configurationprocessor.json.JSONException hasn't accidentally been imported anywhere?
Comment From: snicoll
@stepanovdg the configuration processor shades JSON for internal purpose only. It's not meant to be used anywhere else, especially considering that an annotation processor is meant to be used at compile time only. CommonSecurityConfig should rely on a JSON library directly rather than relying on our shaded, internal version.
You can do so by adding a dependency to com.vaadin.external.google:android-json and fix the import in CommonSecurityConfig.
Comment From: philwebb
@snicoll I'm not sure we've determined that CommonSecurityConfig is importing JSONException, it might be the Reflections class that's somehow picking it up from elsewhere.
@stepanovdg If you haven't got any org.springframework.boot.configurationprocessor.json import in your codebase can you please provide a sample that replicates the problem.
Comment From: stepanovdg
@philwebb @snicoll Thank you very much. Its appeared in side auth filter import was from JsonObject and exception from configuration processor instead of org.json.
Sorry for disturb.
Comment From: qyqcswill
It happens to me. I use another way in my codebase. But I tried spring-boot 2.3.x,it worked. By the way, will you fix this in next version.
Comment From: snicoll
@qyqcswill there's nothing to fix as far as I know. Please review the thread above. If you have imports on org.springframework.boot.configurationprocessor.json, you shouldn't. This is a shaded version that's not meant to be used in user's code. If you don't, please share a small sample that reproduces the problem and we can reopen this issue.
Comment From: qyqcswill
ok, great. I suggested my team upgrading the spring-boot version from spring-boot2.2.x to spring-boot2.4.x.I don't know anyone else who had import on org.springframework.boot.configurationprocessor.json.No matter, everyone review code.
Comment From: retamiro
Is there any way to wrap the lib spring-boot-configuration-processor-2.x.x.jar. As stated above, at the time of packaging this lib is not packaged from version 2.4.x, occurring the error at run time: Caused by exception: java.lang.NoClassDefFoundError Message: org.springframework.boot.configurationprocessor.json.JSONException
This is because the code is using the org.springframework.boot.configurationprocessor.json.JSONException class
Comment From: wilkinsona
@retamiro Please see Stephane's comment above. It sounds like you have some of your own code that's trying to use org.springframework.boot.configurationprocessor.json.JSONException which you should not be using.
Comment From: retamiro
There are some microservices that have been misused, the goal is to minimize the impact. the problem occurs due to the "Jar Optimizations" implemented in spring 2.4x, so I asked if it has any way, but thanks for the feedback