eclipse / Xpect

This repository has been rewritten to move to the Eclipse Foundation. Find the old history here: https://github.com/TypeFox/Xpect
http://www.xpect-tests.org/
Eclipse Public License 2.0
30 stars 28 forks source link

Xpect 0.2.0 uses HashMultimap instead of LinkedHashMultimap leading to unpredictable behaviour with RuntimeModule conflicts #242

Closed trancexpress closed 5 years ago

trancexpress commented 5 years ago

See the following line:

https://github.com/eclipse/Xpect/blob/8cd46a376aba7ada3e77316d29a4dbd3168fe563/org.eclipse.xpect/src/org/eclipse/xpect/registry/FileExtensionInfoRegistry.java#L271

What used to be:

Multimap<String, FileExtensionData> name2xtextInfo = LinkedHashMultimap.create();

Is now:

Multimap<String, FileExtensionData> name2xtextInfo = HashMultimap.create();

Our product tests use Xpect 0.1.0. We are currently trying out Xpect 0.2.0 and have noticed sporadic failures during validation, while an Xpect test is running. The failures log:

at org.eclipse.xpect.ui.registry.UIExtensionInfoRegistry$UiExtensionInfo$1.apply(UIExtensionInfoRegistry.java:55) at org.eclipse.xpect.ui.registry.UIExtensionInfoRegistry$UiExtensionInfo$1.apply(UIExtensionInfoRegistry.java:1) at org.eclipse.xpect.registry.LazyClass.load(LazyClass.java:91) at org.eclipse.xpect.registry.AbstractLanguageInfo.getRuntimeModuleClass(AbstractLanguageInfo.java:102) at org.eclipse.xpect.validation.XpectJavaValidator.validateLanguageModulesAreOnClasspath(XpectJavaValidator.java:63) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.eclipse.xtext.validation.AbstractDeclarativeValidator$MethodWrapper.invoke(AbstractDeclarativeValidator.java:120) at org.eclipse.xtext.validation.AbstractDeclarativeValidator.internalValidate(AbstractDeclarativeValidator.java:314) at org.eclipse.xtext.validation.AbstractInjectableValidator.validate(AbstractInjectableValidator.java:71) at org.eclipse.xtext.validation.CompositeEValidator.validate(CompositeEValidator.java:151) at org.eclipse.emf.ecore.util.Diagnostician.doValidate(Diagnostician.java:257) at org.eclipse.emf.ecore.util.Diagnostician.validate(Diagnostician.java:244) at org.eclipse.xtext.validation.CancelableDiagnostician.validate(CancelableDiagnostician.java:40) at org.eclipse.emf.ecore.util.Diagnostician.validate(Diagnostician.java:201) at org.eclipse.emf.ecore.util.Diagnostician.validate(Diagnostician.java:143) at org.eclipse.xtext.validation.ResourceValidatorImpl.validate(ResourceValidatorImpl.java:146) at org.eclipse.xtext.validation.ResourceValidatorImpl.validate(ResourceValidatorImpl.java:124) at org.eclipse.xtext.validation.ResourceValidatorImpl.validate(ResourceValidatorImpl.java:90) at org.eclipse.xpect.runner.XpectRunner.validate(XpectRunner.java:229) at org.eclipse.xpect.runner.XpectRunner.loadXpectFile(XpectRunner.java:180) at org.eclipse.xpect.runner.XpectRunner.createChild(XpectRunner.java:80) at org.eclipse.xpect.runner.XpectRunner.createChildren(XpectRunner.java:96) at org.eclipse.xpect.runner.XpectRunner.getChildren(XpectRunner.java:149) at org.junit.runners.ParentRunner.getFilteredChildren(ParentRunner.java:426) at org.junit.runners.ParentRunner.getDescription(ParentRunner.java:351) at org.junit.runners.Suite.describeChild(Suite.java:123) at org.junit.runners.Suite.describeChild(Suite.java:27) at org.junit.runners.ParentRunner.getDescription(ParentRunner.java:352) ... at org.eclipse.e4.ui.internal.workbench.swt.E4Testable.lambda$0(E4Testable.java:76) at java.lang.Thread.run(Thread.java:748) Caused by: java.lang.ClassNotFoundException: ***.***RuntimeModule cannot be found by *** at org.eclipse.osgi.internal.loader.BundleLoader.findClassInternal(BundleLoader.java:511) at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:422) at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:414) at org.eclipse.osgi.internal.loader.ModuleClassLoader.loadClass(ModuleClassLoader.java:153) at java.lang.ClassLoader.loadClass(ClassLoader.java:357) at org.eclipse.osgi.internal.framework.EquinoxBundle.loadClass(EquinoxBundle.java:612) at org.eclipse.xpect.ui.registry.UIExtensionInfoRegistry$UiExtensionInfo$1.apply(UIExtensionInfoRegistry.java:53) ...

We noticed a conflict in our code base:

Conflicting Xtext Runtime Modules: '***.***' and ***.***RuntimeModule'

The first entry of the conflict is the actual class for the runtime module, so far not sure about the second. When the first entry is used to resolve the conflict, our tests pass. When the second entry is chosen, no class can be found with the respective name. This results in the listed ClassNotFoundException.

There are two things that would be great here.

  1. We had no idea there was a conflict in the first place. This conflict should be reported as an error if it can result in difficult to understand exceptions.
  2. Random behaviour during tests is not an option. If the HashMultimap leads to that, it would be great if its replaced with the previously used LinkedHashMultimap.
trancexpress commented 5 years ago

Looks like we have a patch in Xpect 0.1.0 for the linked multimap. This seems to be necessary due to:

https://github.com/eclipse/Xpect/issues/184

meysholdt commented 5 years ago

Thank you @trancexpress for the report and analysis. Fixed (by @cdietrich) in https://github.com/eclipse/Xpect/commit/6d95bbc9fc1105cf3fe8d8fb477294fc2f48277c