There are lots of places like this, that I have done exactly this to make sure 
that the visibility of the current class loader is available for a thread which 
I don’t now the history of.  There is nothing that controls how the calling 
thread might decide (via code, or some other magic) what class loader to use 
for the parent of any newly created class loader.

In my serviceUI work, I’ve used readObject in smart proxies and data classes 
referenced by such classes.  Ultimately, I would usually have already set the 
TCCL via some other mechanism related to AWT/Swing events.   But, in some 
cases, you might be on a platform where the TCCL is not set correctly, and thus 
you might find that you had to add this for your software to work on that 
platform.

Gregg

> On Feb 7, 2017, at 1:20 AM, Michał Kłeczek (XPro Sp. z o. o.) 
> <michal.klec...@xpro.biz> wrote:
> 
> I am not sure how OSGI relates to this question. But I can imagine the 
> situation like this:
> 
> class MySmartAssWrappingObject implements Serializable {
> 
>  Object myMember;
> ...
> 
> private void readObject(ObjectInputStream ois) {
>  Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
>  myMember = ois.readObject();
> }
> 
> }
> 
> That would allow you to do something similar to what you wanted to do with 
> class resolution by remembering the stack of class loaders.
> 
> So my question is:
> is it something that people do?
> 
> Thanks,
> Michal
> 
> Peter wrote:
>>  In PreferredClassProvider, no the callers ClassLoader (context) is the 
>> parent ClassLoader of the codebase loader.
>> 
>> It depends on the ClassLoader hierarchy and chosen strategy used to resolve 
>> annotations.
>> 
>> But the index key for PreferrefClassProvider is  URI[] and parent loader 
>> (callers loader).
>> 
>> This strategy allows codebases to be duplicated for different calling 
>> context.
>> 
>> OSGi however, only loads one Bundle per URL, but as Bharath has 
>> demonstrated, the codebase loader doesn't have to be a BundleReference.
>> 
>> There are some caveats if the proxy codebase loader isn't a BundleReference, 
>> one is your dependencies aren't version managed for you, and you can only 
>> see public classes imported by the parent BundleReference.
>> 
>> The strategy of switching context wouldn't work with PreferredClassProvider.
>> 
>> Regards,
>> 
>> Peter.
>> 
>> Sent from my Samsung device.
>>     Include original message
>> ---- Original message ----
>> From: "Michał Kłeczek (XPro Sp. z o. o.)"<michal.klec...@xpro.biz>
>> Sent: 07/02/2017 07:20:59 am
>> To: dev@river.apache.org
>> Subject: Re: Changing TCCL during deserialization
>> 
>> This still does not answer my question - maybe I am not clear enough.
>> Do you have a need to set a TCCL DURING a remote call that is in progress?
>> Ie. you execute a remote call and DURING deserialization of the return value 
>> you change the TCCL (so one class is resolved using one context loader and 
>> another using a different one when reading THE SAME stream)
>> 
>> Thanks,
>> Michal
>> 
>> Gregg Wonderly wrote:
>> Anytime that a thread might end up being the one to download code, you need 
>> that threads CCL to be set.   The AWTEvent thread(s) in particular are a 
>> sticking point.  I have a class which I use for managing threading in 
>> AWT/Swing.  It’s called ComponentUpdateThread.  It works as follows.
>> 
>> new ComponentUpdateThread<List<Item>>( itemList, actionButton1, 
>> actionButton2, checkbox1 ) {
>>      public void setup() {
>>              // In event thread
>>              setBusyCursorOn( itemList );
>>      }
>>      public List<Item>construct() {
>>              try {
>>                      return service.getListOfItems( filterParm1 );
>>              } catch( Exception ex ) {
>>                      reportException(ex);
>>              }
>>              return null;
>>      }
>>      public void finished() {
>>              List<Item>  let;
>>              if( (lst = get()) != null ) {
>>                      itemList.getModel().setContents( lst );
>>              }
>>      }
>> }.start();
>> 
>> This class will make the passed components disabled to keep them from being 
>> clicked on again, setup for processing use a non AWTEvent thread for getting 
>> data with other components of the UI still working, and finally mark the 
>> disabled components back to enabled, and load the list with the returned 
>> items, if there where any returned.
>> 
>> There is the opportunity for 3 or more threads to be involved here.  First, 
>> there is the calling thread.  It doesn’t do anything but start the work.  
>> Next, there is an AWTEvent thread which will invoke setup().  Next there is 
>> a worker thread which will invoke construct().   Finally, there is (possible 
>> another) AWTEventThread which will invoke finished().
>> 
>> In total there could be up to four different threads involved, all of which 
>> must have TCCL set to the correct class loader.  My convention in the 
>> implementation, is that that will be this.getClass()getClassLoader().
>> 
>> This is all managed inside of the implementation of ComponentUpdateThread so 
>> that I don’t have to worry about it, any more.  But it’s important to 
>> understand that if you don’t do that, then the classes that the calling 
>> thread can resolve, and Item in this specific case in particular, and you 
>> would thus potentially see Item come from another class loader than you 
>> intended (the services class loader with “null” as the parent), and this 
>> will result in either a CNFE or CCE.
>> 
>> Gregg
>> 
>> On Feb 6, 2017, at 11:28 AM, Michał Kłeczek (XPro Sp. z o. 
>> o.)<michal.klec...@xpro.biz>  wrote:
>> 
>> What I was specifically asking for is whether this is needed during 
>> deserialization or after deserialization.
>> 
>> In other words - if I can lock the TCCL to an instance of MarshalInputStream 
>> existing for the duration of a single remote call.
>> 
>> Thanks,
>> Michal
>> 
>> Gregg Wonderly wrote:
>> The predominant place where it is needed is when you download a serviceUI 
>> component from a proxy service which just advertises some kind of “browsing” 
>> interface to find specific services and interact with them, and that 
>> serviceUI is embedded in another application with it’s own codebase
>> 
>> appl->serviceUI-for-browsing->Service-to-use->That-Services-ServiceUI
>> 
>> In this case, TCCL must be set to the serviceui classes classloader so that 
>> the “serviceui-for-browsing” will have a proper parent class pointer.
>> 
>> Anytime that downloaded code might download more code, it should always set 
>> TCCL to its own class loader so that the classes it downloads reflect 
>> against the existing class definitions.
>> 
>> Gregg
>> 
>> On Feb 6, 2017, at 12:03 AM, Michał Kłeczek (XPro Sp. z o. 
>> o.)<michal.klec...@xpro.biz>  <mailto:michal.klec...@xpro.biz>  wrote:
>> 
>> Hi,
>> 
>> During my work on object based annotations I realized it would be more 
>> efficient not to look for TCCL upon every call to "load class" (when default 
>> loader does not match the annotation).
>> It might be more effective to look it up upon stream creation and using it 
>> subsequently for class loader selection.
>> 
>> But this might change semantics of deserialization a little bit - it would 
>> not be possible to change the context loader during deserialization.
>> My question is - are there any scenarios that require that?
>> I cannot think of any but...
>> 
>> Thanks,
>> Michal
>> 
>> 
>> 
>> 
>> 
>> 
> 

Reply via email to