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
>>>>>
>>>>>

Reply via email to