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

Bug 314698

Summary: [Xtext] Serialization fails after quickfix insertion
Product: [Modeling] TMF Reporter: Johan Wannheden <johan.wannheden>
Component: XtextAssignee: Project Inbox <tmf.xtext-inbox>
Status: CLOSED FIXED QA Contact:
Severity: normal    
Priority: P3 CC: moritz.eysholdt, sven.efftinge
Version: 0.7.0Flags: moritz.eysholdt: galileo+
Target Milestone: RC3   
Hardware: PC   
OS: Mac OS X - Carbon (unsup.)   
Whiteboard:
Attachments:
Description Flags
Attaching the MyDsl project none

Description Johan Wannheden CLA 2010-05-27 11:15:07 EDT
Build Identifier: 20100218-1602

Serializing a model instance of the following model fails with exception printed in the end:

============================

grammar org.xtext.example.mydsl.MyDsl with org.eclipse.xtext.common.Terminals

import "http://www.eclipse.org/emf/2002/Ecore" as ecore

generate myDsl "http://www.xtext.org/example/mydsl/MyDsl"

Model :
    'model' name=ID
    
    (elements+=Element)*
    
    'end' 'model'
;

Element :
  'element'
        'id'                id=INT
;

terminal INT returns ecore::EInt :
    '-'? ('0'..'9')+
;

============================

Model instance:

model Hello

  element 
    id			-1

end model

============================

Note that the INT rule was overwritten to allow negative integer values. The default org.eclipse.xtext.conversion.impl.INTValueConverter value converter should be able to handle such values.

In order to trigger serialization I implemented a simple quickfix. Applying the quickfix works when the model instance is changed so that "id" is positive, e.g. "1" instead of "-1".

============================

The quickfix would change the model name "Hello" to given file name, e.g. for model "test.mydsl" to "test":

@Fix(MyDslJavaValidator.MODELNAME_FILENAME)
public void fixModelNameFileName(final Issue issue, IssueResolutionAcceptor acceptor) {
    acceptor.accept(issue, "Change model name", "Set model name to file name", null,
            new ISemanticModification() {
        public void apply(EObject element, IModificationContext context) {
            final Model model = (Model) element;
            final String fileNameWithoutExtension = MyDslUtils.getFileNameWithoutExtension(model);
            
            model.setName(fileNameWithoutExtension);
        }
    });
}

============================

Exception:

org.eclipse.emf.common.util.WrappedException: org.eclipse.xtext.parsetree.reconstr.XtextSerializationException: Serialization failed
<# of serialized tokens>: <EObject path> "<serializable fragment, starting from the end>":
  -> <possible reasons for not continuing>
