What causes this: java.lang.NoSuchMethodError: org.apache.poi.ss.usermodel.Workbook.sheetIterator()Ljava/util/Iterator;
What causes this: java.lang.NoSuchMethodError: org.apache.poi.ss.usermodel.Workbook.sheetIterator()Ljava/util/Iterator;
我很难找出这个错误的原因:
org.apache.poi.ss.usermodel.Workbook.sheetIterator()Ljava/util/Iterator;
我有 JAX-WS 服务,使用 POI 解析 Excel 文件。服务在 Weblogic 服务器上运行。这是 Weblogic 响应:
The selected operation convert could not be invoked.
A fault occurred while invoking the webservice operation. The fault is : <ns0:Fault xmlns:ns0="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://www.w3.org/2003/05/soap-envelope">
<faultcode>ns0:Server</faultcode>
<faultstring>org.apache.poi.ss.usermodel.Workbook.sheetIterator()Ljava/util/Iterator;</faultstring>
</ns0:Fault>
oracle.sysman.emInternalSDK.webservices.util.SoapTestException: Client received SOAP Fault from server : org.apache.poi.ss.usermodel.Workbook.sheetIterator()Ljava/util/Iterator;
奇怪的是这段代码在我的 PC 上工作,在 Weblogic 11g 上工作,但在 Weblogic 12c 上不工作
@WebService
public class Excel2XMLConverter {
@WebMethod
public @WebResult(name = "convertedData") String convert(@WebParam(name = "excelData") byte[] data) throws Exception{
System.setProperty("org.apache.poi.util.POILogger", "org.apache.poi.util.NullLogger");
BufferedInputStream bfs = new BufferedInputStream(new ByteArrayInputStream(data));
Workbook wb = WorkbookFactory.create(new ByteArrayInputStream(data));
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.newDocument();
doc.createElementNS("http://namespace.org", "wb:workbook");
Element workbookElement = doc.createElementNS("http://namespace.org", "workbook");
workbookElement.setPrefix("wb");
doc.appendChild(workbookElement);
for(Iterator<Sheet> i = wb.sheetIterator(); i.hasNext();){
Element sheetElement = doc.createElementNS("http://namespace.org", "sheet");
sheetElement.setPrefix("wb");
workbookElement.appendChild(sheetElement);
Sheet sheet = i.next();
for(Iterator<Row> j = sheet.rowIterator(); j.hasNext(); ){
Row row = j.next();
Element rowElement = doc.createElementNS("http://namespace.org", "row");
rowElement.setPrefix("wb");
sheetElement.appendChild(rowElement);
for(Iterator<Cell> k = row.cellIterator(); k.hasNext(); ){
Cell cell = k.next();
cell.setCellType(CellType.STRING);
Element cellElement = doc.createElementNS("http://namespace.org", "cell");
cellElement.setPrefix("wb");
cellElement.setAttribute("value", cell.getStringCellValue());
rowElement.appendChild(cellElement);
}
}
}
StringWriter sw = new StringWriter();
TransformerFactory tf = TransformerFactory.newInstance();
Transformer transformer = tf.newTransformer();
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
transformer.setOutputProperty(OutputKeys.METHOD, "xml");
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
transformer.transform(new DOMSource(doc), new StreamResult(sw));
return sw.toString();
}
无论如何,我认为这个错误与代码无关,因为它仅在 Weblogic 12c 上不起作用。另外,我想知道这种类型的错误通常意味着什么。
当 JVM 加载一个 class 并尝试将其 link 加载到第二个 class 时,会发生此异常。第一个 class 的代码是针对与加载的版本不同的第二个 class 版本编译的。具体来说,它期望第二个 class 中的某些方法具有一个签名,但它不存在具有该签名的方法。
简而言之,您要么针对错误版本的 POI 进行了编译,要么在部署中使用/包含了错误的 POI JAR 文件。
我认为您的类路径中有旧版本的 POI,它可能与也在类路径中的新版本冲突,或者新版本根本不在类路径中。在此提交中添加了 Workbook#sheetIterator():https://github.com/apache/poi/commit/9647b62d1a13719b51a23e25fc508788d611732b 并且自版本 3.13
起可用
您必须确保您的 Weblogic 部署中的类路径中没有旧版本的 POI。这包括您的 WAR 文件和任何 Weblogic 系统库文件夹,无论它们是什么。
感谢大家的帮助。那确实是类加载器问题。您可以通过以下方式找到:
Add the java options verbose:class in startup file. For eg. Use the
below entry in startWebLogic.sh file (just above the start of weblogic
server) to add the verbose:class. It's not necessary to add it in
startWebLogic.sh file. Any location is fine. Please make sure it's
getting picked up during server startup.
export JAVA_OPTIONS="${JAVA_OPTIONS} -verbose:class"
After server reboot, stdout will contain information about how classes
are loaded.
就我而言,有人将旧的 POI 库放入
/oracle//user_projects/domains/%domain_name%/lib。
此目录中的 JAR 会自动添加到 CLASSPATH。
但这还不是全部。由于 Weblogic 使用 Apache Commons Net,因此该库也存储在服务器上:
[Loaded org.apache.commons.net.SocketClient from file:/oracle/<server_name>/wlserver/modules/commons-net.commons-net.jar]
[Loaded org.apache.commons.net.ftp.FTP from file:/oracle/<server_name>/wlserver/modules/commons-net.commons-net.jar]
[Loaded org.apache.commons.net.ftp.FTPClient from file:/oracle/<server_name>/wlserver/modules/commons-net.commons-net.jar]
[Loaded org.apache.commons.net.ftp.FTPHTTPClient from file:/oracle/<server_name>/user_projects/domains/<domain_name>/servers/soa_server1/dc/soa_02656c56-2df4-449a-b79e-ae2f074f34a1/SCA-INF/lib/commons-net-3.5.jar]
因此,虽然 FTPHTTPClient 取自修订版 3.5,但 SocketClient 有点旧,因此 FTPHTTPClient 引用的代码不存在(尚未) SocketClient 方法。在这种情况下降级有点帮助:)
我很难找出这个错误的原因:
org.apache.poi.ss.usermodel.Workbook.sheetIterator()Ljava/util/Iterator;
我有 JAX-WS 服务,使用 POI 解析 Excel 文件。服务在 Weblogic 服务器上运行。这是 Weblogic 响应:
The selected operation convert could not be invoked.
A fault occurred while invoking the webservice operation. The fault is : <ns0:Fault xmlns:ns0="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://www.w3.org/2003/05/soap-envelope">
<faultcode>ns0:Server</faultcode>
<faultstring>org.apache.poi.ss.usermodel.Workbook.sheetIterator()Ljava/util/Iterator;</faultstring>
</ns0:Fault>
oracle.sysman.emInternalSDK.webservices.util.SoapTestException: Client received SOAP Fault from server : org.apache.poi.ss.usermodel.Workbook.sheetIterator()Ljava/util/Iterator;
奇怪的是这段代码在我的 PC 上工作,在 Weblogic 11g 上工作,但在 Weblogic 12c 上不工作
@WebService
public class Excel2XMLConverter {
@WebMethod
public @WebResult(name = "convertedData") String convert(@WebParam(name = "excelData") byte[] data) throws Exception{
System.setProperty("org.apache.poi.util.POILogger", "org.apache.poi.util.NullLogger");
BufferedInputStream bfs = new BufferedInputStream(new ByteArrayInputStream(data));
Workbook wb = WorkbookFactory.create(new ByteArrayInputStream(data));
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.newDocument();
doc.createElementNS("http://namespace.org", "wb:workbook");
Element workbookElement = doc.createElementNS("http://namespace.org", "workbook");
workbookElement.setPrefix("wb");
doc.appendChild(workbookElement);
for(Iterator<Sheet> i = wb.sheetIterator(); i.hasNext();){
Element sheetElement = doc.createElementNS("http://namespace.org", "sheet");
sheetElement.setPrefix("wb");
workbookElement.appendChild(sheetElement);
Sheet sheet = i.next();
for(Iterator<Row> j = sheet.rowIterator(); j.hasNext(); ){
Row row = j.next();
Element rowElement = doc.createElementNS("http://namespace.org", "row");
rowElement.setPrefix("wb");
sheetElement.appendChild(rowElement);
for(Iterator<Cell> k = row.cellIterator(); k.hasNext(); ){
Cell cell = k.next();
cell.setCellType(CellType.STRING);
Element cellElement = doc.createElementNS("http://namespace.org", "cell");
cellElement.setPrefix("wb");
cellElement.setAttribute("value", cell.getStringCellValue());
rowElement.appendChild(cellElement);
}
}
}
StringWriter sw = new StringWriter();
TransformerFactory tf = TransformerFactory.newInstance();
Transformer transformer = tf.newTransformer();
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
transformer.setOutputProperty(OutputKeys.METHOD, "xml");
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
transformer.transform(new DOMSource(doc), new StreamResult(sw));
return sw.toString();
}
无论如何,我认为这个错误与代码无关,因为它仅在 Weblogic 12c 上不起作用。另外,我想知道这种类型的错误通常意味着什么。
当 JVM 加载一个 class 并尝试将其 link 加载到第二个 class 时,会发生此异常。第一个 class 的代码是针对与加载的版本不同的第二个 class 版本编译的。具体来说,它期望第二个 class 中的某些方法具有一个签名,但它不存在具有该签名的方法。
简而言之,您要么针对错误版本的 POI 进行了编译,要么在部署中使用/包含了错误的 POI JAR 文件。
我认为您的类路径中有旧版本的 POI,它可能与也在类路径中的新版本冲突,或者新版本根本不在类路径中。在此提交中添加了 Workbook#sheetIterator():https://github.com/apache/poi/commit/9647b62d1a13719b51a23e25fc508788d611732b 并且自版本 3.13
起可用您必须确保您的 Weblogic 部署中的类路径中没有旧版本的 POI。这包括您的 WAR 文件和任何 Weblogic 系统库文件夹,无论它们是什么。
感谢大家的帮助。那确实是类加载器问题。您可以通过以下方式找到:
Add the java options verbose:class in startup file. For eg. Use the below entry in startWebLogic.sh file (just above the start of weblogic server) to add the verbose:class. It's not necessary to add it in startWebLogic.sh file. Any location is fine. Please make sure it's getting picked up during server startup.
export JAVA_OPTIONS="${JAVA_OPTIONS} -verbose:class"
After server reboot, stdout will contain information about how classes are loaded.
就我而言,有人将旧的 POI 库放入 /oracle//user_projects/domains/%domain_name%/lib。 此目录中的 JAR 会自动添加到 CLASSPATH。
但这还不是全部。由于 Weblogic 使用 Apache Commons Net,因此该库也存储在服务器上:
[Loaded org.apache.commons.net.SocketClient from file:/oracle/<server_name>/wlserver/modules/commons-net.commons-net.jar]
[Loaded org.apache.commons.net.ftp.FTP from file:/oracle/<server_name>/wlserver/modules/commons-net.commons-net.jar]
[Loaded org.apache.commons.net.ftp.FTPClient from file:/oracle/<server_name>/wlserver/modules/commons-net.commons-net.jar]
[Loaded org.apache.commons.net.ftp.FTPHTTPClient from file:/oracle/<server_name>/user_projects/domains/<domain_name>/servers/soa_server1/dc/soa_02656c56-2df4-449a-b79e-ae2f074f34a1/SCA-INF/lib/commons-net-3.5.jar]
因此,虽然 FTPHTTPClient 取自修订版 3.5,但 SocketClient 有点旧,因此 FTPHTTPClient 引用的代码不存在(尚未) SocketClient 方法。在这种情况下降级有点帮助:)