Uploaded image for project: 'Thorntail'
  1. Thorntail
  2. THORN-990

RuntimeDeployer does not put classes into correct location in archive

    Details

    • Type: Bug
    • Status: Closed (View Workflow)
    • Priority: Major
    • Resolution: Done
    • Affects Version/s: 2016.12.0
    • Fix Version/s: 2017.2.0
    • Component/s: core
    • Labels:
      None
    • Sprint:
      2017-Jan-B
    • Steps to Reproduce:
      Hide

      1) create pretty basic project with say just a REST resource and a dependency on jax-rs
      2) create another maven module which is in IntelliJ or Eclipse workspace, next to the first project
      3) create dependency in pom from application to this libary
      4) makek the REST resource use a class out of the library
      5) DO NOT do "mvn install" on the library!! (actually, that isn't important because the IDE will exclude the installed JAR in favour of <module-name>/target/classes
      6) start application using main method. the default Main should be OK.
      7) call the REST resource and watch the exception that is thrown. The class out of the library cannot be found

      Show
      1) create pretty basic project with say just a REST resource and a dependency on jax-rs 2) create another maven module which is in IntelliJ or Eclipse workspace, next to the first project 3) create dependency in pom from application to this libary 4) makek the REST resource use a class out of the library 5) DO NOT do "mvn install" on the library!! (actually, that isn't important because the IDE will exclude the installed JAR in favour of <module-name>/target/classes 6) start application using main method. the default Main should be OK. 7) call the REST resource and watch the exception that is thrown. The class out of the library cannot be found

      Description

      I've put some code into a maven module - call it a "library module".

      My Swarm application (also a maven module) depends on that module and calls a method from it.

      I write a unit test in the swarm module and it runs in JUnit successfully, including a call to the library. It is run from the IDE. But I haven't ever run "mvn install" in the library project

      It works, because IntelliJ knows how to set the classpath when the unit test runs. Some 3rd party libraries are added via their JARs from my local maven repo, other classes, namely those in the IntelliJ "workspace" are added to the classpath as class files.

      Now I start up my Swarm application and call some REST resource which calls the library. I get a NoClassDefFoundError or ClassNotFoundException or some other exception depending upon what I do.

      The reason seems to be because Swarm is building its own classpath at startup (because of the line "Dependencies not bundled, will resolve from local M2REPO" which it logs at startup).

      Based on https://www.mkyong.com/java/how-to-print-out-the-current-project-classpath/ I've tried logging the system classloader's URLs:

      /usr/java/jdk1.8.0_60/jre/lib/rt.jar
      ... lots of other JRE stuff
      /home/ant/.m2/repository/org/wildfly/swarm/jaxrs/2016.12.0/jaxrs-2016.12.0.jar
      /home/ant/.m2/repository/org/wildfly/swarm/container/2016.12.0/container-2016.12.0.jar
      ... logs of other Swarm/JBoss/Undertow stuff
      /home/ant/.m2/repository/org/wildfly/swarm/jaxrs-cdi/2016.12.0/jaxrs-cdi-2016.12.0.jar
      ...all kinds of other libraries used by Swarm or my application
      /home/ant/.m2/repository/org/bouncycastle/bcprov-jdk15on/1.52/bcprov-jdk15on-1.52.jar
      /w/tullia/swarm-demo/target/classes/
      /w/tullia/someservice/target/classes/
      /home/ant/Apps/intellij.2016.3/idea-IC-163.7743.44/lib/idea_rt.jar

      So, there they are, second and third last lines are the classes from my library module (someservice) and my swarm application (swarm-demo), note NOT from the local maven repo!

      But somehow only the swarm application (swarm-demo) is passed on to "swarm" and my library is being skipped.

      According to the docs (https://wildfly-swarm.gitbooks.io/wildfly-swarm-users-guide/content/implementation_details.html), when the main class is started from the IDE, "the first two classloaders are actually both satisfied by the system classloader". But the exception which is thrown is this one:

      Caused by: java.lang.ClassNotFoundException: ch.maxant.temp.service.SomeService33 from [Module "deployment.05bec469-12cd-4cf1-898f-f7daf8bc662a.war:main" from Service Module Loader]

      That suggests the problem is all down to a classloading problem because the service module loader cannot find the class.

      So something isn't right... this should be working without problems, no?

      I debugged into the deployment process.

      I use a Main class with new Swarm().start().deploy() which creates a default deployment which uses a MemoryMapArchiveBase. The content is filled as expected, and sure enough it even adds the classes out of the library JAR to WEB-INF:

      2017-01-10 22:25:48,508 ERROR [stderr] (main) BasicPath [context=/WEB-INF/lib/classes/ch/maxant/temp/service/SomeService33.class] // /WEB-INF/lib/classes/ch/maxant/temp/service/SomeService33.class
      2017-01-10 22:25:48,509 ERROR [stderr] (main) BasicPath [context=/WEB-INF/lib/classes] // /WEB-INF/lib/classes
      2017-01-10 22:25:48,509 ERROR [stderr] (main) BasicPath [context=/WEB-INF/lib/classes/ch] // /WEB-INF/lib/classes/ch
      2017-01-10 22:25:48,509 ERROR [stderr] (main) BasicPath [context=/WEB-INF/lib/classes/ch/maxant] // /WEB-INF/lib/classes/ch/maxant
      2017-01-10 22:25:48,510 ERROR [stderr] (main) BasicPath [context=/WEB-INF/lib/classes/ch/maxant/temp] // /WEB-INF/lib/classes/ch/maxant/temp
      2017-01-10 22:25:48,510 ERROR [stderr] (main) BasicPath [context=/WEB-INF/lib/classes/ch/maxant/temp/service] // /WEB-INF/lib/classes/ch/maxant/temp/service

      (ignore the ERROR, its just how the RuntimeDeployer in swarm logs it)

      BUT LOOK! It has added them to WEB-INF/lib/classes instead of just WEB-INF/classes.

      That is definitely the problem.

      RuntimeDeployer line 184 resolves dependency paths from the appEnv and correctly contains:

      /w/tullia/someservice/target/classes

      But it assumes it is a library even when it is a class. Line 186:

      depContainer.addAsLibraries(new File(path))

      And that causes it to be put under WEB-INF/lib instead of WEB-INF/classes.

        Gliffy Diagrams

          Attachments

            Issue Links

              Activity

                People

                • Assignee:
                  kenfinni Ken Finnigan
                  Reporter:
                  maxant Ant Kutschera
                • Votes:
                  0 Vote for this issue
                  Watchers:
                  1 Start watching this issue

                  Dates

                  • Created:
                    Updated:
                    Resolved: