This was fixed by adding "--add-opens=java.base/java.lang=ALL-UNNAMED". Now all applications are running, and various other issues have been fixed by other "--add-opens" arguments. So these and the last couple of issues are related to Java 17 and not the classloader code above.
Can a Tomcat expert comment on the approach and code to customise the classpath as per the thread topic - I'll repeat here for clarity: Add Dependency: <dependency> <groupId>org.apache.tomcat</groupId> <artifactId>tomcat-catalina</artifactId> <version>${tomcat.version}</version> </dependency> Java List<ClassLoaderFactory.Repository> repositories = new ArrayList<>(); repositories.add(new ClassLoaderFactory.Repository(new File("/dir1").getAbsolutePath(), ClassLoaderFactory.RepositoryType.DIR)); repositories.add(new ClassLoaderFactory.Repository(new File("sub-mod1/target/classes").getAbsolutePath(), ClassLoaderFactory.RepositoryType.DIR)); repositories.add(new ClassLoaderFactory.Repository(new File("sub-mod2/target/classes").getAbsolutePath(), ClassLoaderFactory.RepositoryType.DIR)); File[] files = new File("lib-runtime").listFiles(); for (File file : files) { repositories.add(new ClassLoaderFactory.Repository(file.getAbsolutePath(), ClassLoaderFactory.RepositoryType.JAR)); } ClassLoader myClassLoader = ClassLoaderFactory.createClassLoader(repositories, null); Thread.currentThread().setContextClassLoader(myClassLoader); SecurityClassLoad.securityClassLoad(myClassLoader); ... Tomcat tomcat = new Tomcat(); tomcat.getService().setParentClassLoader(myClassLoader); On Wed, Dec 21, 2022 at 4:20 PM Tim N <tnti...@gmail.com> wrote: > After sorting out the new dependencies (I think) 2 of the 3 web-apps are > now running! > > One fails at startup with > Caused by: java.lang.LinkageError: loader java.net.URLClassLoader > @2328c243 attempted duplicate class definition for > mypackage.MyUserDetailsService$$EnhancerBySpringCGLIB$$f761e392. > (mypackage.MyUserDetailsService$$EnhancerBySpringCGLIB$$f761e392 is in > unnamed module of loader java.net.URLClassLoader @2328c243, parent loader > 'app') > at java.base/java.lang.ClassLoader.defineClass0(Native Method) > at java.base/java.lang.System$2.defineClass(System.java:2307) > at > java.base/java.lang.invoke.MethodHandles$Lookup$ClassDefiner.defineClass(MethodHandles.java:2439) > at > java.base/java.lang.invoke.MethodHandles$Lookup$ClassDefiner.defineClass(MethodHandles.java:2416) > at > java.base/java.lang.invoke.MethodHandles$Lookup.defineClass(MethodHandles.java:1843) > at java.base/jdk.internal.reflect.GeneratedMethodAccessor71.invoke(Unknown > Source) > at > java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) > at java.base/java.lang.reflect.Method.invoke(Method.java:568) > at > org.springframework.cglib.core.ReflectUtils.defineClass(ReflectUtils.java:576) > > > On Wed, Dec 21, 2022 at 3:33 PM Tim N <tnti...@gmail.com> wrote: > >> Sorry - more of the stack-trace: >> Caused by: java.lang.IllegalAccessError: failed to access class >> com.sun.activation.registries.LogSupport from class >> javax.activation.MimetypesFileTypeMap >> (com.sun.activation.registries.LogSupport and >> javax.activation.MimetypesFileTypeMap are in unnamed module of loader >> java.net.URLClassLoader @2328c243) >> at >> javax.activation.MimetypesFileTypeMap.<init>(MimetypesFileTypeMap.java:100) >> at >> javax.activation.MimetypesFileTypeMap.<init>(MimetypesFileTypeMap.java:271) >> at >> org.springframework.mail.javamail.ConfigurableMimeFileTypeMap.createFileTypeMap(ConfigurableMimeFileTypeMap.java:150) >> >> On Wed, Dec 21, 2022 at 3:28 PM Tim N <tnti...@gmail.com> wrote: >> >>> I tried this: >>> >>> List<ClassLoaderFactory.Repository> repositories = new ArrayList<>(); >>> repositories.add(new ClassLoaderFactory.Repository(new >>> File("/dir1").getAbsolutePath(), ClassLoaderFactory.RepositoryType.DIR)); >>> repositories.add(new ClassLoaderFactory.Repository(new >>> File("sub-mod1/target/classes").getAbsolutePath(), >>> ClassLoaderFactory.RepositoryType.DIR)); >>> repositories.add(new ClassLoaderFactory.Repository(new >>> File("sub-mod2/target/classes").getAbsolutePath(), >>> ClassLoaderFactory.RepositoryType.DIR)); >>> File[] files = new File("lib-runtime").listFiles(); >>> for (File file : files) { >>> repositories.add(new >>> ClassLoaderFactory.Repository(file.getAbsolutePath(), >>> ClassLoaderFactory.RepositoryType.JAR)); >>> } >>> >>> ClassLoader myClassLoader = >>> ClassLoaderFactory.createClassLoader(repositories, null); >>> >>> Thread.currentThread().setContextClassLoader(myClassLoader); >>> SecurityClassLoad.securityClassLoad(myClassLoader); >>> ... >>> Tomcat tomcat = new Tomcat(); >>> tomcat.getService().setParentClassLoader(myClassLoader); >>> >>> And am currently getting this: >>> java.util.concurrent.ExecutionException: >>> org.apache.catalina.LifecycleException: Failed to start component >>> [StandardEngine[Tomcat].StandardHost[localhost].StandardContext[]] >>> at java.base/java.util.concurrent.FutureTask.report(FutureTask.java:122) >>> at java.base/java.util.concurrent.FutureTask.get(FutureTask.java:191) >>> at >>> org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:923) >>> at >>> org.apache.catalina.core.StandardHost.startInternal(StandardHost.java:835) >>> at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183) >>> at >>> org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1393) >>> at >>> org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1383) >>> at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) >>> at >>> org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecutorService.java:75) >>> at >>> java.base/java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:145) >>> at >>> org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:916) >>> at >>> org.apache.catalina.core.StandardEngine.startInternal(StandardEngine.java:265) >>> at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183) >>> at >>> org.apache.catalina.core.StandardService.startInternal(StandardService.java:430) >>> at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183) >>> at >>> org.apache.catalina.core.StandardServer.startInternal(StandardServer.java:930) >>> at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183) >>> at org.apache.catalina.startup.Tomcat.start(Tomcat.java:486) >>> >>> So the code looks closer to working, but still something major wrong. >>> >>> On Wed, Dec 21, 2022 at 11:02 AM Tim N <tnti...@gmail.com> wrote: >>> >>>> > The custom class loader approach described in one of the answers is a >>>> > viable option. >>>> >>>> Thanks. >>>> >>>> > No. The same class loader hierarchy isn't constructed when running in >>>> > embedded mode. >>>> >>>> It looks like I would need to replicate all the classloading >>>> capabilities of Tomcat (e.g. loading classes from files and JARs). Any tips >>>> for implementing this? >>>> >>>> It looks like the Tomcat classloader code is available via >>>> https://mvnrepository.com/artifact/org.apache.tomcat/tomcat-catalina. >>>> This isn't a tomcat-embedded module, but looks like it might be compatible. >>>> Could these classes be used to achieve what I'm after? If I could get this >>>> working, I could maybe contribute back with "how-to" documentation. >>>> Thoughts? >>>> >>>> Also, how do I make embedded Tomcat use my classloader? >>>> >>>> >>>> On Wed, Dec 14, 2022 at 9:19 PM Mark Thomas <ma...@apache.org> wrote: >>>> >>>>> On 14/12/2022 03:20, Tim N wrote: >>>>> > I'm currently using embedded Tomcat 9.0.68 and have encountered the >>>>> > infamous compatibility issue with ClassLoader.getSystemClassLoader >>>>> when >>>>> > upgrading from Java 8 to Java 17. >>>>> > See >>>>> > >>>>> https://stackoverflow.com/questions/46694600/java-9-compatability-issue-with-classloader-getsystemclassloader >>>>> > for a good summary. >>>>> >>>>> The custom class loader approach described in one of the answers is a >>>>> viable option. >>>>> >>>>> > Is it possible to utilise and modify the Tomcat classloader >>>>> hierarchy for >>>>> > embedded Tomcat to add to the classpath, specifically: >>>>> > - Add some shared libraries as done with the 'shared.loader' for >>>>> Tomcat >>>>> > for production and development environments >>>>> >>>>> No. The same class loader hierarchy isn't constructed when running in >>>>> embedded mode. >>>>> >>>>> > - Add another module's classes to the classpath for a web-app for >>>>> > development environment only (e.g. add >>>>> "../sub-module/target/classes" to >>>>> > classpath) >>>>> >>>>> Yes. Each web application still retains its own class loader. You >>>>> configure the web application resources to map static resources, JARs >>>>> and/or directories of classes to the right place in your web app. >>>>> >>>>> For example (totally untested but should give you the idea): >>>>> >>>>> Tomcat tomcat = new Tomcat(); >>>>> Context context = tomcat.addContext("", "/some/path"); >>>>> WebResourceRoot root = context.getResources(); >>>>> DirResourceSet extraJARs = new DirResourceSet(root, >>>>> "/WEB-INF/lib", "/path/to/extra/jars", ""); >>>>> root.addPostResources(extraJARs); >>>>> >>>>> > In Java 8 I can achieve this by calling 'addURL' on >>>>> 'URLClassLoader', but >>>>> > that is no longer possible in Java 9+. >>>>> > >>>>> > Is there any official documentation for this? >>>>> >>>>> The docs for configuring this in context.xml are here: >>>>> >>>>> https://tomcat.apache.org/tomcat-9.0-doc/config/resources.html >>>>> >>>>> Javadoc for doing it directly is here: >>>>> >>>>> >>>>> https://tomcat.apache.org/tomcat-9.0-doc/api/org/apache/catalina/webresources/package-summary.html >>>>> >>>>> HTH, >>>>> >>>>> Mark >>>>> > >>>>> >>>>> --------------------------------------------------------------------- >>>>> To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org >>>>> For additional commands, e-mail: users-h...@tomcat.apache.org >>>>> >>>>>