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

Bug 272529

Summary: NPE in BaseSlidableAnchor.hashCode
Product: [Modeling] GMF-Runtime Reporter: Anthony Hunter <ahunter.eclipse>
Component: GeneralAssignee: Alex Boyko <aboyko>
Status: RESOLVED FIXED QA Contact:
Severity: normal    
Priority: P3 CC: antoine
Version: 2.2   
Target Milestone: 2.2   
Hardware: PC   
OS: Windows XP   
Whiteboard:

Description Anthony Hunter CLA 2009-04-16 13:03:16 EDT
From Bug 266959

The GMF developers had the idea of changing the implementation of anchors so
that the hashcode method looks like this:

/* (non-Javadoc)
         * @see java.lang.Object#hashCode()
         */
        public int hashCode() {
                int figureHashCode = getOwner() != null ? getOwner().hashCode()
: 0; 
                if (isDefaultAnchor()) {
                        return figureHashCode;
                }
                return new Double(relativeReference.preciseX()).hashCode()
                                ^ new
Double(relativeReference.preciseY()).hashCode()
                                ^ figureHashCode;
        }

Of course, relativeReference  may be null, something they apparently hadn't
factored in. 

Stack trace:

!ENTRY org.eclipse.ui 4 0 2009-04-10 16:46:23.183
!MESSAGE Unhandled event loop exception
!STACK 0
java.lang.NullPointerException
	at org.eclipse.gmf.runtime.draw2d.ui.figures.BaseSlidableAnchor.hashCode(BaseSlidableAnchor.java:137)
	at org.eclipse.gmf.runtime.draw2d.ui.internal.routers.ObliqueRouter$ArrayListKey.hashCode(ObliqueRouter.java:127)
	at java.util.HashMap.get(HashMap.java:343)
	at org.eclipse.gmf.runtime.draw2d.ui.internal.routers.ObliqueRouter$ArrayListMap.get(ObliqueRouter.java:55)
	at org.eclipse.gmf.runtime.draw2d.ui.internal.routers.ObliqueRouter.removeSelfRelConnection(ObliqueRouter.java:1019)
	at org.eclipse.gmf.runtime.draw2d.ui.internal.routers.ObliqueRouter.checkSelfRelConnection(ObliqueRouter.java:1002)
	at org.eclipse.gmf.runtime.draw2d.ui.internal.routers.ObliqueRouter.routeLine(ObliqueRouter.java:492)
	at org.eclipse.gmf.runtime.draw2d.ui.internal.routers.ObliqueRouter.routeBendpoints(ObliqueRouter.java:212)
	at org.eclipse.gmf.runtime.draw2d.ui.internal.routers.ObliqueRouter.route(ObliqueRouter.java:197)
	at org.eclipse.draw2d.AutomaticRouter.route(AutomaticRouter.java:146)
	at org.eclipse.gmf.runtime.draw2d.ui.internal.routers.FanRouter.routeBendpoints(FanRouter.java:56)
	at org.eclipse.gmf.runtime.draw2d.ui.internal.routers.FanRouter.route(FanRouter.java:40)
	at org.eclipse.draw2d.PolylineConnection.layout(PolylineConnection.java:169)
	at org.eclipse.draw2d.Figure.validate(Figure.java:1739)
	at org.eclipse.draw2d.Figure.validate(Figure.java:1741)
	at org.eclipse.draw2d.Figure.validate(Figure.java:1741)
	at org.eclipse.draw2d.FreeformViewport$FreeformViewportLayout.calculatePreferredSize(FreeformViewport.java:28)
	at org.eclipse.draw2d.AbstractLayout.getPreferredSize(AbstractLayout.java:93)
	at org.eclipse.draw2d.AbstractHintLayout.getPreferredSize(AbstractHintLayout.java:85)
	at org.eclipse.draw2d.Figure.getPreferredSize(Figure.java:735)
	at org.eclipse.draw2d.ScrollPaneSolver.solve(ScrollPaneSolver.java:75)
	at org.eclipse.draw2d.FigureCanvas.layoutViewport(FigureCanvas.java:306)
	at org.eclipse.draw2d.FigureCanvas.access$4(FigureCanvas.java:304)
	at org.eclipse.draw2d.FigureCanvas$3.notifyValidating(FigureCanvas.java:269)
	at org.eclipse.draw2d.UpdateManager.fireValidating(UpdateManager.java:123)
	at org.eclipse.draw2d.DeferredUpdateManager.performValidation(DeferredUpdateManager.java:203)
	at org.eclipse.gmf.runtime.diagram.ui.parts.DiagramGraphicalViewer$ToggleUpdateManager.performValidation(DiagramGraphicalViewer.java:124)
	at org.eclipse.draw2d.DeferredUpdateManager.paint(DeferredUpdateManager.java:154)
	at org.eclipse.draw2d.LightweightSystem.paint(LightweightSystem.java:199)
	at org.eclipse.draw2d.LightweightSystem$2.handleEvent(LightweightSystem.java:107)
	at org.eclipse.swt.widgets.EventTable.sendEvent(EventTable.java:84)
	at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1204)
	at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1228)
	at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1213)
	at org.eclipse.swt.widgets.Control.drawWidget(Control.java:1037)
	at org.eclipse.swt.widgets.Canvas.drawWidget(Canvas.java:152)
	at org.eclipse.swt.widgets.Widget.drawRect(Widget.java:565)
	at org.eclipse.swt.widgets.Display.windowDelegateProc(Display.java:4238)
	at org.eclipse.swt.internal.cocoa.OS.objc_msgSendSuper(Native Method)
	at org.eclipse.swt.widgets.Display.applicationNextEventMatchingMask(Display.java:3838)
	at org.eclipse.swt.widgets.Display.applicationProc(Display.java:3957)
	at org.eclipse.swt.internal.cocoa.OS.objc_msgSend(Native Method)
	at org.eclipse.swt.internal.cocoa.NSApplication.nextEventMatchingMask(NSApplication.java:75)
	at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:2871)
	at org.eclipse.ui.internal.Workbench.runEventLoop(Workbench.java:2393)
	at org.eclipse.ui.internal.Workbench.runUI(Workbench.java:2357)
	at org.eclipse.ui.internal.Workbench.access$4(Workbench.java:2209)
	at org.eclipse.ui.internal.Workbench$5.run(Workbench.java:499)
	at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:332)
	at org.eclipse.ui.internal.Workbench.createAndRunWorkbench(Workbench.java:492)
	at org.eclipse.ui.PlatformUI.createAndRunWorkbench(PlatformUI.java:149)
	at org.eclipse.ui.internal.ide.application.IDEApplication.start(IDEApplication.java:113)
	at org.eclipse.equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java:194)
	at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:110)
	at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:79)
	at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:368)
	at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:179)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
	at java.lang.reflect.Method.invoke(Method.java:585)
	at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:556)
	at org.eclipse.equinox.launcher.Main.basicRun(Main.java:511)
	at org.eclipse.equinox.launcher.Main.run(Main.java:1284)
