Uploaded image for project: 'Jenkins'
  1. Jenkins
  2. JENKINS-51965

Add support of JAXB unpackaging for Java 9+ in WAR Exploder

    XMLWordPrintable

    Details

    • Similar Issues:

      Description

      As discussed in JENKINS-51821, Jenkins won't work on Java 11 due to removed JAXB modules. I propose the following approach:

      • Package 3 JAXB libs (jaxb-api-2.3.0.jar, jaxb-core-2.3.0.1.jar, jaxb-impl-2.3.0.1.jar) to a WAR resource which does not get classloaded by default. E.g. "WEB-INF/platform-compat/java11" (or 9 ?)
      • When Jenkins starts up on Java 9+, Jenkins WAR exploder copies the libraries to "war/WEB-INF/lib" so that they get picked by classloader automatically

      It will allow to have a transparent support of Java 9..11 within the WAR file (without adding modules, etc.)

      A better way forward would be Multi-Version JAR, but we need a massive tooling update to support it

        Attachments

          Issue Links

            Activity

            Hide
            kohsuke Kohsuke Kawaguchi added a comment -

            "war exploder" is a Winstone local concept, so it isn't sufficient to make Jenkins work in other servlet containers, no?

             

            Why don't we just bundle JAXB in WEB-INF/lib instead?

            Show
            kohsuke Kohsuke Kawaguchi added a comment - "war exploder" is a Winstone local concept, so it isn't sufficient to make Jenkins work in other servlet containers, no?   Why don't we just bundle JAXB in WEB-INF/lib instead?
            Hide
            oleg_nenashev Oleg Nenashev added a comment -

            The recent JAXB versions require Java 9 or above.
            We we just bundle them, we won't be able to retain Java 8 compatibility in the same WARs.
            Shipping separate releases for Java 8 and Java 10+ is possible, but it is a serious overhead in terms of infrastructure changes needed.

            > "war exploder" is a Winstone local concept, so it isn't sufficient to make Jenkins work in other servlet containers, no?

            Yes, it will be limited to Jetty which is our "OOTB experience"
            For other Web containers keeping the module requirement is fine IMHO.

            Show
            oleg_nenashev Oleg Nenashev added a comment - The recent JAXB versions require Java 9 or above. We we just bundle them, we won't be able to retain Java 8 compatibility in the same WARs. Shipping separate releases for Java 8 and Java 10+ is possible, but it is a serious overhead in terms of infrastructure changes needed. > "war exploder" is a Winstone local concept, so it isn't sufficient to make Jenkins work in other servlet containers, no? Yes, it will be limited to Jetty which is our "OOTB experience" For other Web containers keeping the module requirement is fine IMHO.
            Hide
            oleg_nenashev Oleg Nenashev added a comment - - edited

            Kohsuke Kawaguchi We also have other options which may be preferable && compatible

            • Cleanup usages of JAXB from Jenkins Core and Modules (like you proposed)
            • Create a new JAXB API Plugin
              • The plugin is compatible with Java 8
              • The plugin implements multi-release JAR (will require tooling updates IIUC)
              • For Java 8 the plugin does nothing
              • For Java 9+ we bundle the libraries into the plugin
            • Release the plugin and mark it as detached from the core

            In such case we will have a clean WAR startup without JAXB modules + the plugin classloaders will be used to add the dependencies from JAXB API Plugin. It will allow running the approach in all Web containers.

            The main problem is that JAXB API Plugin will be present on many instances until we update all main plugins beyond the version with detached version. But it applies to all detached plugins so it should be fine

            WDYT?

            Show
            oleg_nenashev Oleg Nenashev added a comment - - edited Kohsuke Kawaguchi We also have other options which may be preferable && compatible Cleanup usages of JAXB from Jenkins Core and Modules (like you proposed) Create a new JAXB API Plugin The plugin is compatible with Java 8 The plugin implements multi-release JAR (will require tooling updates IIUC) For Java 8 the plugin does nothing For Java 9+ we bundle the libraries into the plugin Release the plugin and mark it as detached from the core In such case we will have a clean WAR startup without JAXB modules + the plugin classloaders will be used to add the dependencies from JAXB API Plugin. It will allow running the approach in all Web containers. The main problem is that JAXB API Plugin will be present on many instances until we update all main plugins beyond the version with detached version. But it applies to all detached plugins so it should be fine WDYT?
            Hide
            kohsuke Kohsuke Kawaguchi added a comment -

            Today we made a good progress on the proposed approach of detached JAXB plugin, but in the very end I discovered that this didn't work.

            The way plugins use JAXB makes JAXB to look up the implementation through thread context classloader, which is servlet classloader and not uber classloader. So it fails to find it. Plugins can invoke JAXB API a little differently, but it'd be nice if plugins need not make any changes.

            So after all that, I come full circle back to my original suggestion of just bundling JAXB in WEB-INF/lib. I discussed this with Paul, and this is a very common practice for JAXB, because JavaSE carries one version of it, EE container carries another version of it, and because those two platforms move very slowly, webapp often wants to use its own version of it. The servlet container is used to handle this kind of situation, and I'm saying this as a former JAXB RI & spec lead, so I know a thing or two about JAXB!

            We just need to bundle the version of JAXB that works with Java 8 (which is 2.2.x) in order to work in any Java 8+ runtime.

            I'll check in with Oleg tomorrow.

             

             

            Show
            kohsuke Kohsuke Kawaguchi added a comment - Today we made a good progress on the proposed approach of detached JAXB plugin, but in the very end I discovered that this didn't work. The way plugins use JAXB makes JAXB to look up the implementation through thread context classloader, which is servlet classloader and not uber classloader. So it fails to find it. Plugins can invoke JAXB API a little differently, but it'd be nice if plugins need not make any changes. So after all that, I come full circle back to my original suggestion of just bundling JAXB in WEB-INF/lib. I discussed this with Paul, and this is a very common practice for JAXB, because JavaSE carries one version of it, EE container carries another version of it, and because those two platforms move very slowly, webapp often wants to use its own version of it. The servlet container is used to handle this kind of situation, and I'm saying this as a former JAXB RI & spec lead, so I know a thing or two about JAXB! We just need to bundle the version of JAXB that works with Java 8 (which is 2.2.x) in order to work in any Java 8+ runtime. I'll check in with Oleg tomorrow.    
            Hide
            oleg_nenashev Oleg Nenashev added a comment -

            Kohsuke Kawaguchi works for me if it works without breaking on Java 8, 10 and 11
            I doubt we want to tweak plugin classloading even more to have this plugin working somehow.

            Show
            oleg_nenashev Oleg Nenashev added a comment - Kohsuke Kawaguchi works for me if it works without breaking on Java 8, 10 and 11 I doubt we want to tweak plugin classloading even more to have this plugin working somehow.
            Hide
            jglick Jesse Glick added a comment -

            thread context classloader, which is servlet classloader and not uber classloader

            I wonder if we should revisit that decision.

            Plugins can invoke JAXB API a little differently, but it'd be nice if plugins need not make any changes.

            Which plugins would actually be affected? It is maybe a five-line change to switch the thread context loader¹, and it would be nice to get JAXB out of core if we could.

            ¹And could be made even simpler with a utility in core:

            public final class WithJenkinsContextClassLoader implements AutoCloseable {
                private final Thread t;
                private final ClassLoader orig;
                public WithJenkinsContextClassLoader() {
                    this(Jenkins.get().getPluginManager().uberClassLoader);
                }
                public WithJenkinsContextClassLoader(Class<?> pluginClass) {
                    this(pluginClass.getClassLoader());
                }
                private WithJenkinsContextClassLoader(ClassLoader loader) {
                    t = Thread.currentThread();
                    orig = t.getContextClassLoader();
                    t.setContextClassLoader(loader);
                }
                @Override public void close() {
                    t.setContextClassLoader(orig);
                }
            }
            

            Thus:

            try (WithJenkinsContextClassLoader context = new WithJenkinsContextClassLoader(ThisClass.class)) {
                myUsageOfJAXB();
            }
            
            Show
            jglick Jesse Glick added a comment - thread context classloader, which is servlet classloader and not uber classloader I wonder if we should revisit that decision. Plugins can invoke JAXB API a little differently, but it'd be nice if plugins need not make any changes. Which plugins would actually be affected? It is maybe a five-line change to switch the thread context loader¹, and it would be nice to get JAXB out of core if we could. ¹And could be made even simpler with a utility in core: public final class WithJenkinsContextClassLoader implements AutoCloseable { private final Thread t; private final ClassLoader orig; public WithJenkinsContextClassLoader() { this (Jenkins.get().getPluginManager().uberClassLoader); } public WithJenkinsContextClassLoader( Class <?> pluginClass) { this (pluginClass.getClassLoader()); } private WithJenkinsContextClassLoader( ClassLoader loader) { t = Thread .currentThread(); orig = t.getContextClassLoader(); t.setContextClassLoader(loader); } @Override public void close() { t.setContextClassLoader(orig); } } Thus: try (WithJenkinsContextClassLoader context = new WithJenkinsContextClassLoader(ThisClass.class)) { myUsageOfJAXB(); }

              People

              • Assignee:
                kohsuke Kohsuke Kawaguchi
                Reporter:
                oleg_nenashev Oleg Nenashev
              • Votes:
                0 Vote for this issue
                Watchers:
                4 Start watching this issue

                Dates

                • Created:
                  Updated: