调用S3Client的listObjects方法报JAXB缺失错误求助
问题背景
使用com.emc.object.s3的S3Client调用listObjects方法列出存储桶Key时,抛出以下异常:
javax.ws.rs.WebApplicationException: javax.xml.bind.JAXBException: Implementation of JAXB-API has not been found on module path or classpath. - with linked exception: [java.lang.ClassNotFoundException: com.sun.xml.bind.v2.ContextFactory]
...
Caused by: java.lang.ClassNotFoundException: com.sun.xml.bind.v2.ContextFactory
已尝试添加GlassFish的JAXB依赖但无效:
implementation 'org.glassfish.jaxb:jaxb-runtime:2.3.0-b170127.1453' implementation 'javax.activation:activation:1.1' implementation 'javax.xml.bind:jaxb-api:2.3.0'
调用代码如下:
public void list() { ListObjectsResult objectListing = s3client.listObjects(nBucket);// 报错行 for (S3Object objectSummary : objectListing.getObjects()) { System.out.println(" - " + objectSummary.getKey() + " " + "(size = " + objectSummary.getSize() + ")"); } }
错误原因
EMC的S3客户端依赖Sun/Oracle官方的JAXB实现(com.sun.xml.bind包),但你添加的是GlassFish的JAXB实现(org.glassfish.jaxb),两者不兼容,导致找不到指定的ContextFactory类。
解决方案
1. 替换为Sun官方JAXB依赖
修改build.gradle中的JAXB依赖为Sun的实现,确保版本匹配:
implementation 'com.sun.xml.bind:jaxb-api:2.3.1' implementation 'com.sun.xml.bind:jaxb-impl:2.3.1' implementation 'com.sun.xml.bind:jaxb-core:2.3.0.1' implementation 'javax.activation:activation:1.1.1'
执行gradle clean build重新构建,确保依赖被正确加载。
2. 排查Spring Boot依赖冲突
如果是Spring Boot项目,可能存在自动依赖管理排除JAXB的情况。可以通过以下命令查看依赖树:
./gradlew dependencies
若发现有依赖排除JAXB相关包,需手动添加强制引入规则,例如:
configurations.all { resolutionStrategy.force 'com.sun.xml.bind:jaxb-impl:2.3.1' }
3. 替代方案:改用AWS S3 SDK操作EMC存储
如果上述方法无效,可使用AWS S3 SDK(兼容EMC S3协议)来列出Key,该SDK对JAXB依赖处理更完善,且支持分页遍历所有Key:
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.services.s3.S3Client; import software.amazon.awssdk.services.s3.model.ListObjectsV2Request; import software.amazon.awssdk.services.s3.model.ListObjectsV2Response; import software.amazon.awssdk.services.s3.model.S3Object; import java.net.URI; public void listAllKeys() { // 配置EMC S3端点、密钥 S3Client s3Client = S3Client.builder() .endpointOverride(URI.create("http://your-emc-s3-endpoint")) .credentialsProvider(() -> AwsBasicCredentials.create("your-access-key", "your-secret-key")) .region(Region.of("us-east-1")) // 任意区域均可,EMC兼容S3协议 .build(); String bucketName = nBucket; String continuationToken = null; // 分页遍历所有Key do { ListObjectsV2Request request = ListObjectsV2Request.builder() .bucket(bucketName) .continuationToken(continuationToken) .build(); ListObjectsV2Response response = s3Client.listObjectsV2(request); for (S3Object obj : response.contents()) { System.out.println(" - " + obj.key() + " (size = " + obj.size() + ")"); } continuationToken = response.nextContinuationToken(); } while (continuationToken != null); }
添加AWS S3 SDK依赖:
implementation 'software.amazon.awssdk:s3:2.20.0'
内容的提问来源于stack exchange,提问作者Leonard Kawhi

