Classloading Behavior in Embedded Tomcat

classic Classic list List threaded Threaded
7 messages Options
Reply | Threaded
Open this post in threaded view
|

Classloading Behavior in Embedded Tomcat

Chirag Dewan-2
Hi,

Due to some backward compatibility concerns, I need to support both
Jersey-1 and Jersey-2 on the same Tomcat instance. This is an embedded
tomcat which runs inside a JVM application.

Since, Jersey-1 and Jersey-2 have different JAXRS  versions, I tried to
remove both jsr311 and javax.ws.rs-2 from my JVMs classpath. And instead
packaged these in the WAR/WEB-INF\lib along with jersey version specific
jars like jersey-core-1.x, jersey-common-2.x etc.

Now when I start my Jersey-1 application, it couldn't find
 javax.ws.rs.ext.MessageBodyReader.

I read Classloader HOW-TO and although it says that the order of loading
JavaEE classes is bootstrap first, it never says anything about WEB-INF as
a source for these jars.

So if there any way I can load javax.* classes from WEB-INF\lib?

Thanks in advance
Chirag
Reply | Threaded
Open this post in threaded view
|

Re: Classloading Behavior in Embedded Tomcat

Mark Thomas-2
On 22/07/2020 11:18, Chirag Dewan wrote:

> Hi,
>
> Due to some backward compatibility concerns, I need to support both
> Jersey-1 and Jersey-2 on the same Tomcat instance. This is an embedded
> tomcat which runs inside a JVM application.
>
> Since, Jersey-1 and Jersey-2 have different JAXRS  versions, I tried to
> remove both jsr311 and javax.ws.rs-2 from my JVMs classpath. And instead
> packaged these in the WAR/WEB-INF\lib along with jersey version specific
> jars like jersey-core-1.x, jersey-common-2.x etc.
>
> Now when I start my Jersey-1 application, it couldn't find
>  javax.ws.rs.ext.MessageBodyReader.
>
> I read Classloader HOW-TO and although it says that the order of loading
> JavaEE classes is bootstrap first, it never says anything about WEB-INF as
> a source for these jars.
>
> So if there any way I can load javax.* classes from WEB-INF\lib?

Tomcat version?

Different Tomcat versions have taken different approaches to
implementing this requirement. A recent(ish) implementation should be
fine but with the exact version number we can give a better answer.

Mark

---------------------------------------------------------------------
To unsubscribe, e-mail: [hidden email]
For additional commands, e-mail: [hidden email]

Reply | Threaded
Open this post in threaded view
|

Re: Classloading Behavior in Embedded Tomcat

Chirag Dewan-2
Thanks for a very quick reply Mark.

The Tomcat version is 8.5.46.

Though I do plan to upgrade to 9.0.36 in the coming weeks.

Chirag

On Wed, 22 Jul, 2020, 4:03 pm Mark Thomas, <[hidden email]> wrote:

> On 22/07/2020 11:18, Chirag Dewan wrote:
> > Hi,
> >
> > Due to some backward compatibility concerns, I need to support both
> > Jersey-1 and Jersey-2 on the same Tomcat instance. This is an embedded
> > tomcat which runs inside a JVM application.
> >
> > Since, Jersey-1 and Jersey-2 have different JAXRS  versions, I tried to
> > remove both jsr311 and javax.ws.rs-2 from my JVMs classpath. And instead
> > packaged these in the WAR/WEB-INF\lib along with jersey version specific
> > jars like jersey-core-1.x, jersey-common-2.x etc.
> >
> > Now when I start my Jersey-1 application, it couldn't find
> >  javax.ws.rs.ext.MessageBodyReader.
> >
> > I read Classloader HOW-TO and although it says that the order of loading
> > JavaEE classes is bootstrap first, it never says anything about WEB-INF
> as
> > a source for these jars.
> >
> > So if there any way I can load javax.* classes from WEB-INF\lib?
>
> Tomcat version?
>
> Different Tomcat versions have taken different approaches to
> implementing this requirement. A recent(ish) implementation should be
> fine but with the exact version number we can give a better answer.
>
> Mark
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: [hidden email]
> For additional commands, e-mail: [hidden email]
>
>
Reply | Threaded
Open this post in threaded view
|

