如何修复ClassNotFoundException: org.springframework.boot.configurationprocessor.json.JSONObject错误?
部署应用时遇到以下错误:
java.lang.reflect.InvocationTargetException at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:568) 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:65) Caused by: java.lang.NoClassDefFoundError: org/springframework/boot/configurationprocessor/json/JSONObject at com.rossmoor.jenarktomds.services.web.GrfPortalClientServiceImpl.getAccessToken(GrfPortalClientServiceImpl.java:53) at com.rossmoor.jenarktomds.services.web.GrfPortalClientServiceImpl.downloadAllGrfUsers(GrfPortalClientServiceImpl.java:325) at com.rossmoor.jenarktomds.services.DataProcessorImpl.testGrfApi(DataProcessorImpl.java:1939) at com.rossmoor.jenarktomds.services.DataProcessorImpl$$FastClassBySpringCGLIB$$716e474b.invoke(<generated>) at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:793) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763) at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:123) at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:388) at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763) at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:708) at com.rossmoor.jenarktomds.services.DataProcessorImpl$$EnhancerBySpringCGLIB$$21e20f26.testGrfApi(<generated>) at com.rossmoor.jenarktomds.JenarkToMdsApplication.run(JenarkToMdsApplication.java:76) at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:771) at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:755) at org.springframework.boot.SpringApplication.run(SpringApplication.java:315) at org.springframework.boot.SpringApplication.run(SpringApplication.java:1306) at org.springframework.boot.SpringApplication.run(SpringApplication.java:1295) at com.rossmoor.jenarktomds.JenarkToMdsApplication.main(JenarkToMdsApplication.java:59) ... 8 more Caused by: java.lang.ClassNotFoundException: org.springframework.boot.configurationprocessor.json.JSONObject at java.base/java.net.URLClassLoader.findClass(URLClassLoader.java:445) at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:587) at org.springframework.boot.loader.LaunchedURLClassLoader.loadClass(LaunchedURLClassLoader.java:151) at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:520) ... 30 more
引发错误的代码片段:
// create request body JSONObject request = new JSONObject(); request.put("username", configurationProperties.getGrfPortalUserName()); request.put("password", configurationProperties.getGrfPortalUserPwd()); // set headers HttpHeaders headers = new HttpHeaders(); headers.add("API-Key", "{{apiKey}}"); headers.add("Authorization", "Basic {{authorization}}"); headers.setContentType(MediaType.APPLICATION_JSON); HttpEntity<String> entity = new HttpEntity<>(request.toString(), headers); if (Logger.isInfoEnabled()) Logger.info("Sending request to GRF Portal"); // send request and parse result ResponseEntity<String> loginResponse = restTemplate .exchange(GRF_LOGIN_URL, HttpMethod.POST, entity, String.class); if (loginResponse.getStatusCode() == HttpStatus.OK) { JSONObject userJson = new JSONObject(loginResponse.getBody()); if (Logger.isInfoEnabled()) Logger.info("Token Data = " + userJson); this.AccessToken = String.valueOf(userJson.get("token")); System.out.println("AccessToken = " + AccessToken); } else if (loginResponse.getStatusCode() == HttpStatus.UNAUTHORIZED) { // nono... bad credentials if (Logger.isErrorEnabled()) Logger.error("nono... bad credentials"); }
关键信息
- 错误仅在生产服务器部署时出现,开发环境或用IntelliJ直接运行无问题
- 部署步骤:
- Gradle build构建应用
- Jar2exe将Jar转成exe
- 通过安装程序部署为Windows服务
Gradle配置:
plugins { id 'org.springframework.boot' version '2.7.0' id 'io.spring.dependency-management' version '1.0.11.RELEASE' id 'java' } group = 'com.rossmoor' version = '0.0.1-SNAPSHOT' sourceCompatibility = '17' configurations { compileOnly { extendsFrom annotationProcessor } } repositories { mavenCentral() } dependencies { implementation 'org.springframework.boot:spring-boot-starter-oauth2-client' implementation 'org.springframework.boot:spring-boot-starter-security' implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-data-rest' compileOnly 'org.projectlombok:lombok' developmentOnly 'org.springframework.boot:spring-boot-devtools' runtimeOnly 'com.microsoft.sqlserver:mssql-jdbc' annotationProcessor 'org.projectlombok:lombok' testImplementation 'org.springframework.boot:spring-boot-starter-test' testImplementation 'org.springframework.security:spring-security-test' annotationProcessor "org.springframework.boot:spring-boot-configuration-processor" // // https://mvnrepository.com/artifact/org.hibernate.orm/hibernate-core // implementation group: 'org.hibernate.orm', name: 'hibernate-core', version: '6.0.2.Final' // // // https://mvnrepository.com/artifact/jakarta.transaction/jakarta.transaction-api // implementation group: 'jakarta.transaction', name: 'jakarta.transaction-api', version: '2.0.1' // // // https://mvnrepository.com/artifact/jakarta.persistence/jakarta.persistence-api // implementation group: 'jakarta.persistence', name: 'jakarta.persistence-api', version: '3.1.0' // https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 implementation group: 'org.apache.commons', name: 'commons-lang3', version: '3.12.0' // https://mvnrepository.com/artifact/commons-validator/commons-validator implementation group: 'commons-validator', name: 'commons-validator', version: '1.7' // https://mvnrepository.com/artifact/org.mapstruct/mapstruct implementation group: 'org.mapstruct', name: 'mapstruct', version: '1.5.2.Final' // https://mvnrepository.com/artifact/com.google.code.gson/gson implementation group: 'com.google.code.gson', name: 'gson', version: '2.9.1' implementation files('lib/connection-manager-2.0.0.1.jar') implementation files('lib/Utils-2.0.0.1.jar') implementation files('lib/TinyLog-2.0.0.1.jar') } tasks.named('test') { useJUnitPlatform() }
问题根源
你代码里用的org.springframework.boot.configurationprocessor.json.JSONObject来自spring-boot-configuration-processor依赖,但这个依赖在Gradle配置里是annotationProcessor范围——这个范围只在编译期生成配置元数据时生效,不会被打包到最终的可执行Jar里。
开发环境能运行是因为IntelliJ会自动把annotationProcessor类加入类路径,但生产部署时,打包后的Jar(以及转成的exe)里没有这个类,所以抛出ClassNotFoundException。
修复方案
方案1:替换为标准JSON库(推荐)
spring-boot-configuration-processor里的JSON类只是内部工具,不应该在业务代码里使用。你已经引入了Gson,直接用它来处理JSON:
修改代码:
import com.google.gson.JsonObject; import com.google.gson.Gson; // 创建请求体 JsonObject request = new JsonObject(); request.addProperty("username", configurationProperties.getGrfPortalUserName()); request.addProperty("password", configurationProperties.getGrfPortalUserPwd()); // 转成字符串 String requestBody = new Gson().toJson(request); HttpEntity<String> entity = new HttpEntity<>(requestBody, headers); // 解析响应 if (loginResponse.getStatusCode() == HttpStatus.OK) { JsonObject userJson = new Gson().fromJson(loginResponse.getBody(), JsonObject.class); this.AccessToken = userJson.get("token").getAsString(); System.out.println("AccessToken = " + AccessToken); }
这样完全不需要依赖spring-boot-configuration-processor的JSON类,避免依赖范围问题。
方案2:调整依赖范围(不推荐)
如果一定要用这个JSONObject,把spring-boot-configuration-processor的依赖范围改成implementation:
// 替换原来的annotationProcessor行 implementation "org.springframework.boot:spring-boot-configuration-processor"
但不建议这么做,因为这个依赖本来就是用于编译期的,打包到生产环境属于冗余,还可能带来版本冲突风险。
额外检查
确认Gradle构建的是可执行Jar(Spring Boot默认的bootJar任务),而不是普通的jar任务。运行./gradlew bootJar来构建,确保所有依赖都被打包进去。另外,用Jar2exe转换时,要确保它正确处理了Spring Boot Jar的嵌套结构,没有遗漏依赖类。
内容的提问来源于stack exchange,提问作者Ram