5:Model'amodel'.elements[0]->Element: "end model":
  -> Element_IdAssignment_2: n/a
	at org.eclipse.xtext.ui.editor.quickfix.IssueResolution.apply(IssueResolution.java:50)
	at org.eclipse.xtext.ui.editor.quickfix.QuickAssistCompletionProposal.apply(QuickAssistCompletionProposal.java:32)
	at org.eclipse.jface.text.contentassist.CompletionProposalPopup.insertProposal(CompletionProposalPopup.java:931)
	at org.eclipse.jface.text.contentassist.CompletionProposalPopup.insertSelectedProposalWithMask(CompletionProposalPopup.java:877)
	at org.eclipse.jface.text.contentassist.CompletionProposalPopup.verifyKey(CompletionProposalPopup.java:1304)
	at org.eclipse.jface.text.contentassist.ContentAssistant$InternalListener.verifyKey(ContentAssistant.java:806)
	at org.eclipse.jface.text.TextViewer$VerifyKeyListenersManager.verifyKey(TextViewer.java:489)
	at org.eclipse.swt.custom.StyledTextListener.handleEvent(StyledTextListener.java:62)
	at org.eclipse.swt.widgets.EventTable.sendEvent(EventTable.java:84)
	at org.eclipse.swt.widgets.Display.sendEvent(Display.java:3543)
	at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1250)
	at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1273)
	at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1258)
	at org.eclipse.swt.widgets.Widget.notifyListeners(Widget.java:1079)
	at org.eclipse.swt.custom.StyledText.handleKeyDown(StyledText.java:5840)
	at org.eclipse.swt.custom.StyledText$7.handleEvent(StyledText.java:5542)
	at org.eclipse.swt.widgets.EventTable.sendEvent(EventTable.java:84)
	at org.eclipse.swt.widgets.Display.sendEvent(Display.java:3543)
	at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1250)
	at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1273)
	at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1258)
	at org.eclipse.swt.widgets.Widget.sendKeyEvent(Widget.java:1287)
	at org.eclipse.swt.widgets.Widget.sendKeyEvent(Widget.java:1283)
	at org.eclipse.swt.widgets.Canvas.sendKeyEvent(Canvas.java:433)
	at org.eclipse.swt.widgets.Control.doCommandBySelector(Control.java:906)
	at org.eclipse.swt.widgets.Display.windowProc(Display.java:4741)
	at org.eclipse.swt.internal.cocoa.OS.objc_msgSend(Native Method)
	at org.eclipse.swt.internal.cocoa.NSResponder.interpretKeyEvents(NSResponder.java:56)
	at org.eclipse.swt.widgets.Composite.keyDown(Composite.java:516)
	at org.eclipse.swt.widgets.Display.windowProc(Display.java:4655)
	at org.eclipse.swt.internal.cocoa.OS.objc_msgSendSuper(Native Method)
	at org.eclipse.swt.widgets.Widget.callSuper(Widget.java:202)
	at org.eclipse.swt.widgets.Widget.windowSendEvent(Widget.java:1753)
	at org.eclipse.swt.widgets.Shell.windowSendEvent(Shell.java:1825)
	at org.eclipse.swt.widgets.Display.windowProc(Display.java:4713)
	at org.eclipse.swt.internal.cocoa.OS.objc_msgSendSuper(Native Method)
	at org.eclipse.swt.widgets.Display.applicationSendEvent(Display.java:4285)
	at org.eclipse.swt.widgets.Display.applicationProc(Display.java:4352)
	at org.eclipse.swt.internal.cocoa.OS.objc_msgSend(Native Method)
	at org.eclipse.swt.internal.cocoa.NSApplication.sendEvent(NSApplication.java:101)
	at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:3097)
	at org.eclipse.ui.internal.Workbench.runEventLoop(Workbench.java:2405)
	at org.eclipse.ui.internal.Workbench.runUI(Workbench.java:2369)
	at org.eclipse.ui.internal.Workbench.access$4(Workbench.java:2221)
	at org.eclipse.ui.internal.Workbench$5.run(Workbench.java:500)
	at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:332)
	at org.eclipse.ui.internal.Workbench.createAndRunWorkbench(Workbench.java:493)
	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:597)
	at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:559)
	at org.eclipse.equinox.launcher.Main.basicRun(Main.java:514)
	at org.eclipse.equinox.launcher.Main.run(Main.java:1311)
	at org.eclipse.equinox.launcher.Main.main(Main.java:1287)
Caused by: org.eclipse.xtext.parsetree.reconstr.XtextSerializationException: Serialization failed
<# of serialized tokens>: <EObject path> "<serializable fragment, starting from the end>":
  -> <possible reasons for not continuing>
