Hi!

We're experiencing a problem when trying to initialize Velocity from our
webapp deployed to TomEE embedded version 8.0.15. The error we're getting
is:

failed to access class
org.apache.velocity.runtime.resource.ResourceCacheImpl$LRUMap from class
org.apache.velocity.runtime.resource.ResourceCacheImpl
(org.apache.velocity.runtime.resource.ResourceCacheImpl$LRUMap is in
unnamed module of loader 'app';
org.apache.velocity.runtime.resource.ResourceCacheImpl is in unnamed module
of loader org.apache.openejb.util.classloader.URLClassLoaderFirst @4dcbae55

We have debugged and tried to understand the issue and this is our findings:

When Velocity is initialized (using the Velocity.init(props)),
Velocity loads the class ResourceCacheImpl by using the classloader from
the current thread (Thread.currentThread().getContextClassLoader()). When
loading Velocity the context class loader on the current thread is
TomEEWebappClassLoader. This class loader delegates to the
URLClassLoaderFirst
<https://github.com/apache/tomee/blob/main/tomee/tomee-catalina/src/main/java/org/apache/tomee/catalina/TomEEWebappClassLoader.java#L201>
and
the result is that ResourceCacheImpl is loaded and the class loader for
that class is URLClassLoaderFirst. After the class is loaded, Velocity
calls the ResourceCacheImpl.initialize(..) method. This method tries to
instantiate the inner class ResourceCacheImpl$LRUMap using "new LRUMap"the.
Since this class is not loaded yet, the JVM tries to load it using the
URLClassLoaderFirst.loadClass method. The problem is that this class loader
delegates to the system class loader here
<https://github.com/apache/tomee/blob/main/container/openejb-core/src/main/java/org/apache/openejb/util/classloader/URLClassLoaderFirst.java#L119>
and
the ResourceCacheImpl$LRUMap is then loaded from the system class loader
(AppClassLoader). The result is then that the two classes are loaded from
different class loaders, and the exception mentioned in the beginning is
thrown.

We have tried to fix this by using the
properties openejb.classloader.forced-skip
and openejb.classloader.forced-load. The forced-skip property seems to
work, but I guess we are then loading the classes from the velocity
artifact that TomEE uses, and not the Velocity artifact from our webapp?
This is not optimal as we would like to be able to control and use our own
version of velocity, no matter which version TomEE Embedded uses. The
forced-load option does not seem to have any effect. To me it looks like
the reason is that the URLClassLoaderFirst delegates to the system class
loader *before* it checks the forced-load property, but there might be
things here that I don't see.

Do you have any idea on how to fix this issue? And in particular if you
think the issue is in our webapp, velocity or in TomEE itself? Any thoughts
or input would be highly appreciated!

Regards,
Henrik Wingerei

Reply via email to