Re: Classloading Behavior in Embedded Tomcat

Mark Thomas-2
On 22/07/2020 11:35, Chirag Dewan wrote:
> Thanks for a very quick reply Mark.
>
> The Tomcat version is 8.5.46.
>
> Though I do plan to upgrade to 9.0.36 in the coming weeks.

OK. Both behave the same way which makes things easier.

See the source code for full details but the summary is:

First Tomcat checks if the requested class is available from the same
class loader that loaded java.lang.String. If it is, it loads it from
that class loader. This prevents web applications over-ridding Java SE
classes.

If the class has not been loaded yet, Tomcat then checks to see if it is
a class that Tomcat is expected to provide. If it is, it uses the common
class loader to load it.

If the class isn't loaded the following search order is used:
- WEB-INF/classes
- WEB-INF/lib
- $CATALINA_BASE/lib (for classes)
- $CATALINA_BASE/lib (for JARs)
- bootstrap / classpath

Embedded scenarios tend not to set up the same class loader structure as
stand alone Tomcat. Often, they use a single class loader for
everything. I'd check that your scenario works in a stand alone Tomcat
first and once you have that working, transfer it to embedded with
particular attention to class loader configuration.

Mark


>
> Chirag
>
> On Wed, 22 Jul, 2020, 4:03 pm Mark Thomas, <[hidden email]> wrote:
>
>> On 22/07/2020 11:18, Chirag Dewan wrote:
>>> Hi,
>>>
>>> Due to some backward compatibility concerns, I need to support both
>>> Jersey-1 and Jersey-2 on the same Tomcat instance. This is an embedded
>>> tomcat which runs inside a JVM application.
>>>
>>> Since, Jersey-1 and Jersey-2 have different JAXRS  versions, I tried to
>>> remove both jsr311 and javax.ws.rs-2 from my JVMs classpath. And instead
>>> packaged these in the WAR/WEB-INF\lib along with jersey version specific
>>> jars like jersey-core-1.x, jersey-common-2.x etc.
>>>
>>> Now when I start my Jersey-1 application, it couldn't find
>>>  javax.ws.rs.ext.MessageBodyReader.
>>>
>>> I read Classloader HOW-TO and although it says that the order of loading
>>> JavaEE classes is bootstrap first, it never says anything about WEB-INF
>> as
>>> a source for these jars.
>>>
>>> So if there any way I can load javax.* classes from WEB-INF\lib?
>>
>> Tomcat version?
>>
>> Different Tomcat versions have taken different approaches to
>> implementing this requirement. A recent(ish) implementation should be
>> fine but with the exact version number we can give a better answer.
>>
>> Mark
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: [hidden email]
>> For additional commands, e-mail: [hidden email]
>>
>>
>


---------------------------------------------------------------------
To unsubscribe, e-mail: [hidden email]
For additional commands, e-mail: [hidden email]

Reply | Threaded
Open this post in threaded view
|

Re: Classloading Behavior in Embedded Tomcat

Chirag Dewan-2
I tried that with standalone Tomcat and it works. I can deploy Jersey-1 and
Jersey-2 apps together.

I was wondering whether Loader with delegate=false work in context for
embedded?

Thanks
Chirag

On Wed, 22 Jul, 2020, 5:03 pm Mark Thomas, <[hidden email]> wrote:

> On 22/07/2020 11:35, Chirag Dewan wrote:
> > Thanks for a very quick reply Mark.
> >
> > The Tomcat version is 8.5.46.
> >
> > Though I do plan to upgrade to 9.0.36 in the coming weeks.
>
> OK. Both behave the same way which makes things easier.
>
> See the source code for full details but the summary is:
>
> First Tomcat checks if the requested class is available from the same
> class loader that loaded java.lang.String. If it is, it loads it from
> that class loader. This prevents web applications over-ridding Java SE
> classes.
>
> If the class has not been loaded yet, Tomcat then checks to see if it is
> a class that Tomcat is expected to provide. If it is, it uses the common
> class loader to load it.
>
> If the class isn't loaded the following search order is used:
> - WEB-INF/classes
> - WEB-INF/lib
> - $CATALINA_BASE/lib (for classes)
> - $CATALINA_BASE/lib (for JARs)
> - bootstrap / classpath
>
> Embedded scenarios tend not to set up the same class loader structure as
> stand alone Tomcat. Often, they use a single class loader for
> everything. I'd check that your scenario works in a stand alone Tomcat
> first and once you have that working, transfer it to embedded with
> particular attention to class loader configuration.
>
> Mark
>
>
> >
> > Chirag
> >
> > On Wed, 22 Jul, 2020, 4:03 pm Mark Thomas, <[hidden email]> wrote:
> >
> >> On 22/07/2020 11:18, Chirag Dewan wrote:
> >>> Hi,
> >>>
> >>> Due to some backward compatibility concerns, I need to support both
> >>> Jersey-1 and Jersey-2 on the same Tomcat instance. This is an embedded
> >>> tomcat which runs inside a JVM application.
> >>>
> >>> Since, Jersey-1 and Jersey-2 have different JAXRS  versions, I tried to
> >>> remove both jsr311 and javax.ws.rs-2 from my JVMs classpath. And
> instead
> >>> packaged these in the WAR/WEB-INF\lib along with jersey version
> specific
> >>> jars like jersey-core-1.x, jersey-common-2.x etc.
> >>>
> >>> Now when I start my Jersey-1 application, it couldn't find
> >>>  javax.ws.rs.ext.MessageBodyReader.
> >>>
> >>> I read Classloader HOW-TO and although it says that the order of
> loading
> >>> JavaEE classes is bootstrap first, it never says anything about WEB-INF
> >> as
> >>> a source for these jars.
> >>>
> >>> So if there any way I can load javax.* classes from WEB-INF\lib?
> >>
> >> Tomcat version?
> >>
> >> Different Tomcat versions have taken different approaches to
> >> implementing this requirement. A recent(ish) implementation should be
> >> fine but with the exact version number we can give a better answer.
> >>
> >> Mark
> >>
> >> ---------------------------------------------------------------------
> >> To unsubscribe, e-mail: [hidden email]
> >> For additional commands, e-mail: [hidden email]
> >>
> >>
> >
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: [hidden email]
> For additional commands, e-mail: [hidden email]
>
>
Reply | Threaded
Open this post in threaded view
|

Re: Classloading Behavior in Embedded Tomcat

Chirag Dewan-2
Hey Mark,

Any clues, how to proceed with this for embedded?

Thanks
Chirag


On Wed, 22 Jul, 2020, 7:31 pm Chirag Dewan, <[hidden email]>
wrote:

> I tried that with standalone Tomcat and it works. I can deploy Jersey-1
> and Jersey-2 apps together.
>
> I was wondering whether Loader with delegate=false work in context for
> embedded?
>
> Thanks
> Chirag
>
> On Wed, 22 Jul, 2020, 5:03 pm Mark Thomas, <[hidden email]> wrote:
>
>> On 22/07/2020 11:35, Chirag Dewan wrote:
>> > Thanks for a very quick reply Mark.
>> >
>> > The Tomcat version is 8.5.46.
>> >
>> > Though I do plan to upgrade to 9.0.36 in the coming weeks.
>>
>> OK. Both behave the same way which makes things easier.
>>
>> See the source code for full details but the summary is:
>>
>> First Tomcat checks if the requested class is available from the same
>> class loader that loaded java.lang.String. If it is, it loads it from
>> that class loader. This prevents web applications over-ridding Java SE
>> classes.
>>
>> If the class has not been loaded yet, Tomcat then checks to see if it is
>> a class that Tomcat is expected to provide. If it is, it uses the common
>> class loader to load it.
>>
>> If the class isn't loaded the following search order is used:
>> - WEB-INF/classes
>> - WEB-INF/lib
>> - $CATALINA_BASE/lib (for classes)
>> - $CATALINA_BASE/lib (for JARs)
>> - bootstrap / classpath
>>
>> Embedded scenarios tend not to set up the same class loader structure as
>> stand alone Tomcat. Often, they use a single class loader for
>> everything. I'd check that your scenario works in a stand alone Tomcat
>> first and once you have that working, transfer it to embedded with
>> particular attention to class loader configuration.
>>
>> Mark
>>
>>
>> >
>> > Chirag
>> >
>> > On Wed, 22 Jul, 2020, 4:03 pm Mark Thomas, <[hidden email]> wrote:
>> >
>> >> On 22/07/2020 11:18, Chirag Dewan wrote:
>> >>> Hi,
>> >>>
>> >>> Due to some backward compatibility concerns, I need to support both
>> >>> Jersey-1 and Jersey-2 on the same Tomcat instance. This is an embedded
>> >>> tomcat which runs inside a JVM application.
>> >>>
>> >>> Since, Jersey-1 and Jersey-2 have different JAXRS  versions, I tried
>> to
>> >>> remove both jsr311 and javax.ws.rs-2 from my JVMs classpath. And
>> instead
>> >>> packaged these in the WAR/WEB-INF\lib along with jersey version
>> specific
>> >>> jars like jersey-core-1.x, jersey-common-2.x etc.
>> >>>
>> >>> Now when I start my Jersey-1 application, it couldn't find
>> >>>  javax.ws.rs.ext.MessageBodyReader.
>> >>>
>> >>> I read Classloader HOW-TO and although it says that the order of
>> loading
>> >>> JavaEE classes is bootstrap first, it never says anything about
>> WEB-INF
>> >> as
>> >>> a source for these jars.
>> >>>
>> >>> So if there any way I can load javax.* classes from WEB-INF\lib?
>> >>
>> >> Tomcat version?
>> >>
>> >> Different Tomcat versions have taken different approaches to
>> >> implementing this requirement. A recent(ish) implementation should be
>> >> fine but with the exact version number we can give a better answer.
>> >>
>> >> Mark
>> >>
>> >> ---------------------------------------------------------------------
>> >> To unsubscribe, e-mail: [hidden email]
>> >> For additional commands, e-mail: [hidden email]
>> >>
>> >>
>> >
>>
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: [hidden email]
>> For additional commands, e-mail: [hidden email]
>>
>>
Reply | Threaded
Open this post in threaded view
|

Re: Classloading Behavior in Embedded Tomcat

Chirag Dewan-2
Hi,

I guess I found the issue.

WebAppClassLoader delegates to parent classloader where my
environment doesn't have the javax.ws.rs.MessageBodyReader class. But this
was present in my build/compile time environment.
So WebAppClassLoader only ignores the ClassNotFoundException:

