Програмно създаване на Runnable JAR, който има външни JAR от GUI?

Имам проста програма за тестване, която има един бутон. Когато потребител щракне върху бутона, програмата трябва да създаде Runnable JAR. Runnable JAR е проста програма, която отваря google.com във Firefox. Програмата има три класа.


1) Main.java

 package test;

    public class Main {

        public static void main(String[] args) {

            Selenium.getGoogle();

        }

    } 

2) Selenium.Java

package test;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;

public class Selenium {

    public static void getGoogle () {
        WebDriver driver = new FirefoxDriver();
        driver.get("http://google.com");
    }

}

3) TestGUI.java

package test;

import javax.swing.*;
import javax.tools.JavaCompiler;
import javax.tools.ToolProvider;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;


public class TestGUI extends JFrame implements ActionListener {

    private static final long serialVersionUID = 1L;

    public TestGUI() {

        setSize(200, 100);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setVisible(true);
        /*
         * JButton.
         */
        JButton startButton = new JButton("Create Runnable JAR file ! ");
        add(startButton);
        startButton.addActionListener(this);
    }


    public static void main(String[] args) {
        new TestGUI();
    }


    public void actionPerformed(ActionEvent e) {
        System.out.println("The Button Works");
        String file1ToCompile = "test" + java.io.File.separator + "Main.java";

        String file2ToCompile = "test" + java.io.File.separator + "Selenium.java";

        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();

        int compilationResult = compiler.run(null, null, null, file1ToCompile, file2ToCompile);

        if (compilationResult == 0) {

            System.out.println("Compilation is successful");

        } else {
            System.out.println("Compilation Failed");
        }
    }
}

Имам два основни класа. Добавих TestGUI.java към манифеста, така че GUI ще се покаже. След като потребител щракне върху бутона, искам моята програма да създаде Runnable JAR, който се състои от Main.java и Selenium.java.

Въпреки това получавам грешка null pointer exception за int compilationResult = compiler.run(null, null, null, file1ToCompile, file2ToCompile);

Как мога да направя това?


person Aleksei Nikolaevich    schedule 07.02.2014    source източник
comment
stackoverflow.com/questions/10237903/   -  person Robert Harvey    schedule 08.02.2014
comment
Това не е дубликат. Всъщност зададох този въпрос въз основа на отговора на stackoverflow.com/posts/21639695/edit   -  person Aleksei Nikolaevich    schedule 08.02.2014
comment
Тогава си оправи заглавието. Това е точно същото като другата публикация.   -  person Robert Harvey    schedule 08.02.2014
comment
@Robert Harvey Моля, премахнете отметката му, сякаш е дубликат. Прочетох този отговор и този урок. Не успях да намеря отговор как да се справя с пакетирани класове и външни буркани, затова задавам този въпрос   -  person Aleksei Nikolaevich    schedule 08.02.2014
comment
Какъв е вашият въпрос?   -  person Robert Harvey    schedule 08.02.2014
comment
Добре, ще оправя заглавието   -  person Aleksei Nikolaevich    schedule 08.02.2014
comment
Въпросът за правенето на буркани от буркани ли е, или е за изключението за нулев указател, което получавате в дъното на въпроса? Като цяло решавате изключенията за нулев указател, като премахнете условието, което причинява това, което препращате, да бъде нулево.   -  person Robert Harvey    schedule 08.02.2014
comment
Предполагам, че става въпрос за създаване на JAR от JAR. Прочетох внимателно урока и основно копирах кода от там. Много е просто. Нямам представа защо не работи. Предполагам, че класът TestGUI.java работи САМО когато нямаме външни буркани като Selenium   -  person Aleksei Nikolaevich    schedule 08.02.2014
comment
Ако този ред от код, който сте поставили като грешка, е правилен, изглежда, че вашата променлива compiler е нула. Така че, когато се опитате да извикате .run() на него, той хвърля изключение, защото няма никой вкъщи. Трябва да се опитате да донесете малко повече на партито; не можете наистина да копирате/поставите някакъв код от интернет, който не разбирате, и след това да очаквате да ви обясним как работи.   -  person Robert Harvey    schedule 08.02.2014
comment
Веднъж е как се пишат единици. Опитах се да редактирам публикацията, за да поправя печатната грешка, но SO не ми позволи, защото промяната е незначителна. Може би е така в знаците, но времето, необходимо на мозъка да обработи това, което има предвид, а не казаното, не е толкова малко, поне за някой с ОКР! :)   -  person axiopisty    schedule 13.02.2014
comment
Каква IDE използвате?   -  person Sionnach733    schedule 13.02.2014
comment
NPE се случва най-вероятно, защото използвате JRE вместо JDK и ToolProvider.getSystemJavaCompiler(); връща null вместо екземпляра на компилатора.   -  person gadget    schedule 14.02.2014
comment
Не е свързано с въпроса, но трябва да избягвате "test" + java.io.File.separator + "Main.java". Това е грешка, която чака да се случи. Използвайте new File(new File("test"), "Main.java"). Или поне използвайте System.getProperty(file.separator).   -  person Paul Hicks    schedule 16.02.2014
comment
Не е ли програмното създаване ... от GUI оксиморон?   -  person Stephen C    schedule 20.02.2014


