1

We are building an application using ScalaFX. When I run the project in IntelliJIDEA, everything works fine. However, when I create jar file and try to execute it, I am getting errors in reading some xml file. I tried various solutions posted in SO, but with no use.

package com.app.adt

import scalafx.application.JFXApp
import scalafx.Includes._
import scalafx.scene.Scene
import scala.reflect.runtime.universe.typeOf
import scalafxml.core.{FXMLView, DependenciesByType}

object App extends JFXApp {

  val root = FXMLView(getClass.getResource("/com/app/adt/Home.fxml"),
    new DependenciesByType(Map(
      typeOf[TestDependency] -> new TestDependency("ADT"))))

  stage = new JFXApp.PrimaryStage() {
    title = "ADT"
    scene = new Scene(root)
  }
}

The xml file(Home.fxml) is placed in com/app/adt package. I am creating the jar file using sbt-one-jar.

I have tried different combinations of path, but alwasys gives the same error.

Error Stack:

Caused by: javafx.fxml.LoadException:
file:/adt-app_2.11-1.3-SNAPSHOT-one-jar.jar!/main/adt-app_2.11-1.3-S
NAPSHOT.jar!/com/app/adt/Home.fxml

        at javafx.fxml.FXMLLoader.constructLoadException(FXMLLoader.java:2611)
        at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2589)
        at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2435)
        at javafx.fxml.FXMLLoader.load(FXMLLoader.java:2403)
        at scalafxml.core.FXMLView$.apply(FXMLView.scala:17)

Jar Structure:

adt-app_2.11-1.3-SNAPSHOT-one-jar.jar
   |
   main
       |
       adt-app_2.11-1.3-SNAPSHOT.jar
            |
             com\app\adt
                       |
                       App.scala
                       Home.fxml

Also, I have tried with sbt-assembly instead of sbt-one-jar. But , still getting the same error. :(

Tried with below answers in SO:

Q1

Q2

Community
  • 1
  • 1
Yadu Krishnan
  • 3,492
  • 5
  • 41
  • 80
  • Well, this is very interesting - I'm using very similar code and `getResourceAsStream` which is mentioned in Q1 works well for me (using `sbt-assembly`). I suggest you to set up a new blank application without JavaFX and try to load the XML resource. In case it doesn't work you have a simpler problem to deal with. If it works, the problem might be JavaFX. In that case you know more about the problem. For now I can't help you more then suggest further problem analysis :) – petrbel May 15 '15 at 14:05
  • @petrbel, getResourceAsStream works for me as well. But the ScalaFX method expects a URL, and not a stream. For that, I used getResource. That is what giving the problem :( – Yadu Krishnan May 15 '15 at 14:09
  • I see, I provide an longer explanation as an answer - hope it clarifies it :) – petrbel May 15 '15 at 14:38

1 Answers1

0

The real problem is rather tricky. Firstly, one needs to realize that JAR is an archive (e.g. similar to ZIP) and archives are regular files. Thus the archive itself is located somewhere in the file system, hence, it is accessible via URL.

On the contrary, the "subfiles" (entries) are just data-block within the archive. Neither the operating system nor the JVM knows that this particular file is an archive therefore they treat is as a regular file.

If you're interested in deeper archive handling, try to figure out how ZipFile works. JAR is basically ZIP so you're able to apply this class to it.

Java provides Class.getResourceAsStream methods that enables the programmer to read files as streams. This solution is obviously useless in this particular example since the ScalaFX method expects the File instead.

So basically you have three options

  1. Use the stream API in order to duplicate the XML into temporary file, than pass this file to the method.
  2. Deploy your resources separately in a way they remain regular files.
  3. Re-implement JavaFX in order to accept streams (this should probably happen anyway)
petrbel
  • 2,428
  • 5
  • 29
  • 49