Issue
I am creating java jar library (maven) which will contain common configuration & util classes used in many services. My project is not multi-modules, so creating a new maven project. The configuration class I am not able to use in my project. Found out there are 2 approach for this from below mentioned references.
Adding entry in resoruces/META-INF/spring.factories in the library project (auto-configure). It is giving error of class not found. Also added package of library in scanPackage attribute of Spring Boot Application. Src code is there after all the text.
Error: The project which uses the library is not able to find class of ouath of spring related which is a dependency in the library class
For the full error stacktrace, please see the following collapsed snippet:
12:41:07.826 [main] ERROR org.springframework.boot.SpringApplication - Application run failed org.springframework.beans.factory.BeanDefinitionStoreException: Failed to process import candidates for configuration class [com.satishch.microspace.nri.security.ReferenceSecurityConfig]; nested exception is java.lang.IllegalArgumentException: Unresolvable class definition for class [com.satishch.microspace.nri.security.ReferenceSecurityConfig] at org.springframework.context.annotation.ConfigurationClassParser.processImports(ConfigurationClassParser.java:610) ~[spring-context-5.2.12.RELEASE.jar:5.2.12.RELEASE] at org.springframework.context.annotation.ConfigurationClassParser.doProcessConfigurationClass(ConfigurationClassParser.java:311) ~[spring-context-5.2.12.RELEASE.jar:5.2.12.RELEASE] at org.springframework.context.annotation.ConfigurationClassParser.processConfigurationClass(ConfigurationClassParser.java:250) ~[spring-context-5.2.12.RELEASE.jar:5.2.12.RELEASE] at org.springframework.context.annotation.ConfigurationClassParser.processImports(ConfigurationClassParser.java:600) ~[spring-context-5.2.12.RELEASE.jar:5.2.12.RELEASE] at org.springframework.context.annotation.ConfigurationClassParser.access$800(ConfigurationClassParser.java:111) ~[spring-context-5.2.12.RELEASE.jar:5.2.12.RELEASE] at org.springframework.context.annotation.ConfigurationClassParser$DeferredImportSelectorGroupingHandler.lambda$processGroupImports$1(ConfigurationClassParser.java:812) ~[spring-context-5.2.12.RELEASE.jar:5.2.12.RELEASE] at java.util.ArrayList.forEach(ArrayList.java:1257) ~[?:1.8.0_191] at org.springframework.context.annotation.ConfigurationClassParser$DeferredImportSelectorGroupingHandler.processGroupImports(ConfigurationClassParser.java:809) ~[spring-context-5.2.12.RELEASE.jar:5.2.12.RELEASE] at org.springframework.context.annotation.ConfigurationClassParser$DeferredImportSelectorHandler.process(ConfigurationClassParser.java:780) ~[spring-context-5.2.12.RELEASE.jar:5.2.12.RELEASE] at org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:193) ~[spring-context-5.2.12.RELEASE.jar:5.2.12.RELEASE] at org.springframework.context.annotation.ConfigurationClassPostProcessor.processConfigBeanDefinitions(ConfigurationClassPostProcessor.java:319) ~[spring-context-5.2.12.RELEASE.jar:5.2.12.RELEASE] at org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(ConfigurationClassPostProcessor.java:236) ~[spring-context-5.2.12.RELEASE.jar:5.2.12.RELEASE] at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanDefinitionRegistryPostProcessors(PostProcessorRegistrationDelegate.java:280) ~[spring-context-5.2.12.RELEASE.jar:5.2.12.RELEASE] at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:96) ~[spring-context-5.2.12.RELEASE.jar:5.2.12.RELEASE] at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:707) ~[spring-context-5.2.12.RELEASE.jar:5.2.12.RELEASE] at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:533) ~[spring-context-5.2.12.RELEASE.jar:5.2.12.RELEASE] at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:143) ~[spring-boot-2.3.8.RELEASE.jar:2.3.8.RELEASE] at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:758) ~[spring-boot-2.3.8.RELEASE.jar:2.3.8.RELEASE] at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:750) [spring-boot-2.3.8.RELEASE.jar:2.3.8.RELEASE] at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:405) [spring-boot-2.3.8.RELEASE.jar:2.3.8.RELEASE] at org.springframework.boot.SpringApplication.run(SpringApplication.java:315) [spring-boot-2.3.8.RELEASE.jar:2.3.8.RELEASE] at com.satish.NriAssetMgmtServiceApplication.main(NriAssetMgmtServiceApplication.java:28) [classes/:?] Caused by: java.lang.IllegalArgumentException: Unresolvable class definition for class [com.satishch.microspace.nri.security.ReferenceSecurityConfig] at org.springframework.util.ClassUtils.resolveClassName(ClassUtils.java:331) ~[spring-core-5.2.12.RELEASE.jar:5.2.12.RELEASE] at org.springframework.security.config.annotation.method.configuration.GlobalMethodSecuritySelector.selectImports(GlobalMethodSecuritySelector.java:51) ~[spring-security-config-5.3.6.RELEASE.jar:5.3.6.RELEASE] at org.springframework.context.annotation.ConfigurationClassParser.processImports(ConfigurationClassParser.java:581) ~[spring-context-5.2.12.RELEASE.jar:5.2.12.RELEASE] ... 21 more Caused by: java.lang.NoClassDefFoundError: org/springframework/security/oauth2/config/annotation/web/configuration/ResourceServerConfigurerAdapter at java.lang.ClassLoader.defineClass1(Native Method) ~[?:1.8.0_191] at java.lang.ClassLoader.defineClass(ClassLoader.java:763) ~[?:1.8.0_191] at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142) ~[?:1.8.0_191] at java.net.URLClassLoader.defineClass(URLClassLoader.java:468) ~[?:1.8.0_191] at java.net.URLClassLoader.access$100(URLClassLoader.java:74) ~[?:1.8.0_191] at java.net.URLClassLoader$1.run(URLClassLoader.java:369) ~[?:1.8.0_191] at java.net.URLClassLoader$1.run(URLClassLoader.java:363) ~[?:1.8.0_191] at java.security.AccessController.doPrivileged(Native Method) ~[?:1.8.0_191] at java.net.URLClassLoader.findClass(URLClassLoader.java:362) ~[?:1.8.0_191] at java.lang.ClassLoader.loadClass(ClassLoader.java:424) ~[?:1.8.0_191] at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:349) ~[?:1.8.0_191] at java.lang.ClassLoader.loadClass(ClassLoader.java:357) ~[?:1.8.0_191] at java.lang.Class.forName0(Native Method) ~[?:1.8.0_191] at java.lang.Class.forName(Class.java:348) ~[?:1.8.0_191] at org.springframework.util.ClassUtils.forName(ClassUtils.java:284) ~[spring-core-5.2.12.RELEASE.jar:5.2.12.RELEASE] at org.springframework.util.ClassUtils.resolveClassName(ClassUtils.java:324) ~[spring-core-5.2.12.RELEASE.jar:5.2.12.RELEASE] at org.springframework.security.config.annotation.method.configuration.GlobalMethodSecuritySelector.selectImports(GlobalMethodSecuritySelector.java:51) ~[spring-security-config-5.3.6.RELEASE.jar:5.3.6.RELEASE] at org.springframework.context.annotation.ConfigurationClassParser.processImports(ConfigurationClassParser.java:581) ~[spring-context-5.2.12.RELEASE.jar:5.2.12.RELEASE] ... 21 more Caused by: java.lang.ClassNotFoundException: org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter at java.net.URLClassLoader.findClass(URLClassLoader.java:382) ~[?:1.8.0_191] at java.lang.ClassLoader.loadClass(ClassLoader.java:424) ~[?:1.8.0_191] at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:349) ~[?:1.8.0_191] at java.lang.ClassLoader.loadClass(ClassLoader.java:357) ~[?:1.8.0_191] at java.lang.ClassLoader.defineClass1(Native Method) ~[?:1.8.0_191] at java.lang.ClassLoader.defineClass(ClassLoader.java:763) ~[?:1.8.0_191] at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142) ~[?:1.8.0_191] at java.net.URLClassLoader.defineClass(URLClassLoader.java:468) ~[?:1.8.0_191] at java.net.URLClassLoader.access$100(URLClassLoader.java:74) ~[?:1.8.0_191] at java.net.URLClassLoader$1.run(URLClassLoader.java:369) ~[?:1.8.0_191] at java.net.URLClassLoader$1.run(URLClassLoader.java:363) ~[?:1.8.0_191] at java.security.AccessController.doPrivileged(Native Method) ~[?:1.8.0_191] at java.net.URLClassLoader.findClass(URLClassLoader.java:362) ~[?:1.8.0_191] at java.lang.ClassLoader.loadClass(ClassLoader.java:424) ~[?:1.8.0_191] at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:349) ~[?:1.8.0_191] at java.lang.ClassLoader.loadClass(ClassLoader.java:357) ~[?:1.8.0_191] at java.lang.Class.forName0(Native Method) ~[?:1.8.0_191] at java.lang.Class.forName(Class.java:348) ~[?:1.8.0_191] at org.springframework.util.ClassUtils.forName(ClassUtils.java:284) ~[spring-core-5.2.12.RELEASE.jar:5.2.12.RELEASE] at org.springframework.util.ClassUtils.resolveClassName(ClassUtils.java:324) ~[spring-core-5.2.12.RELEASE.jar:5.2.12.RELEASE] at org.springframework.security.config.annotation.method.configuration.GlobalMethodSecuritySelector.selectImports(GlobalMethodSecuritySelector.java:51) ~[spring-security-config-5.3.6.RELEASE.jar:5.3.6.RELEASE] at org.springframework.context.annotation.ConfigurationClassParser.processImports(ConfigurationClassParser.java:581) ~[spring-context-5.2.12.RELEASE.jar:5.2.12.RELEASE] ... 21 more
- Creating annotation interface inside the library importing the config class. And, adding the annotation in any project in main class.
For the full error stacktrace, please see the following collapsed snippet:
12:34:17.903 [main] ERROR org.springframework.boot.SpringApplication - Application run failed org.springframework.context.ApplicationContextException: Unable to start web server; nested exception is org.springframework.context.ApplicationContextException: Unable to start ServletWebServerApplicationContext due to missing ServletWebServerFactory bean. at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.onRefresh(ServletWebServerApplicationContext.java:161) ~[spring-boot-2.3.8.RELEASE.jar:2.3.8.RELEASE] at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:545) ~[spring-context-5.2.12.RELEASE.jar:5.2.12.RELEASE] at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:143) ~[spring-boot-2.3.8.RELEASE.jar:2.3.8.RELEASE] at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:758) ~[spring-boot-2.3.8.RELEASE.jar:2.3.8.RELEASE] at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:750) [spring-boot-2.3.8.RELEASE.jar:2.3.8.RELEASE] at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:405) [spring-boot-2.3.8.RELEASE.jar:2.3.8.RELEASE] at org.springframework.boot.SpringApplication.run(SpringApplication.java:315) [spring-boot-2.3.8.RELEASE.jar:2.3.8.RELEASE] at com.satish.AssetMgmtServiceApplication.main(AssetMgmtServiceApplication.java:31) [classes/:?] Caused by: org.springframework.context.ApplicationContextException: Unable to start ServletWebServerApplicationContext due to missing ServletWebServerFactory bean. at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.getWebServerFactory(ServletWebServerApplicationContext.java:205) ~[spring-boot-2.3.8.RELEASE.jar:2.3.8.RELEASE] at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.createWebServer(ServletWebServerApplicationContext.java:177) ~[spring-boot-2.3.8.RELEASE.jar:2.3.8.RELEASE] at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.onRefresh(ServletWebServerApplicationContext.java:158) ~[spring-boot-2.3.8.RELEASE.jar:2.3.8.RELEASE] ... 7 more
Source code:
resoruces/META-INF/spring.factories (1st Approach)
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.satish.security.ReferenceSecurityConfig
Config inside the library
@EnableGlobalMethodSecurity(prePostEnabled = true)
@EnableResourceServer
@EnableWebSecurity
@Configuration
@ConfigurationProperties(prefix = "security")
@Data
@EqualsAndHashCode(callSuper=false)
public class ReferenceSecurityConfig extends ResourceServerConfigurerAdapter {
private boolean bypass;
@Override
public void configure(HttpSecurity http) throws Exception {
http
.cors()
.and()
.csrf().disable();
if (bypass) {
http.authorizeRequests().antMatchers("/**").permitAll();
} else {
http.authorizeRequests()
.antMatchers("/swagger-ui/**").permitAll()
.antMatchers("/management").permitAll()
.antMatchers("/management/**").permitAll()
.antMatchers("/swagger-ui.html").permitAll()
.antMatchers("/swagger-resources/**").permitAll()
.antMatchers("/v2/api-docs/**").permitAll()
.antMatchers("/webjars/**").permi tAll()
.antMatchers("/v3/api-docs/**").permitAll()
.antMatchers("/swagger-ui/**").permitAll()
.antMatchers("/**").authenticated();
}
}
}
Annotation to use in the main project (2nd approach)
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Import(ReferenceSecurityConfig.class)
public @interface EnableCustomSecurityConfig {
}
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.satish</groupId>
<artifactId>core-lib</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>core-lib</name>
<description>Storing common implementation</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.8.RELEASE</version>
<relativePath />
</parent>
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<log4j2.version>2.17.1</log4j2.version>
<log4j2Version>2.7</log4j2Version>
<slf4jVersion>1.7.21</slf4jVersion>
</properties>
<repositories>
<repository>
<id>confluent</id>
<url>https://packages.confluent.io/maven/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.1.RELEASE</version>
<type>pom</type>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- security dependencies -->
<dependency>
<groupId>org.springframework.security.oauth.boot</groupId>
<artifactId>spring-security-oauth2-autoconfigure</artifactId>
<version>2.3.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-core</artifactId>
<version>5.1.7.RELEASE</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>${springSecurityVersion}</version>
</dependency>
<!-- spring-boot-starter-security -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<optional>true</optional>
</dependency>
<!-- Not sure why Lombok is not working -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<!-- Provided Dependencies -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifestEntries>
<Implementation-Vendor>Satish's Companies Inc.</Implementation-Vendor>
<Implementation-Title>TITLE</Implementation-Title>
<Implementation-Version>2.2</Implementation-Version>
</manifestEntries>
</archive>
</configuration>
</plugin>
<!--plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId>
<configuration> <fork>true</fork> <mainClass>${start-class}</mainClass> </configuration>
<executions> <execution> <goals> <goal>repackage</goal> </goals> </execution>
</executions> </plugin -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Solution
First, I believe I already did a lib achieving what you're trying to do. A lot is configurable from properties (CORS, authorities mapping and more) and it is published on maven-central.
Spring-boot starters have changed since 2.7.
Auto-configured components should now be:
- decorated with
@AutoConfiguration
- declared in
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
Minimal sample here with this resource
com.c4_soft.springaddons.starter.webclient.SpringBootAutoConfiguration
and that loaded file
package com.c4_soft.springaddons.starter.webclient;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.context.annotation.Import;
@AutoConfiguration
@Import({ C4ProxySettings.class, C4WebClientBuilderFactoryService.class })
public class SpringBootAutoConfiguration {
}
Answered By - ch4mp
Answer Checked By - Dawn Plyler (JavaFixing Volunteer)