简体   繁体   中英

Running .jar file using Apache POI in Maven project

I'm struggling to run a simple program that uses Apache POI to create an Excel document. This is also my first time with a Maven project, so that might have something to do with it:

My pom.xml looks like this:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

  <modelVersion>4.0.0</modelVersion>
  <groupId>com.mycompany.app</groupId>
  <artifactId>calendar</artifactId>
  <packaging>jar</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>calendar</name>
  <url>http://maven.apache.org</url>

    <dependencies>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>3.8.1</version>
        <scope>test</scope>
    </dependency>

    <dependency>
          <groupId>org.apache.poi</groupId>
          <artifactId>poi</artifactId>
          <version>3.10-FINAL</version>
    </dependency>


    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi-ooxml</artifactId>
        <version>3.10-FINAL</version>
    </dependency>

  </dependencies>
</project>

From what I can tell, my dependencies are alright.

This is my java code, I skipped over import statements but they are all there, no errors in this code from what I can tell:

public class App 
{

    private static final String FILE_NAME = "/tmp/MyFirstExcel.xlsx";

    public static void main( String[] args ) throws IOException
    {
        XSSFWorkbook workbook = new XSSFWorkbook();
        XSSFSheet sheet = workbook.createSheet("Datatypes in Java");

        Object[][] datatypes = {
            {"Datatype", "Type", "Size(in bytes)"},
            {"int", "Primitive", 2},
            {"float", "Primitive", 4},
            {"double", "Primitive", 8},
            {"char", "Primitive", 1},
            {"String", "Non-Primitive", "No fixed size"}    
        };

        int rowNum = 0;
        System.out.println("Creating excel");
        for(Object[] datatype : datatypes) {
            Row row = sheet.createRow(rowNum++);
            int colNum = 0;
            for(Object field : datatype) {
                Cell cell = row.createCell(colNum++);
                if(field instanceof String) {
                    cell.setCellValue((String) field);
                }
                else if(field instanceof Integer) {
                    cell.setCellValue((Integer) field);
                }
            }
        }

        try {
            FileOutputStream outputStream = new FileOutputStream(FILE_NAME);
            workbook.write(outputStream);
            //workbook.close()
        } catch (FileNotFoundException e) {
            System.out.println("Couldn't find file to write out to");
        } catch (IOException e) {
            System.out.println("IO Exception in printing");
        }

    }
}

I have workbook.close() commented out since this caused an error (deprecated method?).

With the above code in my source folder, I can run mvn package which builds successfully and generates the .jar file calendar-1.0-SNAPSHOT.jar in the target folder.

I am attempting to run this file using

java -cp target/calendar-1.0-SNAPSHOT.jar com.mycompany.app.App

...and I get the following error message

Error: A JNI error has occurred, please check your installation and try again
Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/poi/ss/usermodel/Workbook
        at java.lang.Class.getDeclaredMethods0(Native Method)
        at java.lang.Class.privateGetDeclaredMethods(Unknown Source)
        at java.lang.Class.privateGetMethodRecursive(Unknown Source)
        at java.lang.Class.getMethod0(Unknown Source)
        at java.lang.Class.getMethod(Unknown Source)
        at sun.launcher.LauncherHelper.validateMainClass(Unknown Source)
        at sun.launcher.LauncherHelper.checkAndLoadMain(Unknown Source)
Caused by: java.lang.ClassNotFoundException: org.apache.poi.ss.usermodel.Workbook
        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)
        ... 7 more

If this question requires any more information let me know. I'm at a loss here.

You need to create a fat/uber jar with Maven Assembly Plugin. Which means create a Jar together with its dependency Jars into a single executable Jar file. When you run it then it would have all the dependencies available.

Add following plugin inside your POM

<build>
    <plugins>
        <!-- Maven Assembly Plugin -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-assembly-plugin</artifactId>
            <version>2.4.1</version>
            <configuration>
                <!-- get all project dependencies -->
                <descriptorRefs>
                    <descriptorRef>jar-with-dependencies</descriptorRef>
                </descriptorRefs>
                <!-- MainClass in mainfest make a executable jar -->
                <archive>
                  <manifest>
                    <mainClass>com.your.path.to.main.App</mainClass>
                  </manifest>
                </archive>

            </configuration>
            <executions>
              <execution>
                <id>make-assembly</id>
                                    <!-- bind to the packaging phase -->
                <phase>package</phase>
                <goals>
                    <goal>single</goal>
                </goals>
              </execution>
            </executions>
        </plugin>

    </plugins>
</build>

Run following:

mvn package

Two jar files will be created in the target folder.

calendar-1.0-SNAPSHOT.jar – Only your project classes
calendar-1.0-SNAPSHOT-with-dependencies.jar – Project and dependency classes in a single jar.

You can run it follwoing;

java -cp target/calendar-1.0-SNAPSHOT-with-dependencies.jarcom.mycompany.app.App

You can review the contents of calendar-1.0-SNAPSHOT-with-dependencies.jar

jar tf target/calendar-1.0-SNAPSHOT-with-dependencies.jar

You are packaging your maven artifact as a jar and by default a jar packaged by the maven jar plugin doesn't include the dependency jars with the built artifact. Whereas the missing class at runtime.

If you want to include dependency jars of your application inside your jar, you should use the maven assembly plugin and specify jar-with-dependencies for the descriptorRef parameter.

You could bind the assembly single goal execution to the package phase so that the mvn package execution that you are using actually creates automatically the expected jar.

<plugins>
  <plugin>
    <artifactId>maven-assembly-plugin</artifactId>
    <configuration>
      <archive>
        <manifest>
          <mainClass>YourMainClassPrefixedByItsPackage</mainClass>
        </manifest>
      </archive>
      <descriptorRefs>
        <descriptorRef>jar-with-dependencies</descriptorRef>
      </descriptorRefs>
    </configuration>
    <executions>
      <execution>
        <id>make-assembly</id> 
        <phase>package</phase> <!-- bind to the packaging phase -->
        <goals>
          <goal>single</goal>
        </goals>
      </execution>
    </executions>
  </plugin>

The problem is that at compile time POI libraries are available but not at run time. The reason why they are available is that they are in Maven Dependency. Also I don't see any build wrapper in your pom file. You will need to add a build wrapper to build jar file that you can run outside of your IDE.

Now coming back to your problem, either you need to add POI jar in your CLASSPATH environment variable so that java run-time can access it or build a fat jar including dependencies.

You can use this template to add a build wrapper in pom file to build jar with dependencies.

<build>
    <plugins>
      <plugin>
        <artifactId>maven-dependency-plugin</artifactId>
        <executions>
          <execution>
            <phase>install</phase>
            <goals>
              <goal>copy-dependencies</goal>
            </goals>
            <configuration>
              <outputDirectory>${project.build.directory}/lib</outputDirectory>
            </configuration>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>

Maven package task just packs compiled classes of your project into a single jar file. All 3rd party libraries are not included, that's why you're getting error - POI class is not found.

You should build a runnable jar file that includes all dependencies. Please, refer to this question - you should use some additional maven plugins to achieve that

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM