代码之家  ›  专栏  ›  技术社区  ›  posdef

执行期间加载资源的问题

  •  5
  • posdef  · 技术社区  · 14 年前

    下面是潜在问题的背景,我正在与一个小组合作一个项目,该项目使用 Swt SWT 非常依赖于平台/架构。我想把六个都打包 jar 将s(linux、mac、win和32/64位)放入同一个包中,并根据系统使用相应的库。我意识到这是一个艰难的挑战,但是,转换到 Swing (或其他)现在不是一个真正的选择。

    我找到了一些相关的线索( @Aaron Digulla's thread @mchr's thread )这让我对手头的问题有了宝贵的见解。我试图实现@Alexey Romanov提出的解决方案 here . 有一点不同 loadSwtJar() 他提出的方法不是静态的,我实例化了对象,紧接着,在对对象做任何其他操作之前运行该方法。

    这似乎是因为加载程序不能正常工作。我对这一说法的理由如下:

    • 如果全部 Swt公司 jar从可执行jar文件的类路径中删除,然后 Exception in thread "main" java.lang.NoClassDefFoundError: org/eclipse/swt/events/MouseListener 是由以下原因引发的: java.lang.ClassNotFoundException: org.eclipse.swt.events.MouseListener

    • 如果 swt jar留在类路径上,然后系统在执行期间使用第一个jar文件。也就是说,如果gtk-linux-x86_64恰好是jar列表中的第一个swtjar,那么系统将尝试使用它,而不管系统是win32还是Mac OSX。

    我试图添加一些输出以查看 loadSwtJar() 方法正在选择正确的jar,并且输出似乎在我尝试过的所有平台上都是正确的,就像选择了正确的包一样(并且文件确实存在于runnable jar中)。但是,没有加载正确的库,因此会发生执行错误: Exception in thread "main" java.lang.reflect.InvocationTargetException 由以下原因引起: Caused by: java.lang.UnsatisfiedLinkError: Cannot load 32-bit SWT libraries on 64-bit JVM (注意,如果我更改了 build.xml

    那么,这里的问题是什么?我是否遗漏了一些细节,或者根本无法检查系统属性并相应地加载适当的库?

    最后,下面是我的构建文件的一个摘录,它可能有助于找到问题的根源。

    提前谢谢你,


    编辑: 在与同事进行了长时间的调试之后,问题就解决了(除了我提到的MacOS上的线程管理方面的一个恼人的错误 here ). 它涉及到调整ANT构建以及编写主类的方式。(事实证明,主类正在扩展和实现SWT库中的引用,这意味着代码根本无法编译,用另一个类包装主类,并从那里加载SWT jar,这似乎足以解决问题)

    感谢并问候所有贡献的人,特别是“亚伦”。非常感谢!

    2 回复  |  直到 7 年前
        1
  •  5
  •   Aaron Digulla    14 年前

    这是我主课的最新版本。如果这对你有用,请告诉我。我在Linux(32/64位)和Windows(32位)上测试了它。

    package de.pdark.epen.editor;
    
    import java.io.File;
    import java.lang.reflect.Constructor;
    import java.lang.reflect.Method;
    import java.net.URL;
    import java.net.URLClassLoader;
    
    import org.apache.commons.lang.SystemUtils;
    import org.apache.commons.lang.exception.ExceptionUtils;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    import ch.qos.logback.classic.LoggerContext;
    import ch.qos.logback.core.util.StatusPrinter;
    import de.pdark.epen.exceptions.WikiException;
    
    public class Main
    {
        public final static String VERSION = "V0.9 (13.05.2010)"; //$NON-NLS-1$
        private final static Logger log = LoggerFactory.getLogger (Main.class);
    
        private static final String ORG_ECLIPSE_SWT_WIDGETS_SHELL = "org.eclipse.swt.widgets.Shell"; //$NON-NLS-1$
    
        /**
        * @param args
        */
        @SuppressWarnings({"nls", "PMD.SystemPrintln"})
        public static void main (String[] args)
        {
            String msg = "Starting ePen "+VERSION;
            System.out.println (msg);
            log.info (msg);
    
            LoggerContext lc = (LoggerContext)LoggerFactory.getILoggerFactory ();
            StatusPrinter.print (lc);
    
            int rc = 1;
            try
            {
                Main main = new Main ();
                main.run (args);
                rc = 0;
            }
            catch (Throwable t) //NOPMD
            {
                ExceptionUtils.printRootCauseStackTrace (t);
            }
            finally
            {
                System.out.println ("Done.");
                log.info ("Exit {}", rc);
                System.exit (rc); //NOPMD
            }
        }
    
        @SuppressWarnings({"nls", "PMD.SystemPrintln", "PMD.SignatureDeclareThrowsException"})
        private void run (String[] args) throws Exception
        {
            if (!SystemUtils.isJavaVersionAtLeast (150))
            {
                System.out.println ("Version="+SystemUtils.JAVA_VERSION_INT);
                throw new WikiException ("Need at least Java 5 but this Java is only "+SystemUtils.JAVA_VERSION);
            }
    
            loadSwtJar ();
    
            URLClassLoader cl = (URLClassLoader) getClass().getClassLoader(); //NOPMD
            Class<?> c = cl.loadClass ("de.pdark.epen.editor.EPenEditor");
            Class<?> shellClass = cl.loadClass (ORG_ECLIPSE_SWT_WIDGETS_SHELL);
    
            Constructor<?> ctor = c.getConstructor (shellClass);
            Object obj = ctor.newInstance (new Object[] { null });
            Method run = c.getMethod ("run", args.getClass ()); //$NON-NLS-1$
            run.invoke (obj, new Object[] { args });
        }
    
        @SuppressWarnings({"nls", "PMD"})
        private void loadSwtJar ()
        {
            try {
                Class.forName (ORG_ECLIPSE_SWT_WIDGETS_SHELL);
                // Already on classpath
                return;
            } catch (ClassNotFoundException e) {
                // Add the JAR
            }
    
            String osName = SystemUtils.OS_NAME.toLowerCase ();
            String osArch = SystemUtils.OS_ARCH.toLowerCase ();
    
            String swtFileNameOsPart = 
                osName.contains("win") ? "win32" :
                osName.contains("mac") ? "macosx" :
                osName.contains("linux") || osName.contains("nix") ? "linux" :
                null;
            String swtFileNameUiPart = 
                osName.contains("win") ? "win32" :
                osName.contains("mac") ? "cocoa" :
                osName.contains("linux") || osName.contains("nix") ? "gtk" :
                null;
    
            if (null == swtFileNameOsPart)
            {
                throw new RuntimeException ("Can't determine name of SWT Jar from os.name=[" + osName + "] and os.arch=["
                        + osArch + "]");
            }
    
            String swtFileNameArchPart = osArch.contains ("64") ? ".x86_64" : ".x86";
            if(".x86".equals(swtFileNameArchPart) && "macosx".equals(swtFileNameOsPart)) {
                swtFileNameArchPart = "";
            }
    
            String swtFileName = "org.eclipse.swt." + swtFileNameUiPart + "." + swtFileNameOsPart + swtFileNameArchPart + "-3.6.0.jar";
            File file = new File ("swt", swtFileName);
            if (!file.exists ())
            {
                throw new RuntimeException ("Can't locate SWT Jar " + file.getAbsolutePath ());
            }
            try
            {
                URLClassLoader classLoader = (URLClassLoader) getClass ().getClassLoader ();
                Method addUrlMethod = URLClassLoader.class.getDeclaredMethod ("addURL", URL.class);
                addUrlMethod.setAccessible (true);
    
                URL swtFileUrl = file.toURI ().toURL ();
                log.info ("Adding {} to the classpath", swtFileUrl);
                addUrlMethod.invoke (classLoader, swtFileUrl);
            }
            catch (Exception e)
            {
                throw new RuntimeException ("Unable to add the swt jar to the class path: " + file.getAbsoluteFile (), e);
            }
        }
    }
    
        2
  •  0
  •   Eugene Kuleshov    14 年前

    您可以使用Java Web Start作为多平台SWT应用程序的引导机制。见a corresponding entry 在SWT FAQ中。