Apache POI创建EncryptionInfo实例时ClassCastException问题(Weblogic12)
从你给出的异常栈来看,核心问题是org.apache.poi.poifs.crypt.agile.AgileEncryptionInfoBuilder cannot be cast to org.apache.poi.poifs.crypt.EncryptionInfoBuilder,这种类转换异常几乎都是类加载器冲突导致的——Weblogic服务器自带了旧版本的Apache POI相关类,和你应用中打包的POI版本不一致,导致同一个逻辑类被不同的类加载器加载,JVM认为它们是不同类型,从而抛出转换异常。
解决方案步骤
1. 确保POI依赖版本完全一致
首先检查你的项目依赖,确保所有POI相关组件(poi、poi-ooxml、poi-ooxml-schemas、poi-scratchpad等)使用同一个稳定版本,比如4.1.2或者5.2.3(避免混合不同版本,这本身就容易引发问题)。
如果用Maven,在pom.xml里统一管理版本:
<properties> <poi.version>4.1.2</poi.version> </properties> <dependencies> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>${poi.version}</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>${poi.version}</version> </dependency> <!-- 其他POI组件也用同样版本 --> </dependencies>
2. 配置Weblogic优先加载应用的POI类
Weblogic默认会优先加载自身库中的类,所以需要修改应用的weblogic.xml(放在WEB-INF下),配置prefer-application-packages,让应用优先使用自己打包的POI及相关依赖类:
<weblogic-web-app xmlns="http://xmlns.oracle.com/weblogic/weblogic-web-app" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.oracle.com/weblogic/weblogic-web-app http://xmlns.oracle.com/weblogic/weblogic-web-app/1.7/weblogic-web-app.xsd"> <container-descriptor> <prefer-application-packages> <!-- 覆盖所有POI相关包 --> <package-name>org.apache.poi.*</package-name> <!-- XMLBeans是POI依赖的,也需要优先加载 --> <package-name>org.apache.xmlbeans.*</package-name> <!-- OpenXML格式相关包 --> <package-name>org.openxmlformats.*</package-name> </prefer-application-packages> </container-descriptor> </weblogic-web-app>
3. 验证类加载器(可选)
如果不确定是否是类加载器问题,可以在代码中加入日志,打印两个类的加载器:
logger.info("EncryptionInfoBuilder loaded by: " + EncryptionInfoBuilder.class.getClassLoader()); logger.info("AgileEncryptionInfoBuilder loaded by: " + AgileEncryptionInfoBuilder.class.getClassLoader());
如果输出的类加载器不同,就确认是冲突问题,上面的配置就能解决。
4. 优化代码中的资源关闭
另外注意你代码里的finally块,资源关闭没有做异常处理,一个资源关闭失败会导致后续资源无法关闭。推荐使用Java 7+的try-with-resources语法,自动管理资源:
public static void parseFileToSecureFile(String fullFileName, String password) throws MyException{ try (POIFSFileSystem fs = new POIFSFileSystem(); OPCPackage opc = OPCPackage.open(new File(fullFileName), PackageAccess.READ_WRITE); FileOutputStream fos = new FileOutputStream(fullFileName)) { EncryptionInfo info = new EncryptionInfo(EncryptionMode.agile, CipherAlgorithm.aes256, HashAlgorithm.sha512, -1, -1, null); Encryptor enc = info.getEncryptor(); enc.confirmPassword(password); try (OutputStream os = enc.getDataStream(fs)) { opc.save(os); } fs.writeFilesystem(fos); } catch (Exception e) { logger.error("Error encrypting file: "+e.getMessage(), e); throw new MyException("Failed to encrypt Excel file"); } }
这样不用手动关闭资源,JVM会自动确保所有资源被正确关闭,避免资源泄漏。
内容的提问来源于stack exchange,提问作者Bal_lam




