You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@felix.apache.org by "Richard S. Hall" <he...@ungoverned.org> on 2006/04/14 15:19:59 UTC

Strict class loading diagnostics (Was: Re: Fixed bug in class loading)

Ok, I have just committed some changes for Felix that try to diagnose 
class loading errors and suggest how to fix them. Along with this 
change, I commented out the default boot delegation configuration 
property in hopes that we would get more feedback if/when people run 
into class loading errors.

The following are the cases and examples of the messages that are logged 
as a result...

Case 1 - A class load error for a class that does not exist in an 
imported package:

****
****
Package 'javax.swing' is imported by bundle 4 from bundle 0, but the 
exported package from bundle 0 does not contain the requested class 
'javax.swing.Foo'. Please verify that the class name is correct in the 
importing bundle 4 and/or that the exported package is correctly bundled 
in 0.
****
****

Case 2 - A class load error for a class from a package that is not 
imported, but an exporter exists:

****
****
Class 'javax.swing.table.TableModel' was not found because bundle 4 does 
not import 'javax.swing.table' even though bundle 0 does export it. 
There are two fixes: 1) Add an import for 'javax.swing.table' to bundle 
4; imports are necessary for each class directly touched by bundle code 
or indirectly touched, such as super classes if their methods are used. 
2) Add package 'javax.swing.table' to the 
'org.osgi.framework.bootdelegation' property; a library or VM bug can 
cause classes to be loaded by the wrong class loader. The first approach 
is preferable for preserving modularity.
****
****

Case 3 - A class load error for an unresolved optional import package 
where there is an exporter available, but with attributes that do not 
match (this also checks if the exporter matches, but perhaps was 
installed after the importer was resolved):

****
****
Class 'org.foo.Bar' was not found, but this is likely normal since 
package 'org.foo' is optionally imported by bundle 4. However, bundle 0 
does export this package with attributes that do not match.
****
****

Case 4 - A class load error for an unresolved dynamic import package 
where there is an exporter available, but with attributes that do not match:

****
****
Class 'org.woz.Bar' was not found, but this is likely normal since 
package 'org.woz' is dynamically imported by bundle 4. However, bundle 0 
does export this package with attributes that do not match.
****
****

Case 5 - A class load error for a package that is not imported, but is 
available from the system class loader:

****
****
Package 'javax.swing.plaf.metal' is not imported by bundle 4, nor is 
there any bundle that exports package 'javax.swing.plaf.metal'. However, 
the class 'javax.swing.plaf.metal.MetalLookAndFeel' is available from 
the system class loader. There are two fixes: 1) Add package 
'javax.swing.plaf.metal' to the 'org.osgi.framework.system.packages' 
property and modify bundle 4 to import this package; this causes the 
system bundle to export class path packages. 2) Add package 
'javax.swing.plaf.metal' to the 'org.osgi.framework.bootdelegation' 
property; a library or VM bug can cause classes to be loaded by the 
wrong class loader. The first approach is preferable for preserving 
modularity.
****
****

Case 6 - A class load error where there is no import or export:

****
****
Class 'org.toto.Bar' was not found. Bundle 4 does not import package 
'org.toto', nor is the package exported by any other bundle or available 
from the system class loader.
****
****

Right now these are getting logged as an ERROR, but perhaps it should be 
INFO, I don't know.

Perhaps there are other cases to consider. I wanted to have a diagnostic 
that looked more deeply into errors that might be detectable when 
loadClassInternal() is on the stack, but I could not find a scenario 
that was definitely an error.

-> richard

Richard S. Hall wrote:
> Peter Kriens wrote:
>> RSH> My desire is not to cause people using Felix any undue pain. I 
>> certainly
>> RSH> want Felix to work properly out of the box, but how will we ever 
>> learn
>> RSH> about these issues and improve the situation if we never try?
>> Maybe you can log any delegation to the bootclasspath as a warning?
>>   
>
> Yes, that is a possibility. However, the Swing LAF example that was 
> resolved without needing to import "com.sun.*" or "sun.*" is really 
> telling. By exposing these hidden dependencies in a more strict way, 
> then we can actually learn something from them. Making them too easy 
> to ignore just creates more of the same issues.
>
> Still, I agree that we should try to make being more strict as 
> painless as possible. Another possible approach is for us to try to 
> improve Felix' error diagnostics when a class loading error occurs. 
> For example, we could:
>
>    * Check to see if there are exporters of the package, but no import
>      and suggest adding it to the Import-Package declaration.
>    * Check to see if the class is available from the system class
>      loader and suggest adding the package to the system bundle's 
> packages.
>    * Check to see if the class is being loaded using
>      ClassLoader.loadClassInternal() by examing the stack trace and
>      suggest to add the package to the boot delegation property.
>
> Perhaps there are other possible diagnostics that could help 
> developers when they encounter a class loading error.
>
> -> richard
>
>> Kind regards,
>>
>>      Peter Kriens
>>
>> RSH> John E. Conlon wrote:
>>  
>>>> the problem lay in another part of the class where I build the menu
>>>> items to allow the user to change the configuration of the LAF. For 
>>>> that
>>>> I needed to determine if my string classnames were accessible.
>>>>
>>>> Here is the problematic way:
>>>>
>>>> static boolean isAvailableLookAndFeel(String laf) {
>>>>  try {
>>>>    Class lnfClass = Class.forName(laf);
>>>>    LookAndFeel newLAF = (LookAndFeel) (lnfClass.newInstance());
>>>>    return newLAF.isSupportedLookAndFeel();
>>>>  } catch (Exception e) {                                          
>>>> return false;
>>>>  }
>>>> }
>>>>
>>>> The right way to do this is to use the
>>>> javax.swing.UIManager.getInstalledLookAndFeels() method
>>>> which returns an array of LookAndFeelInfo objects. An LookAndFeelInfo
>>>> object can then be used for building the menu items.
>>>>
>>>> After refactoring the class I was able to remove the 
>>>> com.sun.java.swing.plaf.gtk; com.sun.java.swing.plaf.motif; package 
>>>> imports from the bundle and the from the
>>>> org.osgi.framework.system.packages property.
>>>>
>>>> The bundle then loaded without error.
>>>>       
>>
>> RSH> Interesting. Thanks for looking into this in detail.
>>
>> RSH> However, did you check out the latest version of Felix since I 
>> did add
>> RSH> "com.sun.*" and "sun.*" to the boot delegation property.
>>
>> RSH> If this is accurate, then it basically demonstrates my thinking 
>> exactly.
>> RSH> We either can by default try to be a little more strict and look 
>> into RSH> problems and try to figure them out in a proper modular 
>> fashion or do we
>> RSH> just forget about it and allow more and more and more legacy to 
>> be built
>> RSH> with the same modularity problems. I am in the camp of the former.
>>
>> RSH> My desire is not to cause people using Felix any undue pain. I 
>> certainly
>> RSH> want Felix to work properly out of the box, but how will we ever 
>> learn
>> RSH> about these issues and improve the situation if we never try?
>>
>> ->> richard
>>
>>
>>   
>