Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.

Bug 323074

Summary: NPE thrown from base class's equals() causes role creation to fail
Product: [Tools] Objectteams Reporter: Stephan Herrmann <stephan.herrmann>
Component: OTJAssignee: Project Inbox <objectteams.otj-inbox>
Status: NEW --- QA Contact:
Severity: normal    
Priority: P3    
Version: 0.7   
Target Milestone: ---   
Hardware: PC   
OS: Linux   
Whiteboard:

Description Stephan Herrmann CLA 2010-08-18 14:29:58 EDT
This was observed in OTEquinoxBuilderTests by the following stacktrace:

java.lang.NullPointerException        at org.eclipse.pde.internal.core.PDEClasspathContainer$Rule.equals(PDEClasspathContainer.java:31)        at java.util.WeakHashMap.isEqual(WeakHashMap.java:737)        at java.util.WeakHashMap.put(WeakHashMap.java:612)        at org.objectteams.DoublyWeakHashMap.put(DoublyWeakHashMap.java:69)        at org.eclipse.objectteams.otdt.internal.compiler.adaptor.PDEAdaptor$__OT__Rule.&lt;init&gt;(PDEAdaptor.java:154)        at org.eclipse.objectteams.otdt.internal.compiler.adaptor.PDEAdaptor._OT$create$Rule(PDEAdaptor.java:153)        at org.eclipse.objectteams.otdt.internal.compiler.adaptor.PDEAdaptor.access$3(PDEAdaptor.java:152)        at org.eclipse.objectteams.otdt.internal.compiler.adaptor.PDEAdaptor$__OT__RequiredPluginsClasspathContainer.addForcedExports(PDEAdaptor.java:112)        at org.eclipse.objectteams.otdt.internal.compiler.adaptor.PDEAdaptor._OT$RequiredPluginsClasspathContainer$addForcedExports$getInclusions(PDEAdaptor.java:94)        at org.eclipse.pde.internal.core.RequiredPluginsClasspathContainer._OT$getInclusions$chain(RequiredPluginsClasspathContainer.java)        at org.eclipse.pde.internal.core.RequiredPluginsClasspathContainer.getInclusions(RequiredPluginsClasspathContainer.java)        at org.eclipse.pde.internal.core.RequiredPluginsClasspathContainer.getInclusions(RequiredPluginsClasspathContainer.java:272)

Here is the code being executed:
  protected Rule(RequiredPluginsClasspathContainer encl, 
                 AdaptedBaseBundle aspectBindingData, 
                 String packageName) 
  {
	encl.base(); // base constructor
        ...
        setPath(..);
        ...
  }

Inspecting the code it tells us that role creation tried to insert the base-role pair into the role cache, which seemed to collide with an existing entry so DoublyWeakHashMap had to call equals(). However, at this point the base object (Rule) was not fully initialized and thus equals() threw NPE.

This is ugly, because the role has no chance to fully initialize its base object before the map.put, because the constructor of Rule doesn't suffice for this initialization criterion, but setPath() must be called afterwards.

One might argue that the design of the base class is bogus, but since we don't own that class, we must somehow cope with the situation.

Ideas include:

 * catch NPE within the generated role registration code. but then what?

 * add syntax for telling the compiler that role registration should be 
   deferred until after some more statements, like:
      encl.base() {
          setPath(..);
      }; // only now the base is fully initialized
   This is kindof funky syntax and we would have to add special rules 
   for the initialization block: use callout only with great care etc.
   Notably: the base instance must not leak to locations that may cause
   it to be lifted (which isn't yet possible!).