如何将MigLayout for JavaFX转换为OSGi包,使其在OSGi容器中工作?

如何将MigLayout for JavaFX转换为OSGi包,使其在OSGi容器中工作?,javafx,osgi,apache-felix,equinox,miglayout,Javafx,Osgi,Apache Felix,Equinox,Miglayout,我正在尝试制作一个OSGi包,它是一个用JavaFX编写的GUI。我的设置如下: OS name: "linux", version: "3.8.0-25-generic", arch: "amd64", family: "unix" Java version: 1.7.0_45, vendor: Oracle Corporation Apache Maven 3.1.1 (0728685237757ffbf44136acec0402957f723d9a; 2013-09-17 10:22:22

我正在尝试制作一个OSGi包,它是一个用JavaFX编写的GUI。我的设置如下:

OS name: "linux", version: "3.8.0-25-generic", arch: "amd64", family: "unix"
Java version: 1.7.0_45, vendor: Oracle Corporation
Apache Maven 3.1.1 (0728685237757ffbf44136acec0402957f723d9a; 2013-09-17 10:22:22-0500)
我按照javafxmaven插件提供的说明进行操作。我使用ApacheFelix作为OSGi容器。所有这些结合在一起效果相当不错。(即:我可以将javafxgui创建为一个OSGi包,它可以工作!)

我遇到的问题是JavaFX的MigLayout库。我正在使用这些依赖项:

<dependency>
  <groupId>com.miglayout</groupId>
  <artifactId>miglayout-core</artifactId>
  <version>4.2</version>
</dependency>
<dependency>
  <groupId>com.miglayout</groupId>
  <artifactId>miglayout-javafx</artifactId>
  <version>4.2</version>
</dependency>
下面是我尝试加载的示例fxml文件login.fxml:

<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.StackPane?>
<?import javafx.scene.control.Button?>
<?import org.tbee.javafx.scene.layout.fxml.MigPane?>
<StackPane xmlns:fx="http://javafx.com/fxml" fx:controller="client.view.LoginView" fx:id="pane">
  <children>
    <Button text="Login" fx:id="loginButton" onAction="#login"/>
  </children>
</StackPane>
miglayout-core-4.2.jar MANIFEST.MF:

Manifest-Version: 1.0
Archiver-Version: Plexus Archiver
Bnd-LastModified: 1384015623755
Build-Jdk: 1.6.0_29
Built-By: Mike
Bundle-ManifestVersion: 2
Bundle-Name: miglayout.core
Bundle-SymbolicName: miglayout.core
Bundle-Version: 0
Created-By: 1.7.0_45 (Oracle Corporation)
Export-Package: net.miginfocom.layout
Originally-Created-By: Apache Maven
Tool: Bnd-2.1.0.20130426-122245
Manifest-Version: 1.0
Archiver-Version: Plexus Archiver
Bnd-LastModified: 1384015600603
Build-Jdk: 1.6.0_29
Built-By: Mike
Bundle-ManifestVersion: 2
Bundle-Name: miglayout.javafx
Bundle-SymbolicName: miglayout.javafx
Bundle-Version: 0
Created-By: 1.7.0_45 (Oracle Corporation)
Export-Package: org.tbee.javafx.scene.layout;uses:="javafx.scene,javafx.
 scene.layout,net.miginfocom.layout",org.tbee.javafx.scene.layout.fxml;u
 ses:="javafx.beans,javafx.scene,net.miginfocom.layout,org.tbee.javafx.s
 cene.layout"
Import-Package: javafx.beans;resolution:=optional,javafx.collections;res
 olution:=optional,javafx.geometry;resolution:=optional,javafx.scene;res
 olution:=optional,javafx.scene.control;resolution:=optional,javafx.scen
 e.layout;resolution:=optional,javafx.scene.paint;resolution:=optional,j
 avafx.scene.shape;resolution:=optional,javafx.stage;resolution:=optiona
 l,net.miginfocom.layout;resolution:=optional
Originally-Created-By: Apache Maven
Tool: Bnd-2.1.0.20130426-122245
miglayout-javafx-4.2.jar MANIFEST.MF:

Manifest-Version: 1.0
Archiver-Version: Plexus Archiver
Bnd-LastModified: 1384015623755
Build-Jdk: 1.6.0_29
Built-By: Mike
Bundle-ManifestVersion: 2
Bundle-Name: miglayout.core
Bundle-SymbolicName: miglayout.core
Bundle-Version: 0
Created-By: 1.7.0_45 (Oracle Corporation)
Export-Package: net.miginfocom.layout
Originally-Created-By: Apache Maven
Tool: Bnd-2.1.0.20130426-122245
Manifest-Version: 1.0
Archiver-Version: Plexus Archiver
Bnd-LastModified: 1384015600603
Build-Jdk: 1.6.0_29
Built-By: Mike
Bundle-ManifestVersion: 2
Bundle-Name: miglayout.javafx
Bundle-SymbolicName: miglayout.javafx
Bundle-Version: 0
Created-By: 1.7.0_45 (Oracle Corporation)
Export-Package: org.tbee.javafx.scene.layout;uses:="javafx.scene,javafx.
 scene.layout,net.miginfocom.layout",org.tbee.javafx.scene.layout.fxml;u
 ses:="javafx.beans,javafx.scene,net.miginfocom.layout,org.tbee.javafx.s
 cene.layout"
Import-Package: javafx.beans;resolution:=optional,javafx.collections;res
 olution:=optional,javafx.geometry;resolution:=optional,javafx.scene;res
 olution:=optional,javafx.scene.control;resolution:=optional,javafx.scen
 e.layout;resolution:=optional,javafx.scene.paint;resolution:=optional,j
 avafx.scene.shape;resolution:=optional,javafx.stage;resolution:=optiona
 l,net.miginfocom.layout;resolution:=optional
Originally-Created-By: Apache Maven
Tool: Bnd-2.1.0.20130426-122245
但是将生成的“bundle”放在OSGi容器中并不能解决问题。我也犯了同样的错误

我不知道还能尝试什么,这样我就可以使用OSGi容器中的MigLayout库了

我需要做什么才能在OSGi容器中使用MigLayout

编辑

下面是加载FXML的代码。它是用Scala编写的

package client

import _root_.javafx.application.Application
import _root_.javafx.stage.Stage
import _root_.javafx.scene.{Parent, Scene}
import _root_.javafx.fxml.FXMLLoader
import client.view.{Login, Screen}

class Gui extends Application {
  def start(stage: Stage) {
    val initialScreen: Screen = Login
    stage.setTitle("GUI")
    val loader = new FXMLLoader
    loader.setLocation(initialScreen.url)
    try {
      val root: Parent = loader.load(initialScreen.inputStream).asInstanceOf[Parent]
      val scene: Scene = new Scene(root, 800, 600)
      scene.getStylesheets.add("/fxml/styles/styles.css")
      stage.setScene(scene)
      stage.show()
    } catch {
      case t: Throwable => t.printStackTrace()
    }
  }

  override def stop() {
    System.out.println("Stopping JavaFX Application")
    Container.shutdown()
  }
}
另外,这里是为客户端定义的导入包。这个构建实际上是使用scala和osgi插件与gradle一起完成的

build.gradle的代码片段:

def importPackages =
  '  akka.actor' +
    ', akka.actor.dungeon' +
    ', akka.event' +
    ', akka.osgi' +
    ', javafx.application' +
    ', javafx.beans' +
    ', javafx.collections' +
    ', javafx.fxml' +
    ', javafx.geometry' +
    ', javafx.scene' +
    ', javafx.scene.control' +
    ', javafx.scene.image' +
    ', javafx.scene.layout' +
    ', javafx.scene.paint' +
    ', javafx.scene.shape' +
    ', javafx.stage' +
    ', net.miginfocom.layout' +
    ', org.osgi.framework' +
    ', org.tbee.javafx.scene.layout' +
    ', org.tbee.javafx.scene.layout.fxml' +
    ', scala' +
    ', scala.collection' +
    ', scala.reflect' +
    ', scala.runtime'

jar {
  manifest {
    name = "client (OSGi bundle)"

    instruction 'Bundle-Vendor', 'Company'
    instruction 'Bundle-Description', 'Client (OSGi bundle)'

    instruction 'Private-Package', 'client'
    instruction 'Bundle-Activator', 'client.ClientActivator'

    instruction 'Import-Package', importPackages
  }
}
def importPackages =
  '  akka.actor' +
    ', akka.actor.dungeon' +
    ', akka.event' +
    ', akka.osgi' +
    ', javafx.application' +
    ', javafx.beans' +
    ', javafx.collections' +
    ', javafx.fxml' +
    ', javafx.geometry' +
    ', javafx.scene' +
    ', javafx.scene.control' +
    ', javafx.scene.image' +
    ', javafx.scene.layout' +
    ', javafx.scene.paint' +
    ', javafx.scene.shape' +
    ', javafx.stage' +
    ', net.miginfocom.layout' +
    ', org.osgi.framework' +
    ', org.tbee.javafx.scene.layout' +
    ', org.tbee.javafx.scene.layout.fxml' +
    ', scala' +
    ', scala.collection' +
    ', scala.reflect' +
    ', scala.runtime'
编辑2

我根据tomsontom的建议修改了加载fxml的代码,以设置类加载器。以下是更新的代码:

build.gradle中的代码段:

def importPackages =
  '  akka.actor' +
    ', akka.actor.dungeon' +
    ', akka.event' +
    ', akka.osgi' +
    ', javafx.application' +
    ', javafx.beans' +
    ', javafx.collections' +
    ', javafx.fxml' +
    ', javafx.geometry' +
    ', javafx.scene' +
    ', javafx.scene.control' +
    ', javafx.scene.image' +
    ', javafx.scene.layout' +
    ', javafx.scene.paint' +
    ', javafx.scene.shape' +
    ', javafx.stage' +
    ', net.miginfocom.layout' +
    ', org.osgi.framework' +
    ', org.tbee.javafx.scene.layout' +
    ', org.tbee.javafx.scene.layout.fxml' +
    ', scala' +
    ', scala.collection' +
    ', scala.reflect' +
    ', scala.runtime'

jar {
  manifest {
    name = "client (OSGi bundle)"

    instruction 'Bundle-Vendor', 'Company'
    instruction 'Bundle-Description', 'Client (OSGi bundle)'

    instruction 'Private-Package', 'client'
    instruction 'Bundle-Activator', 'client.ClientActivator'

    instruction 'Import-Package', importPackages
  }
}
def importPackages =
  '  akka.actor' +
    ', akka.actor.dungeon' +
    ', akka.event' +
    ', akka.osgi' +
    ', javafx.application' +
    ', javafx.beans' +
    ', javafx.collections' +
    ', javafx.fxml' +
    ', javafx.geometry' +
    ', javafx.scene' +
    ', javafx.scene.control' +
    ', javafx.scene.image' +
    ', javafx.scene.layout' +
    ', javafx.scene.paint' +
    ', javafx.scene.shape' +
    ', javafx.stage' +
    ', net.miginfocom.layout' +
    ', org.osgi.framework' +
    ', org.tbee.javafx.scene.layout' +
    ', org.tbee.javafx.scene.layout.fxml' +
    ', scala' +
    ', scala.collection' +
    ', scala.reflect' +
    ', scala.runtime'
fxml加载代码:

  def start(stage: Stage) {
    val initialScreen: Screen = Login
    stage.setTitle("GUI")
    val loader = new FXMLLoader
    loader.setClassLoader(getClass.getClassLoader)
    loader.setLocation(initialScreen.url)
    try {
      val root: Parent = loader.load(initialScreen.inputStream).asInstanceOf[Parent]
      val scene: Scene = new Scene(root, 800, 600)
      scene.getStylesheets.add("/fxml/styles/styles.css")
      stage.setScene(scene)
      stage.show()
    } catch {
      case t: Throwable => t.printStackTrace()
    }
  }
但请注意,现在在OSGi容器中运行应用程序时,我收到了一条类似但不同的错误消息:

<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.StackPane?>
<?import javafx.scene.control.Button?>
<!--<?import org.tbee.javafx.scene.layout.fxml.MigPane?>-->
<StackPane xmlns:fx="http://javafx.com/fxml" fx:controller="client.view.LoginView" fx:id="pane">
  <children>
    <Button text="Login" fx:id="loginButton" onAction="#login"/>
  </children>
</StackPane>
javafx.fxml.LoadException: java.lang.ClassNotFoundException: org.tbee.javafx.scene.layout.fxml.MigPane
    at javafx.fxml.FXMLLoader.importClass(FXMLLoader.java:2489)
    at javafx.fxml.FXMLLoader.processImport(FXMLLoader.java:2333)
    at javafx.fxml.FXMLLoader.processProcessingInstruction(FXMLLoader.java:2301)
    at javafx.fxml.FXMLLoader.load(FXMLLoader.java:2154)
    at client.Gui.start(Gui.scala:23)
    at com.sun.javafx.application.LauncherImpl$5.run(LauncherImpl.java:319)
    at com.sun.javafx.application.PlatformImpl$5.run(PlatformImpl.java:216)
    at com.sun.javafx.application.PlatformImpl$4$1.run(PlatformImpl.java:179)
    at com.sun.javafx.application.PlatformImpl$4$1.run(PlatformImpl.java:176)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.javafx.application.PlatformImpl$4.run(PlatformImpl.java:176)
    at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:76)
    at com.sun.glass.ui.gtk.GtkApplication._runLoop(Native Method)
    at com.sun.glass.ui.gtk.GtkApplication$3$1.run(GtkApplication.java:89)
    at java.lang.Thread.run(Thread.java:744)
