1

I have an old war-file where the source code was lost as my old machine passed away.

It did run there with tomcat 8 with no problems.

On my new machine, when tomcat (8 as well as 9) tries to deploy the war file, it gives me

... 10 more Caused by: java.lang.ClassNotFoundException: javafx.scene.image.Image at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1358) at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1180) ... 23 more

I don't remember having used javafx in my code directly.

So, how to check imports of a *.war file to see which class or library causes the trouble?

I have tried javap on sample classes but never see any imports.

I am aware that javafx is no longer part of the runtime environment, which obviously is the immediate cause of the problem, but, for this application, javafx should not be needed at all.

Gyro Gearloose
  • 1,056
  • 1
  • 9
  • 26
  • 2
    Import statements are compile-time only mechanism. They are not part of the compiled byte code. – Seelenvirtuose May 10 '20 at 11:38
  • You can try to open your war and decompile the .class files. But, as you pointed, 'downgrading' your java or adding javafx to your tomcat should solve the problem without the need of checking the files. – Lucas Campos May 10 '20 at 11:39
  • @LucasCampos just as @ Seelenvirtuose noted, javap is not the tool for that. Are there any halfway official tools that can do the decompilation? – Gyro Gearloose May 10 '20 at 11:43
  • Run `javap -v -constants` on your .class files to see class references. You might want to pipe the output through `grep "= Class"` (Linux) or `findstr "=\ Class"` (Windows), or maybe just `grep javafx` / `findstr javafx`. – Andreas May 10 '20 at 11:44

2 Answers2

2

Run javap -v -constants on your .class files to see class references.

You might want to pipe the output through grep "= Class" (Linux) or findstr "=\ Class" (Windows), or maybe just grep javafx / findstr javafx.

E.g. even a super simple "Hello World" program uses multiple classes.

public class Test {
    public static void main(String[] args) {
        System.out.println("Hello World");
    }
}

Output

C:\path\to\classes\classes>javap -v -constants Test.class | grep "= Class"
   #1 = Class              #2             // Test
   #3 = Class              #4             // java/lang/Object
  #17 = Class              #18            // java/lang/System
  #25 = Class              #26            // java/io/PrintStream

It doesn't show the use of String. To see why, look at the full constant pool, which for that small program is:

Constant pool:
   #1 = Class              #2             // Test
   #2 = Utf8               Test
   #3 = Class              #4             // java/lang/Object
   #4 = Utf8               java/lang/Object
   #5 = Utf8               <init>
   #6 = Utf8               ()V
   #7 = Utf8               Code
   #8 = Methodref          #3.#9          // java/lang/Object."<init>":()V
   #9 = NameAndType        #5:#6          // "<init>":()V
  #10 = Utf8               LineNumberTable
  #11 = Utf8               LocalVariableTable
  #12 = Utf8               this
  #13 = Utf8               LTest;
  #14 = Utf8               main
  #15 = Utf8               ([Ljava/lang/String;)V
  #16 = Fieldref           #17.#19        // java/lang/System.out:Ljava/io/PrintStream;
  #17 = Class              #18            // java/lang/System
  #18 = Utf8               java/lang/System
  #19 = NameAndType        #20:#21        // out:Ljava/io/PrintStream;
  #20 = Utf8               out
  #21 = Utf8               Ljava/io/PrintStream;
  #22 = String             #23            // Hello World
  #23 = Utf8               Hello World
  #24 = Methodref          #25.#27        // java/io/PrintStream.println:(Ljava/lang/String;)V
  #25 = Class              #26            // java/io/PrintStream
  #26 = Utf8               java/io/PrintStream
  #27 = NameAndType        #28:#29        // println:(Ljava/lang/String;)V
  #28 = Utf8               println
  #29 = Utf8               (Ljava/lang/String;)V
  #30 = Utf8               args
  #31 = Utf8               [Ljava/lang/String;
  #32 = Utf8               SourceFile
  #33 = Utf8               Test.java

Since you don't need all the string constants, you could use grep -v Utf8:

   #1 = Class              #2             // Test
   #3 = Class              #4             // java/lang/Object
   #8 = Methodref          #3.#9          // java/lang/Object."<init>":()V
   #9 = NameAndType        #5:#6          // "<init>":()V
  #16 = Fieldref           #17.#19        // java/lang/System.out:Ljava/io/PrintStream;
  #17 = Class              #18            // java/lang/System
  #19 = NameAndType        #20:#21        // out:Ljava/io/PrintStream;
  #22 = String             #23            // Hello World
  #24 = Methodref          #25.#27        // java/io/PrintStream.println:(Ljava/lang/String;)V
  #25 = Class              #26            // java/io/PrintStream
  #27 = NameAndType        #28:#29        // println:(Ljava/lang/String;)V
Andreas
  • 154,647
  • 11
  • 152
  • 247
  • 1
    And for those who are impatient: find . -name '*.class' | xargs -i sh -c 'echo '{}': $(javap -v -constants '{}' | grep "= Class")' | grep javafx – Gyro Gearloose May 10 '20 at 12:07
0

The WAR archives are noting but compressed zip files. You can extract them using any tools like WinRar (In Windows ) or unzip (in Linux) or any tool you prefer. Once you extract you will get a directory and files of the archive. Inside this you will find all the additional libraries that you used and the class files , along with the static contents.

Dibsyhex
  • 119
  • 7