Community
Participate
Working Groups
Build Identifier: Here is the exception: org.eclipse.swt.SWTException: Invalid thread access at org.eclipse.swt.SWT.error(SWT.java:4282) at org.eclipse.swt.SWT.error(SWT.java:4197) at org.eclipse.swt.SWT.error(SWT.java:4168) at org.eclipse.swt.widgets.Widget.error(Widget.java:468) at org.eclipse.swt.widgets.Widget.checkWidget(Widget.java:359) at org.eclipse.swt.widgets.Label.setImage(Label.java:345) at org.eclipse.sapphire.ui.assist.internal.PropertyEditorAssistDecorator.refreshImageAndCursor(PropertyEditorAssistDecorator.java:495) at org.eclipse.sapphire.ui.assist.internal.PropertyEditorAssistDecorator.refresh(PropertyEditorAssistDecorator.java:445) at org.eclipse.sapphire.ui.assist.internal.PropertyEditorAssistDecorator.access$2(PropertyEditorAssistDecorator.java:348) at org.eclipse.sapphire.ui.assist.internal.PropertyEditorAssistDecorator$1.handlePropertyChangedEvent(PropertyEditorAssistDecorator.java:164) at org.eclipse.sapphire.modeling.ModelElement.notifyPropertyChangeListeners(ModelElement.java:1297) at org.eclipse.sapphire.modeling.ModelElement.notifyPropertyChangeListeners(ModelElement.java:1260) at sapphire.bug.test.internal.SimpleModel.refreshProperty(SimpleModel.java:93) at org.eclipse.sapphire.modeling.ModelElement.refresh(ModelElement.java:455) at org.eclipse.sapphire.modeling.ModelElement.refresh(ModelElement.java:448) at sapphire.bug.test.internal.SimpleModel.setName(SimpleModel.java:60) at sapphire.bug.test.NonDisplayThreadAccessTest.test(NonDisplayThreadAccessTest.java:25) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) at java.lang.reflect.Method.invoke(Unknown Source) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20) at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28) at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:31) at org.junit.runners.BlockJUnit4ClassRunner.runNotIgnored(BlockJUnit4ClassRunner.java:79) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:71) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:49) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184) at org.junit.runners.ParentRunner.run(ParentRunner.java:236) at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50) at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390) at org.eclipse.pde.internal.junit.runtime.RemotePluginTestRunner.main(RemotePluginTestRunner.java:62) at org.eclipse.pde.internal.junit.runtime.PlatformUITestHarness$1.run(PlatformUITestHarness.java:47) at java.lang.Thread.run(Unknown Source) Reproducible: Always Steps to Reproduce: 1. Run the test in UI thread: no exception 2. Run the test in non UI thread: you'll see above exception
Created attachment 200766 [details] test project to reproduce the problem
I could not figure out how to run test case to produce the failure. I tried importing the project and doing Run As -> Junit Plugin Test on the test class, but that test case passed without any fix. In any case, the stack trace is all that I needed and I added asyncExec indirection at PropertyEditorAssistDecorator$1.handlePropertyChangedEvent. Please verify.
Sorry, the test does not fail, just show the exceptions when changing the model. I am not able to intercept the exception it was intercepted in ModelElement.notifyPropertyChangeListeners(). To reproduce you need to uncheck "Run in UI thread" in Test tab in launch configuration. So test will run outside of UI thread. I think by default when you run "Run As -> Junit Plugin Test" it will be checked. I have validated it again, now the same exception is surfacing from another end: org.eclipse.swt.SWTException: Invalid thread access at org.eclipse.swt.SWT.error(SWT.java:4282) at org.eclipse.swt.SWT.error(SWT.java:4197) at org.eclipse.swt.SWT.error(SWT.java:4168) at org.eclipse.swt.widgets.Widget.error(Widget.java:468) at org.eclipse.swt.widgets.Widget.checkWidget(Widget.java:359) at org.eclipse.swt.widgets.Control.setEnabled(Control.java:3266) at org.eclipse.sapphire.ui.renderers.swt.PropertyEditorRenderer.handlePropertyChangedEvent(PropertyEditorRenderer.java:485) at org.eclipse.sapphire.ui.renderers.swt.PropertyEditorRenderer$1.handlePropertyChangedEvent(PropertyEditorRenderer.java:198) at org.eclipse.sapphire.modeling.ModelElement.notifyPropertyChangeListeners(ModelElement.java:1299) at org.eclipse.sapphire.modeling.ModelElement.notifyPropertyChangeListeners(ModelElement.java:1262) at sapphire.bug.test.internal.SimpleModel.refreshProperty(SimpleModel.java:93) at org.eclipse.sapphire.modeling.ModelElement.refresh(ModelElement.java:457) at org.eclipse.sapphire.modeling.ModelElement.refresh(ModelElement.java:450) at sapphire.bug.test.internal.SimpleModel.setName(SimpleModel.java:60) at sapphire.bug.test.NonDisplayThreadAccessTest.test(NonDisplayThreadAccessTest.java:28)
Within the same line of thinking, I think, code in ModelElement.notifyPropertyChangeListeners should not wrap listeners methods execution with try/catch, instead bubble runtime exceptions up to clients directly and live it up to them to decide what to do. Clients may supply their own listeners, so it should be up to them how to handle runtime exceptions. And it will help to fail this Junit test :-)
> Within the same line of thinking, I think, code in > ModelElement.notifyPropertyChangeListeners should not wrap listeners methods > execution with try/catch, instead bubble runtime exceptions up to clients > directly and live it up to them to decide what to do. Clients may supply their > own listeners, so it should be up to them how to handle runtime exceptions. The try/catch in notify prevents one flaky listener from causing the rest of the listeners from being invoked and potentially corrupting the model in the process. It's a stability feature as we are limiting the impact of the exception. So while it would help fail the JUnit tests, it isn't a good change.
From the other hand, it will be harder to troubleshoot the problems in listeners, especially, if it is originated in third-party code. EMF does not have runtime protection too.
> From the other hand, it will be harder to troubleshoot the problems in > listeners, especially, if it is originated in third-party code. Don't see how. At runtime, the problem ends up being logged either way. If you are in the debugger, you can still trap the exception. In fact, I would say that it is actually easier to troubleshot when impact of the exception is limited. You certainly don't get a long chain of follow-on exceptions that are caused by data structure corruption from the original exception and require investigation to determine if they are related to the original failure. > EMF does not have runtime protection too. I wouldn't use EMF as a model of runtime stability. Either you do everything right or it just blows up in your face. No thread safety, no guarding against misbehaving third-party code, etc. I think that the real reason that you don't see more guards when calling out to third-party code is that it is easier on the framework writer to just let exception propagate and then blame third party code for any subsequent issues in the framework. The other reason is that there is a largely mistaken belief that try/catch blocks are expensive.
> To reproduce you need to uncheck "Run in UI thread" in Test tab in launch > configuration. I did not know about this checkbox or that it would run in the UI thread on its own accord. Thanks for the tip. Try now.
Verified. Thanks Kosta.
Closing. yrw