Caused by: java.lang.ClassNotFoundException: org.tbee.javafx.scene.layout.fxml.MigPane
    at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:425)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:358)
    at org.apache.felix.framework.ExtensionManager$ExtensionManagerWiring.getClassByDelegation(ExtensionManager.java:873)
    at org.apache.felix.framework.BundleWiringImpl.searchImports(BundleWiringImpl.java:1553)
    at org.apache.felix.framework.BundleWiringImpl.findClassOrResourceByDelegation(BundleWiringImpl.java:1484)
    at org.apache.felix.framework.BundleWiringImpl.access$400(BundleWiringImpl.java:75)
    at org.apache.felix.framework.BundleWiringImpl$BundleClassLoader.loadClass(BundleWiringImpl.java:1955)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:358)
    at javafx.fxml.FXMLLoader.loadTypeForPackage(FXMLLoader.java:2557)
    at javafx.fxml.FXMLLoader.loadType(FXMLLoader.java:2546)
    at javafx.fxml.FXMLLoader.importClass(FXMLLoader.java:2487)
    ... 14 more
它仍在生成ClassNotFoundException。但这一次,堆栈跟踪不包括任何与跟踪来自哪个包有关的内容。这是一个微妙的区别,我不知道这意味着什么。有什么想法吗

编辑3

