I tried to run Spring Boot within my Java Plugin, but when I try to actually run it on the Server, it keeps producing this error:
The error is, that im am trying to load spring boot inside a paper environment and even when the spring.factories is included in my jar, it cannot be found in the minecraft server environment
[21:59:15 INFO]: [STDOUT] . ____ _ __ _ _
[21:59:15 INFO]: [STDOUT] /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
[21:59:15 INFO]: [STDOUT] ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
[21:59:15 INFO]: [STDOUT] \\/ ___)| |_)| | | | | || (_| | ) ) ) )
[21:59:15 INFO]: [STDOUT] ' |____| .__|_| |_|_| |_\__, | / / / /
[21:59:15 INFO]: [STDOUT] =========|_|==============|___/=/_/_/_/
[21:59:15 INFO]: [STDOUT] :: Spring Boot :: (v2.7.2)
[21:59:15 INFO]:
[21:59:15 INFO]: Starting application using Java 17.0.2 on DESKTOP-N582J7M with PID 2364 (started by Programmers PC in F:\programming\paper 1.18.2 server)
[21:59:15 INFO]: No active profile set, falling back to 1 default profile: "default"
[21:59:15 ERROR]: Application run failed
java.lang.IllegalArgumentException: No auto configuration classes found in META-INF/spring.factories nor in META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports. If you are using a custom packaging, make sure that file is correct.
at org.springframework.util.Assert.notEmpty(Assert.java:470) ~[paradubschmanager-0.1.jar:?]
at org.springframework.boot.autoconfigure.AutoConfigurationImportSelector.getCandidateConfigurations(AutoConfigurationImportSelector.java:185) ~[paradubschmanager-0.1.jar:?]
...
at org.springframework.boot.builder.SpringApplicationBuilder.run(SpringApplicationBuilder.java:164) ~[paradubschmanager-0.1.jar:?]
at de.paradubsch.paradubschmanager.persistance.SpringConfigurer.initializeSpringApplication(SpringConfigurer.java:35) ~[paradubschmanager-0.1.jar:?]
at de.paradubsch.paradubschmanager.ParadubschManager.onEnable(ParadubschManager.java:68) ~[paradubschmanager-0.1.jar:?]
...
at java.lang.Thread.run(Thread.java:833) ~[?:?]
I'm using Spring v2.7.2,
Paper git-Paper-260 (MC: 1.18.2) (Implementing API version 1.18.2-R0.1-SNAPSHOT) (Git: bc68ee0)
To include this in my Plugin, I need it to work without parent. Here is my pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
...
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.4</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<!-- Not Working idk why
<minimizeJar>true</minimizeJar> -->
<createDependencyReducedPom>false</createDependencyReducedPom>
<createSourcesJar>false</createSourcesJar>
<createTestSourcesJar>false</createTestSourcesJar>
<!--<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>META-INF/spring.factories</resource>
</transformer>
</transformers> -->
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
<exclude>META-INF/*.kotlin_module</exclude>
<exclude>META-INF/*.txt</exclude>
<exclude>META-INF/proguard/*</exclude>
<exclude>META-INF/services/*</exclude>
<exclude>META-INF/versions/9/*</exclude>
<exclude>*License*</exclude>
<exclude>*LICENSE*</exclude>
</excludes>
</filter>
</filters>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<phase>package</phase>
<id>server</id>
<configuration>
<target>
<!-- This deletes all generated classes after the compilation.
IDK why, but there are bugs if I don't do that-->
<exec dir="${project.basedir}/target/" executable="cmd.exe">
<arg value="/c" />
<arg value="@RD" />
<arg value="/S" />
<arg value="/Q" />
<arg value='"./classes"' />
</exec>
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
<!--<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M7</version>
<configuration>
<junitArtifactName>org.junit.jupiter:junit-jupiter</junitArtifactName>
<trimStackTrace>false</trimStackTrace>
</configuration>
</plugin> -->
</plugins>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
</build>
<dependencyManagement>
<dependencies>
<dependency>
<!-- Import dependency management from Spring Boot -->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.7.2</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<repositories>
<repository>
<id>papermc-repo</id>
<url>https://papermc.io/repo/repository/maven-public/</url>
</repository>
<repository>
<id>sonatype</id>
<url>https://oss.sonatype.org/content/groups/public/</url>
</repository>
...
<repository>
<id>dmulloy2-repo</id>
<url>https://repo.dmulloy2.net/repository/public/</url>
</repository>
</repositories>
<dependencies>
<!-- Provided -->
<dependency>
<groupId>io.papermc.paper</groupId>
<artifactId>paper-api</artifactId>
<version>1.18.2-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.22</version>
<scope>provided</scope>
</dependency>
...
<!-- Runtime -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.22</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-jcache</artifactId>
<version>5.6.10.Final</version>
</dependency>
<dependency>
<groupId>org.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>3.6.3</version>
</dependency>
<!-- Testing -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.8.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.github.seeseemelk</groupId>
<artifactId>MockBukkit-v1.18</artifactId>
<version>2.85.2</version>
<scope>test</scope>
<exclusions>
<exclusion>
<artifactId>spigot-api</artifactId>
<groupId>org.spigotmc</groupId>
</exclusion>
<exclusion>
<artifactId>annotations</artifactId>
<groupId>org.jetbrains</groupId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
</project>
I think i actually need the maven-compiler-plugin and maven-shade-plugin to properly bundle it for production.
My Main Method: src/main/java/de/paradubsch/paradubschmanager/ParadubschManager.java,
...
public class ParadubschManager extends JavaPlugin {
...
@Override
public void onEnable() {
...
ResourceLoader loader = new DefaultResourceLoader(Thread.currentThread().getContextClassLoader());
ctx = SpringConfigurer.initializeSpringApplication(loader);
...
}
}
calls my SpringConfigurer:
public static ConfigurableApplicationContext initializeSpringApplication(ResourceLoader loader) {
return new SpringApplicationBuilder(SpringApplication.class).properties(getConfiguration()).run();
}
with properties getConfiguration(), to replace application.properties:
Properties props = new Properties();
props.put("spring.datasource.driver-class-name", ConfigurationManager.getString("hibernate.driver"));
props.put("spring.datasource.username", ConfigurationManager.getString("hibernate.user"));
props.put("spring.datasource.password", ConfigurationManager.getString("hibernate.pass"));
props.put("spring.datasource.url", ConfigurationManager.getString("hibernate.url"));
props.put("spring.jpa.show-sql", ConfigurationManager.getString("hibernate.showSql"));
props.put("spring.jpa.hibernate.ddl-auto", ConfigurationManager.getString("hibernate.hmb2ddlAuto"));
props.put("spring.jpa.properties.hibernate.dialect", ConfigurationManager.getString("hibernate.dialect"));
props.put("spring.flyway.enabled", "false");
props.put("logging.level.org.springframework", "DEBUG");
and starting my src/main/java/de/paradubsch/paradubschmanager/persistance/SpringApplication.java:
@SpringBootApplication
public class SpringApplication {
}
**I'm pretty sure the compilation works as intended:**
It compiles, shades and gives me my Jar
I doublechecked - my jar includes a META-INF/spring.factorys that is not empty, also the META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports.
So it has something to do with the ClassLoader not loading the file from my jar correctly.
I confirmed this when Mocking my Server with MockBukkit:
@BeforeAll
public static void setUp() {
server = MockBukkit.mock();
plugin = MockBukkit.load(ParadubschManager.class);
server.getScheduler().performOneTick();
server.getScheduler().waitAsyncTasksFinished();
server.getScheduler().waitAsyncEventsFinished();
adminPlayer = server.addPlayer();
targetPlayer = server.addPlayer();
server.getScheduler().waitAsyncTasksFinished();
server.getScheduler().waitAsyncEventsFinished();
}
and then everything works as intended and all my tests pass.
Does anyone have an idea?