if (delegateLoad) {
    if (log.isDebugEnabled())
        log.debug("  Delegating to parent classloader1 " + parent);
    try {
        clazz = Class.forName(name, false, parent);
        if (clazz != null) {
            if (log.isDebugEnabled())
                log.debug("  Loading class from parent");
            if (resolve)
                resolveClass(clazz);
            return clazz;
        }
    } catch (ClassNotFoundException e) {
        // Ignore
    }

But in this case I get a NoClassDefFoundError and hence the context
fails to start.

I guess I will need to implement a custom class loader. Is there any
other way to make this work?

Thanks,

Chirag


On Thu, Jul 23, 2020 at 11:32 PM Chirag Dewan <[hidden email]>
wrote:

> Hey Mark,
>
> Any clues, how to proceed with this for embedded?
>
> Thanks
> Chirag
>
>
> On Wed, 22 Jul, 2020, 7:31 pm Chirag Dewan, <[hidden email]>
> wrote:
>
>> I tried that with standalone Tomcat and it works. I can deploy Jersey-1
>> and Jersey-2 apps together.
>>
>> I was wondering whether Loader with delegate=false work in context for
>> embedded?
>>
>> Thanks
>> Chirag
>>
>> On Wed, 22 Jul, 2020, 5:03 pm Mark Thomas, <[hidden email]> wrote:
>>
>>> On 22/07/2020 11:35, Chirag Dewan wrote:
>>> > Thanks for a very quick reply Mark.
>>> >
>>> > The Tomcat version is 8.5.46.
>>> >
>>> > Though I do plan to upgrade to 9.0.36 in the coming weeks.
>>>
>>> OK. Both behave the same way which makes things easier.
>>>
>>> See the source code for full details but the summary is:
>>>
>>> First Tomcat checks if the requested class is available from the same
>>> class loader that loaded java.lang.String. If it is, it loads it from
>>> that class loader. This prevents web applications over-ridding Java SE
>>> classes.
>>>
>>> If the class has not been loaded yet, Tomcat then checks to see if it is
>>> a class that Tomcat is expected to provide. If it is, it uses the common
>>> class loader to load it.
>>>
>>> If the class isn't loaded the following search order is used:
>>> - WEB-INF/classes
>>> - WEB-INF/lib
>>> - $CATALINA_BASE/lib (for classes)
>>> - $CATALINA_BASE/lib (for JARs)
>>> - bootstrap / classpath
>>>
>>> Embedded scenarios tend not to set up the same class loader structure as
>>> stand alone Tomcat. Often, they use a single class loader for
>>> everything. I'd check that your scenario works in a stand alone Tomcat
>>> first and once you have that working, transfer it to embedded with
>>> particular attention to class loader configuration.
>>>
>>> Mark
>>>
>>>
>>> >
>>> > Chirag
>>> >
>>> > On Wed, 22 Jul, 2020, 4:03 pm Mark Thomas, <[hidden email]> wrote:
>>> >
>>> >> On 22/07/2020 11:18, Chirag Dewan wrote:
>>> >>> Hi,
>>> >>>
>>> >>> Due to some backward compatibility concerns, I need to support both
>>> >>> Jersey-1 and Jersey-2 on the same Tomcat instance. This is an
>>> embedded
>>> >>> tomcat which runs inside a JVM application.
>>> >>>
>>> >>> Since, Jersey-1 and Jersey-2 have different JAXRS  versions, I tried
>>> to
>>> >>> remove both jsr311 and javax.ws.rs-2 from my JVMs classpath. And
>>> instead
>>> >>> packaged these in the WAR/WEB-INF\lib along with jersey version
>>> specific
>>> >>> jars like jersey-core-1.x, jersey-common-2.x etc.
>>> >>>
>>> >>> Now when I start my Jersey-1 application, it couldn't find
>>> >>>  javax.ws.rs.ext.MessageBodyReader.
>>> >>>
>>> >>> I read Classloader HOW-TO and although it says that the order of
>>> loading
>>> >>> JavaEE classes is bootstrap first, it never says anything about
>>> WEB-INF
>>> >> as
>>> >>> a source for these jars.
>>> >>>
>>> >>> So if there any way I can load javax.* classes from WEB-INF\lib?
>>> >>
>>> >> Tomcat version?
>>> >>
>>> >> Different Tomcat versions have taken different approaches to
>>> >> implementing this requirement. A recent(ish) implementation should be
>>> >> fine but with the exact version number we can give a better answer.
>>> >>
>>> >> Mark
>>> >>
>>> >> ---------------------------------------------------------------------
>>> >> To unsubscribe, e-mail: [hidden email]
>>> >> For additional commands, e-mail: [hidden email]
>>> >>
>>> >>
>>> >
>>>
>>>
>>> ---------------------------------------------------------------------
>>> To unsubscribe, e-mail: [hidden email]
>>> For additional commands, e-mail: [hidden email]
>>>
>>>