在使用bnd命令行实用程序之后,我修改了OP,以包含为这两个MigLayout依赖项生成的MANIFEST.MF文件

编辑4

client.jar MANIFEST.MF (请注意,我的包实际上是x.x.client,而不仅仅是client。但是我已经从包名中删除了x.x.,这就是这个MANIFEST.MF文件中行距不一致的原因):

编辑5

我创建了一个,你可以下载看看问题。正如当前签入的一样,如果您按照文件README.txt中的说明进行操作,则在签出该项目后,该项目应立即运行


如果您想查看我在MigLayout库中遇到的问题,请通过取消对MigPane导入的注释来编辑文件
client/src/main/resources/fxml/login.fxml
。重建项目,将新创建的client-1.0.0-SNAPSHOT.jar复制到
app/bundle/
目录,使用
$rm-rf app/felix cache/
清除felix缓存目录,然后使用命令
$java-jar bin/felix.jar

app
目录中重新启动felix启动器。您还需要在UI包中包含相应的导入包语句。创建这些文件的最简单方法是在UI包的pom中使用


无论您是否使用bundle插件,都要检查生成的清单,以确保所有nevassery Import包语句都存在。

我99%确定在fxml中,您的问题是没有设置正确的类加载器。请显示您的fxml加载代码

是的,我应该在OP中包含该代码。我在客户端捆绑包中有导入语句。我不明白为什么它不起作用。唯一的另一个想法是,可能midlayout核心没有Import-Package语句,而异常发生在一个miglayout核心类中,当然它使用自己的类加载器。这不会产生不同的错误消息吗,有关无法将捆绑包连接在一起的问题?如果存在导入包语句,但没有捆绑包导出它,则会发生有关解析失败的错误。如果缺少Import-Package语句,但该包仍在使用,则会出现运行时ClassNotFoundException,如您的情况。好的,我看到您已更新,是的,您需要在fxmlloader实例上调用setClassloader。如果您考虑一下,您的代码在OSGi中必须失败,因为FXMLLoader位于extclassloader中,而extclassloader自然不知道OSGi捆绑包中的migpane。我应该将哪个类装入器传递给setClassloader?在OSGi包中它来自哪里?保存加载代码的包必须依赖于migpane,然后传递这个包。如果在java类中实现fxml文件中的内容,您需要考虑如何配置包,因此您还应该导入所有javafx包!您将获得一个类加载器,它是getClass()。getClassloader()谢谢您的帮助。我认为这几乎解决了,但它仍然造成了一个问题。请参阅我再次更新了OP。您没有显示ui包的清单。我建议从纯java/scala开始,然后向其中添加fxml