You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@tomcat.apache.org by Tim N <tn...@gmail.com> on 2022/12/14 03:20:53 UTC

Embedded Tomcat 9.0.x Classpath Modification Migrating From Java 8 to 17

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.

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

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?

Re: Embedded Tomcat 9.0.x Classpath Modification Migrating From Java 8 to 17

Posted by Tim N <tn...@gmail.com>.
Looks like this is due to a conflict with EE JARs added to replace those
removed when moving from Java 8 to 17.

On Wed, Dec 21, 2022 at 3:33 PM Tim N <tn...@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 <tn...@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 <tn...@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-unsubscribe@tomcat.apache.org
>>>> For additional commands, e-mail: users-help@tomcat.apache.org
>>>>
>>>>

Re: Embedded Tomcat 9.0.x Classpath Modification Migrating From Java 8 to 17

Posted by Mark Thomas <ma...@apache.org>.
On 23/12/2022 03:28, Tim N wrote:
> Do you think this thread is useful info for any Tomcat-embedded Java 17
> migration guide/how-to? I'm happy to tidy it up and contribute if there's
> an official Tomcat-embedded place for it.

It is on the mailing list so it shoudl alreayd be findable. The wiki is 
probably the place for this.

>> The Java code looks good to me. The calls to
>> SecurityClassLoad.securityClassLoad() and Service.setParentClassLoader()
>> may be unnecessary
> 
> Looks like I can ditch the SecurityClassLoad.securityClassLoad() call, but
> without the Service.setParentClassLoader() call I get classloading errors,

<snip/>

> Do you think I need to look into that more, or does it make sense that the
> Service.setParentClassLoader() prevents this?

It makes sense. Keep the call.

Mark

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
For additional commands, e-mail: users-help@tomcat.apache.org


Re: Embedded Tomcat 9.0.x Classpath Modification Migrating From Java 8 to 17

Posted by Tim N <tn...@gmail.com>.
> This should be unnecessary. The classes in that package should be
> included in tomcat-embed-core

Nice - thanks. I was reading and using the catalina code, but after
trimming down my code it no longer needs that dependency.

Do you think this thread is useful info for any Tomcat-embedded Java 17
migration guide/how-to? I'm happy to tidy it up and contribute if there's
an official Tomcat-embedded place for it.

> The Java code looks good to me. The calls to
> SecurityClassLoad.securityClassLoad() and Service.setParentClassLoader()
> may be unnecessary

Looks like I can ditch the SecurityClassLoad.securityClassLoad() call, but
without the Service.setParentClassLoader() call I get classloading errors,
specifically:
Dec 23, 2022 1:47:00 PM org.apache.catalina.core.StandardContext
listenerStart
SEVERE: Error configuring application listener of class
[org.springframework.web.context.request.RequestContextListener]
java.lang.ClassNotFoundException:
org.springframework.web.context.request.RequestContextListener
at
org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1412)
at
org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1220)
at
org.apache.catalina.core.DefaultInstanceManager.loadClass(DefaultInstanceManager.java:534)
at
org.apache.catalina.core.DefaultInstanceManager.loadClassMaybePrivileged(DefaultInstanceManager.java:515)
at
org.apache.catalina.core.DefaultInstanceManager.newInstance(DefaultInstanceManager.java:149)
at
org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4687)
at
org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5222)
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$$$capture(FutureTask.java:264)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java)
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.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$$$capture(FutureTask.java:264)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java)
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)

Do you think I need to look into that more, or does it make sense that the
Service.setParentClassLoader() prevents this?



On Thu, Dec 22, 2022 at 9:49 PM Mark Thomas <ma...@apache.org> wrote:

> On 21/12/2022 22:37, Tim N wrote:
> > 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>
>
> This should be unnecessary. The classes in that package should be
> included in tomcat-embed-core
>
>
> > Java
>
> <snip/>
>
> The Java code looks good to me. The calls to
> SecurityClassLoad.securityClassLoad() and Service.setParentClassLoader()
> may be unnecessary but I don't think they'll cause any harm.
>
> Mark
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
> For additional commands, e-mail: users-help@tomcat.apache.org
>
>

Re: Embedded Tomcat 9.0.x Classpath Modification Migrating From Java 8 to 17

Posted by Mark Thomas <ma...@apache.org>.
On 21/12/2022 22:37, Tim N wrote:
> 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>

This should be unnecessary. The classes in that package should be 
included in tomcat-embed-core


> Java

<snip/>

The Java code looks good to me. The calls to 
SecurityClassLoad.securityClassLoad() and Service.setParentClassLoader() 
may be unnecessary but I don't think they'll cause any harm.

Mark

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
For additional commands, e-mail: users-help@tomcat.apache.org


Re: Embedded Tomcat 9.0.x Classpath Modification Migrating From Java 8 to 17

Posted by Tim N <tn...@gmail.com>.
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 <tn...@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 <tn...@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 <tn...@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 <tn...@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-unsubscribe@tomcat.apache.org
>>>>> For additional commands, e-mail: users-help@tomcat.apache.org
>>>>>
>>>>>

Re: Embedded Tomcat 9.0.x Classpath Modification Migrating From Java 8 to 17

Posted by Tim N <tn...@gmail.com>.
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 <tn...@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 <tn...@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 <tn...@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-unsubscribe@tomcat.apache.org
>>>> For additional commands, e-mail: users-help@tomcat.apache.org
>>>>
>>>>

Re: Embedded Tomcat 9.0.x Classpath Modification Migrating From Java 8 to 17

Posted by Tim N <tn...@gmail.com>.
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 <tn...@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 <tn...@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-unsubscribe@tomcat.apache.org
>>> For additional commands, e-mail: users-help@tomcat.apache.org
>>>
>>>

Re: Embedded Tomcat 9.0.x Classpath Modification Migrating From Java 8 to 17

Posted by Tim N <tn...@gmail.com>.
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 <tn...@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-unsubscribe@tomcat.apache.org
>> For additional commands, e-mail: users-help@tomcat.apache.org
>>
>>

Re: Embedded Tomcat 9.0.x Classpath Modification Migrating From Java 8 to 17

Posted by Tim N <tn...@gmail.com>.
> 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-unsubscribe@tomcat.apache.org
> For additional commands, e-mail: users-help@tomcat.apache.org
>
>

Re: Embedded Tomcat 9.0.x Classpath Modification Migrating From Java 8 to 17

Posted by Mark Thomas <ma...@apache.org>.
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-unsubscribe@tomcat.apache.org
For additional commands, e-mail: users-help@tomcat.apache.org