You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@tomcat.apache.org by Chirag Dewan <ch...@gmail.com> on 2020/07/22 10:18:38 UTC

Classloading Behavior in Embedded Tomcat

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

Re: Classloading Behavior in Embedded Tomcat

Posted by Chirag Dewan <ch...@gmail.com>.
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 <ch...@gmail.com>
wrote:

> Hey Mark,
>
> Any clues, how to proceed with this for embedded?
>
> Thanks
> Chirag
>
>
> On Wed, 22 Jul, 2020, 7:31 pm Chirag Dewan, <ch...@gmail.com>
> 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, <ma...@apache.org> 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, <ma...@apache.org> 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: users-unsubscribe@tomcat.apache.org
>>> >> For additional commands, e-mail: users-help@tomcat.apache.org
>>> >>
>>> >>
>>> >
>>>
>>>
>>> ---------------------------------------------------------------------
>>> To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
>>> For additional commands, e-mail: users-help@tomcat.apache.org
>>>
>>>

Re: Classloading Behavior in Embedded Tomcat

Posted by Chirag Dewan <ch...@gmail.com>.
Hey Mark,

Any clues, how to proceed with this for embedded?

Thanks
Chirag


On Wed, 22 Jul, 2020, 7:31 pm Chirag Dewan, <ch...@gmail.com>
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, <ma...@apache.org> 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, <ma...@apache.org> 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: users-unsubscribe@tomcat.apache.org
>> >> For additional commands, e-mail: users-help@tomcat.apache.org
>> >>
>> >>
>> >
>>
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
>> For additional commands, e-mail: users-help@tomcat.apache.org
>>
>>

Re: Classloading Behavior in Embedded Tomcat

Posted by Chirag Dewan <ch...@gmail.com>.
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, <ma...@apache.org> 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, <ma...@apache.org> 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: users-unsubscribe@tomcat.apache.org
> >> For additional commands, e-mail: users-help@tomcat.apache.org
> >>
> >>
> >
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
> For additional commands, e-mail: users-help@tomcat.apache.org
>
>

Re: Classloading Behavior in Embedded Tomcat

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


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


Re: Classloading Behavior in Embedded Tomcat

Posted by Chirag Dewan <ch...@gmail.com>.
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, <ma...@apache.org> 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: users-unsubscribe@tomcat.apache.org
> For additional commands, e-mail: users-help@tomcat.apache.org
>
>

Re: Classloading Behavior in Embedded Tomcat

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