使用Apache POI与xmlsec时遇java.lang.InstantiationError错误求助
问题描述
调用SignatureInfo.confirmSignature()时触发java.lang.InstantiationError: org.apache.xml.security.signature.XMLSignatureInput错误,完整栈信息如下:
java.lang.InstantiationError: org.apache.xml.security.signature.XMLSignatureInput
at org.apache.poi.poifs.crypt.dsig.services.RelationshipTransformService.transform(RelationshipTransformService.java:228) ~[poi-ooxml-5.2.5.jar:5.2.5]
at org.apache.jcp.xml.dsig.internal.dom.DOMTransform.transform(DOMTransform.java:150) ~[xmlsec-4.0.2.jar:4.0.2]
at org.apache.jcp.xml.dsig.internal.dom.DOMReference.transform(DOMReference.java:486) ~[xmlsec-4.0.2.jar:4.0.2]
at org.apache.jcp.xml.dsig.internal.dom.DOMReference.digest(DOMReference.java:387) ~[xmlsec-4.0.2.jar:4.0.2]
at org.apache.jcp.xml.dsig.internal.dom.DOMXMLSignature.digestReference(DOMXMLSignature.java:503) ~[xmlsec-4.0.2.jar:4.0.2]
at org.apache.jcp.xml.dsig.internal.dom.DOMXMLSignature.sign(DOMXMLSignature.java:389) ~[xmlsec-4.0.2.jar:4.0.2]
at org.apache.poi.poifs.crypt.dsig.SignatureInfo.preSign(SignatureInfo.java:413) ~[poi-ooxml-5.2.5.jar:5.2.5]
at org.apache.poi.poifs.crypt.dsig.SignatureInfo.confirmSignature(SignatureInfo.java:225) ~[poi-ooxml-5.2.5.jar:5.2.5]
at com.daimler.rde.importer.batch.steps.excel.creator.SignatureCreator.addSignatureToDocument(SignatureCreator.java:40) ~[classes/:?]
at com.daimler.rde.importer.batch.steps.excel.creator.ReportingFileExcelCreator.createExcelFile(ReportingFileExcelCreator.java:54) ~[classes/:?]
at com.daimler.rde.importer.batch.steps.excel.ReportingFileProcessor.process(ReportingFileProcessor.java:50) ~[classes/:?]
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.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:351) ~[spring-aop-6.1.5.jar:6.1.5]
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:196) ~[spring-aop-6.1.5.jar:6.1.5]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring...]
当前依赖配置(Maven)
<dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcprov-jdk18on</artifactId> <version>1.78.1</version> </dependency> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcpkix-jdk18on</artifactId> <version>1.78.1</version> </dependency> <dependency> <groupId>org.apache.santuario</groupId> <artifactId>xmlsec</artifactId> <version>4.0.2</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>5.2.5</version> </dependency>
签名核心代码
public byte[] addSignatureToDocument (byte[] excelFile) throws IOException, InvalidFormatException, XMLSignatureException, MarshalException, RdeSignatureException { InputStream in = new ByteArrayInputStream(excelFile); OPCPackage opcPackage = OPCPackage.open(in); SignatureConfig signatureConfig = certificateService.getSignatureConfig(); SignatureInfo si = new SignatureInfo(); si.setOpcPackage(opcPackage); si.setSignatureConfig(signatureConfig); si.confirmSignature(); //obtain signed document ByteArrayOutputStream os = new ByteArrayOutputStream(); opcPackage.save(os); return os.toByteArray(); }
问题原因与解决方案
原因
这个错误是POI版本与xmlsec版本不兼容导致的:
- POI 5.2.5依赖的xmlsec版本是2.3.0,但你使用了更高版本的xmlsec 4.0.2
- xmlsec 3.x及以上版本对
XMLSignatureInput类做了重大修改(比如从普通类改为抽象类,或构造方法变更),导致POI的RelationshipTransformService无法实例化该类
解决步骤
- 统一xmlsec版本为POI兼容版本:
修改Maven的xmlsec依赖,将版本改为2.3.0:<dependency> <groupId>org.apache.santuario</groupId> <artifactId>xmlsec</artifactId> <version>2.3.0</version> </dependency> - 排查并排除依赖冲突:
执行mvn dependency:tree命令,查看是否有其他依赖引入高版本xmlsec。如果有,通过<exclusions>标签排除冲突依赖:<dependency> <!-- 存在冲突的依赖 --> <groupId>xxx</groupId> <artifactId>xxx</artifactId> <exclusions> <exclusion> <groupId>org.apache.santuario</groupId> <artifactId>xmlsec</artifactId> </exclusion> </exclusions> </dependency> - 清理并重新构建项目:
执行mvn clean install,确保新依赖正确引入,旧的冲突jar包被移除
额外注意事项
- 如果需要使用xmlsec 3.x+的新特性,需升级POI到支持该版本的版本(可查看POI官方文档确认兼容的xmlsec版本)
- BouncyCastle 1.78.1与POI 5.2.5兼容,无需调整
内容的提问来源于stack exchange,提问作者Pallavi Ar

