造成这种情况的原因是:java.lang.NoSuchMethodError:org.apache.poi.ss.usermodel.Workbook.sheetIterator()Ljava / ut il / Iterator;

时间:2017-04-04 12:00:19

标签: java web-services weblogic12c

我很难弄清楚这个错误的原因:

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;

奇怪的是这段代码可以在我的电脑上运行,适用于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。另外,我喜欢这种类型的错误通常意味着什么。

3 个答案:

答案 0 :(得分:0)

当JVM加载一个类并尝试将其链接到第二个类时,会发生此异常。第一个类的代码是针对第二个类的不同版本而不是已加载的代码编译的。具体来说,它希望第二类中的某些方法有一个签名,但它不存在该签名。

简而言之,您要么针对错误版本的POI进行了编译,要么在部署中使用/包含了错误的POI JAR文件。

答案 1 :(得分:0)

我认为存在一个问题,即您在类路径中有旧版本的POI,它可能与同样在类路径上的较新版本冲突,或者较新版本根本不在类路径上。 Workbook#sheetIterator()已添加到此提交中:https://github.com/apache/poi/commit/9647b62d1a13719b51a23e25fc508788d611732b,自版本3.13起可用

您必须确保Weblogic部署中的类路径上没有旧版本的POI。这包括您的WAR文件和任何Weblogic系统lib文件夹,无论它们是什么。

答案 2 :(得分:0)

感谢大家的帮助。这确实是类加载器问题。你可以这样找到:

  

在启动文件中添加java选项verbose:class。例如。使用   在startWebLogic.sh文件中的下面的条目(就在weblogic的开头上方   server)添加verbose:class。没有必要添加它   startWebLogic.sh文件。任何位置都没问题。请确保它是   在服务器启动期间被拿起。

     

export JAVA_OPTIONS =“$ {JAVA_OPTIONS} -verbose:class”

     

服务器重启后,stdout将包含有关类的信息   装了。

在我的情况下,有人将旧的POI库放入 的 / ORACLE // user_projects /域/%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 方法。在这种情况下,降级有点帮助:)