在用Ant编译的文件中找不到主类
我在Eclipse中编译和运行我的程序,一切正常,但是当我用Ant打包并运行它时,出现这个错误:
Exception in thread "main" java.lang.NoClassDefFoundError: org/supercsv/io/ICsvB eanReader Caused by: java.lang.ClassNotFoundException: org.supercsv.io.ICsvBeanReader at java.net.URLClassLoader$1.run(Unknown Source) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(Unknown Source) at java.lang.ClassLoader.loadClass(Unknown Source) at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source) at java.lang.ClassLoader.loadClass(Unknown Source) Could not find the main class: jab.jm.main.Test. Program will exit.
请注意,这是一个运行时错误,而不是Ant的编译器错误 。
我已经在过去build立了这个项目0个问题,现在当我添加第二个包到我的lib文件夹,它突然对我的行为 ?
这是构build文件供参考:
<?xml version="1.0" ?> <project name="ServerJar" default="dist" basedir="."> <description> Builds client files into .jar </description> <!-- [build variables] --> <property name="src" location="src" /> <property name="build" location="build" /> <property name="dist" location="dist" /> <property name="lib" location="lib" /> <!-- [path to packages] --> <path id="master-classpath"> <fileset dir="${lib}"> <include name="*.jar"/> </fileset> </path> <target name="init"> <!-- makes time stamp to be used in jar name --> <tstamp /> <!-- creates build directory structure --> <mkdir dir="${build}" /> </target> <target name="compile" depends="init" description="Compiles the source"> <!-- compiles the java code from ${src} into ${build} --> <!-- <javac srcdir="${src}" destdir="${build}" /> --> <javac destdir= "${build}"> <src path="${src}"/> <classpath refid="master-classpath"/> </javac> </target> <target name="dist" depends="compile" description="Generates distributable"> <!-- creates the distribution directory --> <mkdir dir="${dist}/lib" /> <!-- puts everything in ${build} into the jar file --> <jar jarfile="${dist}/lib/CC-${DSTAMP}.jar" basedir="${build}"> <manifest> <attribute name="Main-Class" value="jab.jm.main.Test" /> </manifest> </jar> <!-- makes a jar file for quick test execution --> <jar jarfile="${dist}/lib/CC.jar" basedir="${build}"> <manifest> <attribute name="Main-Class" value="jab.jm.main.Test" /> </manifest> </jar> </target> <target name="clean" description="Cleans up the extra build files"> <!-- deletes the ${build} and ${dist} directories --> <delete dir="${build}" /> <delete dir="${dist}" /> </target> </project>
先谢谢您的帮助!
编辑:
以下是我的主类的结构(这不是实际的文件,但这是我的基础)。 Java程序的构造非常奇怪,可能会给Ant一些问题。 任何关于如何重build的build议? 试图将其分成多个部分时,我遇到了一些错误。 我以前从来没有见过这样的构造(是的,我知道它是如何工作的(编译时会这么做),但Ant可能不喜欢它)。
import java.io.FileReader; import java.io.IOException; import org.supercsv.cellprocessor.Optional; import org.supercsv.cellprocessor.ParseDate; import org.supercsv.cellprocessor.ParseInt; import org.supercsv.cellprocessor.constraint.StrMinMax; import org.supercsv.cellprocessor.constraint.Unique; import org.supercsv.cellprocessor.ift.CellProcessor; import org.supercsv.io.CsvBeanReader; import org.supercsv.io.ICsvBeanReader; import org.supercsv.prefs.CsvPreference; class ReadingObjects { static final CellProcessor[] userProcessors = new CellProcessor[] { new Unique(new StrMinMax(5, 20)), new StrMinMax(8, 35), new ParseDate("dd/MM/yyyy"), new Optional(new ParseInt()), null }; public static void main(String[] args) throws Exception { ICsvBeanReader inFile = new CsvBeanReader(new FileReader("foo.csv"), CsvPreference.EXCEL_PREFERENCE); try { final String[] header = inFile.getCSVHeader(true); UserBean user; while( (user = inFile.read(UserBean.class, header, userProcessors)) != null) { System.out.println(user.getZip()); } } finally { inFile.close(); } } } public class UserBean { String username, password, town; Date date; int zip; public Date getDate() { return date; } public String getPassword() { return password; } public String getTown() { return town; } public String getUsername() { return username; } public int getZip() { return zip; } public void setDate(final Date date) { this.date = date; } public void setPassword(final String password) { this.password = password; } public void setTown(final String town) { this.town = town; } public void setUsername(final String username) { this.username = username; } public void setZip(final int zip) { this.zip = zip; } }
请注意,类的名称实际上是UserBean,它包含一个名为ReadingObjects的非公共类,它包含主方法。
看起来你的运行时类path缺less包含类org.supercsv.io.ICsvBeanReader的jar。
问题是,调用可执行jar时,不能从命令行设置类path。 您必须在清单中将其设置如下:
<target name="dist" depends="compile" description="Generates distributable"> <!-- creates the distribution directory --> <mkdir dir="${dist}/lib" /> <!-- Remove manifest. This jar will end up on the classpath of CC.jar --> <jar jarfile="${dist}/lib/CC-${DSTAMP}.jar" basedir="${build}"/> <!-- Fancy task that takes the pain out creating properly formatted manifest value --> <manifestclasspath property="mf.classpath" jarfile="${dist}/lib/CC.jar"> <classpath> <fileset dir="${dist}/lib" includes="*.jar"/> </classpath><!--end tag--> </manifestclasspath> <!-- This is the executable jar --> <jar jarfile="${dist}/lib/CC.jar" basedir="${build}"> <manifest> <attribute name="Main-Class" value="jab.jm.main.Test"/> <attribute name="Class-Path" value="${mf.classpath}"/> </manifest> </jar> </target>
这种方法将允许你如下运行jar:
java -jar CC.jar
没有额外的清单条目,你必须运行jar如下:
java -cp CC.jar:CC-DSTAMPVALUE.jar jab.jm.main.Test
注意
只有CC.jar是可执行的,需要特殊的清单。 使用这个模式意味着放在lib目录中的将来的附加jar会自动包含在运行时类path中。 (对于像log4j这样的开源相关性很有用)
显然,在运行CC.jar时,如果jar文件不存在,你会得到一个类似的错误:-)
你是否在运行jar的时候显式地指定了类path,以确保新的库在上面?
也许库1存在于默认的类path,所以你的项目运行良好,直到你添加库2,这是不存在的。 在Eclipse中运行时,IDE可能会自动将库2添加到类path中。 您可以在Eclipse中的项目运行configuration中检查类path,并确保在不通过IDE运行时包含所有内容。
这可能是由于生成的类文件的位置而发生的。 即当你build立一个通过eclipse的时候,它会在指定为ex:bin的Output文件夹的位置生成类文件,而在运行的时候,它会查看这个类文件的位置。
因此,检查您的ant是否在BuildPathconfiguration中提到的输出文件夹的相同位置生成类文件。 如果不将输出文件夹位置更改为您的ant正在生成类文件的位置 。