Отговори (2)


Ето е отговорът O.o най-накрая го намери!! просто трябва да видите по този начин последната част от кода:

File folder = new File("C://Users//YourUser//YourWorkspace//YourProject//bin");
File[] files = folder.listFiles();
File file=new File("C://Users//YourUser//Desktop//Examples.jar");
person Federico Contreras    schedule 05.05.2014

Получавате NullPointerException най-вероятно, защото използвате JRE, а не JDK. Изтеглете JDK и го добавете към пътя за изграждане .

Второ, вие просто компилирате файловете. След това трябва да създадете jar файл и да добавите .class файловете към него. важно е те да имат еднаква структура на опаковката в буркана. В буркана ще ви трябва още:

Манифестен файл

Зависещи буркани

Програма за зареждане на класове

Файлът на манифеста описва кой клас съдържа метода main и информация за пътя на класа. Зависимите буркани (селен) също трябва да присъстват по очевидни причини. за зареждане на класовете в зависимия буркан е необходимо средство за зареждане на класове. по-долу е моето изпълнение:

public void actionPerformed(ActionEvent e){
        System.out.println("The Button Works");
        String file1ToCompile = "src" + java.io.File.separator + "test" + java.io.File.separator + "Main.java";
        String file2ToCompile = "src" + java.io.File.separator + "test" + java.io.File.separator + "Selenium.java";
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        int compilationResult = compiler.run(null, null, null, file1ToCompile, file2ToCompile);
        if (compilationResult == 0) {
            System.out.println("Compilation is successful");
        } else {
            System.out.println("Compilation Failed");
        }

        Manifest manifest = new Manifest();
        manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0");
        manifest.getMainAttributes().put(new Name("Rsrc-Class-Path"), "./ selenium-server-standalone-2.39.0.jar");
        manifest.getMainAttributes().put(Attributes.Name.CLASS_PATH, ".");
        manifest.getMainAttributes().put(new Name("Rsrc-Main-Class"), "test.Main");
        manifest.getMainAttributes().put(Attributes.Name.MAIN_CLASS, "org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader");
        try{
            JarOutputStream target = new JarOutputStream(new FileOutputStream("output.jar"), manifest);
            add(new File("src" + java.io.File.separator + "test" + java.io.File.separator + "Main.class"), target);
            add(new File("src" + java.io.File.separator + "test" + java.io.File.separator + "Selenium.class"), target);
            add(new File("org"), target);
            add(new File("selenium-server-standalone-2.39.0.jar"), target);
            target.close();
        }catch(Exception ex){
            ex.printStackTrace();
        }
    }

    private void add(File source, JarOutputStream target) throws IOException
    {
        BufferedInputStream in = null;
        try
        {
            if (source.isDirectory())
            {
                String name = source.getPath().replace("\\", "/");
                if (!name.isEmpty())
                {
                    if (!name.endsWith("/"))
                        name += "/";
                    JarEntry entry = new JarEntry(name);
                    entry.setTime(source.lastModified());
                    target.putNextEntry(entry);
                    target.closeEntry();
                }
                for (File nestedFile: source.listFiles())
                    add(nestedFile, target);
                return;
            }

            JarEntry entry = null;

            if(source.getPath().contains("jarinjarloader")){
                entry = new JarEntry(source.getPath());
            }
            else if(source.getName().endsWith(".class")){
                entry = new JarEntry("test/"+source.getName());
            }else if(source.getName().endsWith(".classpath")){
                entry = new JarEntry(source.getName());
            }else if(source.getName().endsWith(".jar")){
                entry = new JarEntry(source.getName());
            }
            entry.setTime(source.lastModified());
            target.putNextEntry(entry);
            in = new BufferedInputStream(new FileInputStream(source));

            byte[] buffer = new byte[1024];
            while (true)
            {
                int count = in.read(buffer);
                if (count == -1)
                    break;
                target.write(buffer, 0, count);
            }
            target.closeEntry();
        }
        finally
        {
            if (in != null)
                in.close();
        }
    }

Използвах jarinjarloader на Eclipse за моя classloader, който получих чрез създаване на изпълняващ се буркан в eclipse и извличане на папката org и копиране в моята директория на проекта.

въведете описание на изображението тук

Има малък проблем с това, но подозирам, че пропускам нещо малко. output.jar ще работи добре, ако файловете на classloader са в същата директория като jar. В момента се опитвам да поправя това, така че да може да намери програмата за зареждане на класове от буркана.

person Sionnach733    schedule 14.02.2014
comment
ТОВА не е правилно. Отговорът работи само от папката. Това не е истински JAR - person CHEBURASHKA; 17.02.2014
comment
@ЧЕБУРАШКА Това го обясних в края на отговора си. Работя, за да го поправя, имате ли някакви мисли? - person Sionnach733; 17.02.2014