2016年5月20日 星期五

NoClassDefFoundError有時不是class找不到,而是其他問題

java.lang.NoClassDefFoundError, 一般只認為是因為某個class找不到, 但其實很多時候class是存在的, 而是在初始這個類的時候出現錯誤, 特別是static區塊出錯的時候, 這就必須深入這個類去除錯, 才能解決問題.

另外ClassLoader載入class出錯, 也會報java.lang.NoClassDefFoundError的錯誤


(The ClassLoader ran into an error while reading the class definition when trying to read the class. Put a try/catch inside your static initializer and look at the exception. )
使用try catch找出錯誤
static {
  try {

    ... your init code here

  } catch (Throwable t) {
    LOG.error("Failure during static initialization", t);
    throw t;
  }
}


而 ClassNotFoundException 比較可能是單純的class找不到的情況


以下這一篇個人認為講的還不錯

關於NoClassDefFoundError和ClassNotFoundException異常


2016/05/31 update

出現 NoClassDefFoundError : org.apache.tika.parse.xml.DcXMLParser

org.apache.tika.parse.xml.DcXMLParser明明是存在的, 所以深入追踪原始碼:


EpubParser epubParser = null;
if (type.equals("epub")) {

//NoClassDefFoundError出現在下面這一行
    epubParser = new EpubParser();
    epubParser.parse(inputstream, handler, metadata, pcontext);
}



找到 EpubParser 的原始碼:
public class EpubParser extends AbstractParser {
    private static final long serialVersionUID = 215176772484050550L;
    private static final Set SUPPORTED_TYPES 
= Collections.unmodifiableSet(new HashSet(Arrays.asList
(new MediaType[]{MediaType.application("epub+zip"), 
MediaType.application("x-ibooks+zip")})));

//DcXMLParser 找不到
    private Parser meta = new DcXMLParser();
    private Parser content = new EpubContentParser();

    public EpubParser() {
    }

    public Parser getMetaParser() {
        return this.meta;
    }

    public void setMetaParser(Parser meta) {
        this.meta = meta;
    }

    public Parser getContentParser() {
        return this.content;
    }

    public void setContentParser(Parser content) {
        this.content = content;
    }

    public Set getSupportedTypes(ParseContext context) {
// 在這一行出錯, 但這是最後一行返回值, 可見不是這一行的原因, 而是上
//方定義 private Parser meta = new DcXMLParser();時出錯
        return SUPPORTED_TYPES;
    }



找出 DcXMLParser 的原始碼:
原來是下面有幾個import的元件未加入library中, 
將未加入的部分加入就解決了

import org.apache.tika.metadata.Metadata;
import org.apache.tika.metadata.Property;
import org.apache.tika.metadata.TikaCoreProperties;
import org.apache.tika.parser.ParseContext;
import org.apache.tika.parser.xml.ElementMetadataHandler;
import org.apache.tika.parser.xml.XMLParser;
import org.apache.tika.sax.TeeContentHandler;
import org.xml.sax.ContentHandler;

public class DcXMLParser extends XMLParser {
    private static final long serialVersionUID = 4905318835463880819L;

    public DcXMLParser() {
    }

    private static ContentHandler getDublinCoreHandler(Metadata metadata, Property property, String element) {
        return new ElementMetadataHandler("http://purl.org/dc/elements/1.1/", element, metadata, property);
    }

    protected ContentHandler getContentHandler(ContentHandler handler, Metadata metadata, ParseContext context) {
        return new TeeContentHandler(new ContentHandler[]{super.getContentHandler(handler, metadata, context), getDublinCoreHandler(metadata, TikaCoreProperties.TITLE, "title"), getDublinCoreHandler(metadata, TikaCoreProperties.KEYWORDS, "subject"), getDublinCoreHandler(metadata, TikaCoreProperties.CREATOR, "creator"), getDublinCoreHandler(metadata, TikaCoreProperties.DESCRIPTION, "description"), getDublinCoreHandler(metadata, TikaCoreProperties.PUBLISHER, "publisher"), getDublinCoreHandler(metadata, TikaCoreProperties.CONTRIBUTOR, "contributor"), getDublinCoreHandler(metadata, TikaCoreProperties.CREATED, "date"), getDublinCoreHandler(metadata, TikaCoreProperties.TYPE, "type"), getDublinCoreHandler(metadata, TikaCoreProperties.FORMAT, "format"), getDublinCoreHandler(metadata, TikaCoreProperties.IDENTIFIER, "identifier"), getDublinCoreHandler(metadata, TikaCoreProperties.LANGUAGE, "language"), getDublinCoreHandler(metadata, TikaCoreProperties.RIGHTS, "rights")});
    }
}
2016/06/01 update
令天又遇到一個 NoClassDefFoundError 的問題
基本上與昨天遇到的問題差不多, 同樣是 import 的地方沒把 class 加進來而出問題. 
但今天的問題, 即使把 import 的地方的 class 加進來, 一樣報錯. 

NoClassDefFoundError錯誤的是這個 org.apache.tika.io.TikaInputStream class
追踪TikaInputStream 的原始碼:


package org.apache.tika.io;

//以下三個 import 的class 都加入了, 仍然報錯
import org.apache.tika.io.TaggedInputStream;
import org.apache.tika.io.TemporaryResources;
import org.apache.tika.metadata.Metadata;

//原來問題出在 TaggedInputStream , 因為 TikaInputStream 是繼承 TaggedInputStream
//所以要把 TaggedInputStream 的原始碼也挖出來看
 
public class TikaInputStream extends TaggedInputStream {
    private static final int BLOB_SIZE_THRESHOLD = 1048576;
    private Path path;
    private final TemporaryResources tmp;
    private long length;
    private long position = 0L;

//TikaInputStream 以下原始碼省略...

}


TaggedInputStream 的原始碼:

//把以下兩個 class 加入(ProxyInputStream及TaggedIOException), 就解決了, 
//所以不止看出問題的 class, 如果它繼承自別的 class , 連父類的 class 
//也要查看是否有import 的 class 未加入.
import org.apache.tika.io.ProxyInputStream;
import org.apache.tika.io.TaggedIOException;

public class TaggedInputStream extends ProxyInputStream {
    private final Serializable tag = UUID.randomUUID();

    public TaggedInputStream(InputStream proxy) {
        super(proxy);
    }


還有一種情況:所有的 import 都己加入 library 中, 但在程碼中, 卻直接引用
class 如下面的 org.apache.xmlbeans.SchemaComponent.Ref 也要加進來


public void setContainerFieldRef(org.apache.xmlbeans.SchemaComponent.Ref ref) {
    this.assertUnresolved();
    this._containerFieldRef = ref;
    this._containerFieldCode = 0;
}

  © Blogger templates Psi by Ourblogtemplates.com 2008

Back to TOP