Comment 1 Antoine Toulmé CLA 2009-04-16 13:22:54 EDT
The isDefaultAnchor implementation of the BaseSlidableAnchor is actually just checking if relativeReference is null. We have completely overridden this and we calculate the defaultAnchor in a different manner. So we got in trouble with this implementation change.

I believe you should just plainly check that the relativeReference is not null in the hashcode method rather than in the isDefaultAnchor method. If it is null, you should rely on the super method for hashcode.
Comment 2 Alex Boyko CLA 2009-05-22 15:36:40 EDT
Anthony and Antoine,

I agree that checking for isDefault() instead of a plain null check is incorrect, relies too much on the default implementation of #isDefault(). However, I feel that we should return the hash of the owner figure rather than super.hashCode(). Owner figure may cache anchors.
Comment 3 Anthony Hunter CLA 2009-05-26 15:53:56 EDT
(In reply to comment #2)
> Anthony and Antoine,
> 
> I agree that checking for isDefault() instead of a plain null check is
> incorrect, relies too much on the default implementation of #isDefault().
> However, I feel that we should return the hash of the owner figure rather than
> super.hashCode(). Owner figure may cache anchors.
> 

OK, yes we can fix right away.
Comment 4 Alex Boyko CLA 2009-05-26 16:12:55 EDT
Fixed for 2.2 as described
Comment 5 Eclipse Webmaster CLA 2010-07-16 23:35:44 EDT
[target cleanup] 2.2 RC was the original target milestone for this
bug
Comment 6 Eclipse Webmaster CLA 2010-07-19 21:59:28 EDT
[GMF Restructure] Bug 319140 : product GMF and component
Runtime was the original product and component for this bug