5:Model'amodel'.elements[0]->Element: "end model":
  -> Element_IdAssignment_2: n/a
	at org.eclipse.xtext.parsetree.reconstr.impl.AbstractParseTreeConstructor.serialize(AbstractParseTreeConstructor.java:670)
	at org.eclipse.xtext.parsetree.reconstr.impl.AbstractParseTreeConstructor.serialize(AbstractParseTreeConstructor.java:677)
	at org.eclipse.xtext.parsetree.reconstr.impl.AbstractParseTreeConstructor.serializeSubtree(AbstractParseTreeConstructor.java:700)
	at org.eclipse.xtext.parsetree.reconstr.Serializer.serialize(Serializer.java:55)
	at org.eclipse.xtext.parsetree.reconstr.Serializer.serializeReplacement(Serializer.java:96)
	at org.eclipse.xtext.ui.editor.model.edit.DefaultTextEditComposer.getObjectEdits(DefaultTextEditComposer.java:162)
	at org.eclipse.xtext.ui.editor.model.edit.DefaultTextEditComposer.getTextEdit(DefaultTextEditComposer.java:137)
	at org.eclipse.xtext.ui.editor.model.edit.DefaultTextEditComposer.endRecording(DefaultTextEditComposer.java:121)
	at org.eclipse.xtext.ui.editor.model.edit.DefaultDocumentEditor$ReconcilingUnitOfWork.exec(DefaultDocumentEditor.java:42)
	at org.eclipse.xtext.ui.editor.model.edit.DefaultDocumentEditor$ReconcilingUnitOfWork.exec(DefaultDocumentEditor.java:1)
	at org.eclipse.xtext.util.concurrent.IStateAccess$AbstractImpl.modify(IStateAccess.java:57)
	at org.eclipse.xtext.ui.editor.model.XtextDocument$XtextDocumentLocker.modify(XtextDocument.java:149)
	at org.eclipse.xtext.ui.editor.model.XtextDocument.modify(XtextDocument.java:62)
	at org.eclipse.xtext.ui.editor.model.edit.DefaultDocumentEditor.process(DefaultDocumentEditor.java:59)
	at org.eclipse.xtext.ui.editor.model.edit.SemanticModificationWrapper.apply(SemanticModificationWrapper.java:33)
	at org.eclipse.xtext.ui.editor.quickfix.IssueResolution.apply(IssueResolution.java:48)
	... 61 more


Reproducible: Always
Comment 1 Johan Wannheden CLA 2010-05-27 11:16:15 EDT
Created attachment 170200 [details]
Attaching the MyDsl project
Comment 2 Moritz Eysholdt CLA 2010-05-27 11:38:34 EDT
> Note that the INT rule was overwritten to allow negative integer values. The
> default org.eclipse.xtext.conversion.impl.INTValueConverter value converter
> should be able to handle such values.


Nope, it's not...

org.eclipse.xtext.conversion.impl.INTValueConverter.assertValidValue(Integer):
-----
protected void assertValidValue(Integer value) {
  super.assertValidValue(value);
  if (value < 0)
    throw new ValueConverterException(getRuleName() + "-value may not be negative (value:" + value + ").", null, null);
}

I assume that this exception is thrown which is then caught in org.eclipse.xtext.parsetree.reconstr.impl.ValueSerializer.isValid(EObject, RuleCall, Object, IErrorAcceptor) which then returns false and consequently causes serialization to fail.

Can you confirm this?

I don't think it would be a good idea to use the parser/lexer by default to validate int values... validating them as integers is so much more performant and straight forward. 

in case serialization fails because of the reasons mentioned above, please adopt your ValueConverter.
Comment 3 Johan Wannheden CLA 2010-05-27 11:46:43 EDT
You're quite right, it did turn out to be a value converter issue. Sorry for the noise.
Comment 4 Sven Efftinge CLA 2010-05-27 13:08:03 EDT
But still there error message sucks. It should have been the ValueConverterException which is shown to the user, shouldn't it?
Comment 5 Johan Wannheden CLA 2010-05-28 02:01:34 EDT
Another small follow-up question for something I noticed when fiddling with this: after application of a quickfix the textual model is formatted, but not using the formatter I have configured for my language - is that right? Should I file a bug?
Comment 6 Johan Wannheden CLA 2010-05-28 02:02:35 EDT
And yes Sven, a ValueConverterException was actually thrown, but never visible to the user, which is sub-optimal.
Comment 7 Moritz Eysholdt CLA 2010-05-28 12:41:47 EDT
Now the serialization exception mentions the messages from ValueConverterExceptions, if they have been a likely reason for serialization to fail.
Comment 8 Karsten Thoms CLA 2017-09-19 16:21:33 EDT
Closing bug which were set to RESOLVED before Eclipse Neon.0.