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

Bug 368180

Summary: Exception when serializing semantic model with 0.0 valued ecore::EDouble feature
Product: [Modeling] TMF Reporter: Thomas Williams <thwill>
Component: XtextAssignee: Project Inbox <tmf.xtext-inbox>
Status: CLOSED FIXED QA Contact:
Severity: normal    
Priority: P3 CC: moritz.eysholdt
Version: 2.1.1   
Target Milestone: ---   
Hardware: PC   
OS: Linux   
Whiteboard:

Description Thomas Williams CLA 2012-01-09 11:43:42 EST
Steps to Reproduce
------------------

1. Using this grammar:
----------------------

grammar psenterprise.xtext.MyLanguage with org.eclipse.xtext.common.Terminals 

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

generate myLanguage "http://www.mycompany.com/MyLanguage"

GeneralProcessModellingSystem:
    variableTypeEntity=VariableTypeEntity ;

VariableTypeEntity:
    name = ID
    '=' default=RealNumber
    ':' lowerBound=RealNumber 
    ':' upperBound=RealNumber 
    ("UNIT" '=' unit=STRING)? ;

RealNumber returns ecore::EDouble:
    ('-')? INT ( '.' INT )? ;

2. Parse and serialize a String like this:
------------------------------------------

private static String LANGUAGE_TEXT = "GasConcentration = 1.0 : 0.0 : 10.0 UNIT = \"mol/m3\"";

public static void main(String[] args) throws IOException {

    new org.eclipse.emf.mwe.utils.StandaloneSetup().setPlatformUri("../");
    Injector injector = new MyLanguageStandaloneSetup().createInjectorAndDoEMFRegistration();
    XtextResourceSet resourceSet = injector.getInstance(XtextResourceSet.class);
    resourceSet.addLoadOption(XtextResource.OPTION_RESOLVE_ALL, Boolean.TRUE);
    Resource resource = resourceSet.createResource(URI.createURI("dummy:/example.myLanguage"));

    InputStream in = new ByteArrayInputStream(LANGUAGE_TEXT.getBytes());

    resource.load(in, resourceSet.getLoadOptions());
    if (!resource.getErrors().isEmpty()) {
        System.out.println(resource.getErrors());
        return;
    }

    GeneralProcessModellingSystem gpms = (GeneralProcessModellingSystem) resource.getContents().get(0);		
    VariableTypeEntity variableTypeEntity = gpms.getVariableTypeEntity();
    System.out.println(org.eclipse.xtext.util.EmfFormatter.objToStr(gpms));
    Serializer serializer = injector.getInstance(Serializer.class);  
    String s = serializer.serialize(gpms);
    System.out.println(s);
}

Actual Results
--------------

The following output is produced by EmfFormatter#objToStr(gpms):

GeneralProcessModellingSystem {
    cref VariableTypeEntity variableTypeEntity VariableTypeEntity {
        attr EString name 'GasConcentration'
        attr EDouble default '1.0'
        attr EDouble upperBound '10.0'
        attr EString unit 'mol/m3'
    }
}

N.B. Missing 'lowerBound' feature.

The Serializer#serialize() call fails with:

Exception in thread "main" java.lang.RuntimeException: Could not serialize EObject via backtracking.
Constraint: null name=ID default=RealNumber lowerBound=RealNumber upperBound=RealNumber unit=STRING? null
Values: name(1), default(1), upperBound(1), unit(1)
Semantic Object: GeneralProcessModellingSystem.variableTypeEntity->VariableTypeEntity'GasConcentration'
Context: VariableTypeEntity
	at org.eclipse.xtext.serializer.diagnostic.ISerializationDiagnostic$ExceptionThrowingAcceptor.accept(ISerializationDiagnostic.java:70)
	at org.eclipse.xtext.serializer.sequencer.BacktrackingSemanticSequencer.createSequence(BacktrackingSemanticSequencer.java:425)
	at psenterprise.xtext.serializer.AbstractMyLanguageSemanticSequencer.sequence_VariableTypeEntity(AbstractMyLanguageSemanticSequencer.java:112)
	at psenterprise.xtext.serializer.AbstractMyLanguageSemanticSequencer.createSequence(AbstractMyLanguageSemanticSequencer.java:67)
	at org.eclipse.xtext.serializer.acceptor.SequenceFeeder.acceptEObjectRuleCall(SequenceFeeder.java:299)
	at org.eclipse.xtext.serializer.acceptor.SequenceFeeder.acceptRuleCall(SequenceFeeder.java:325)
	at org.eclipse.xtext.serializer.acceptor.SequenceFeeder.accept(SequenceFeeder.java:215)
	at psenterprise.xtext.serializer.AbstractMyLanguageSemanticSequencer.sequence_GeneralProcessModellingSystem(AbstractMyLanguageSemanticSequencer.java:102)
	at psenterprise.xtext.serializer.AbstractMyLanguageSemanticSequencer.createSequence(AbstractMyLanguageSemanticSequencer.java:60)
	at org.eclipse.xtext.serializer.impl.Serializer.serialize(Serializer.java:84)
	at org.eclipse.xtext.serializer.impl.Serializer.serialize(Serializer.java:103)
	at org.eclipse.xtext.serializer.impl.Serializer.serialize(Serializer.java:117)
	at org.eclipse.xtext.serializer.impl.Serializer.serialize(Serializer.java:50)
	at psenterprise.gparser.Main.serializeGPMS(Main.java:108)
	at psenterprise.gparser.Main.main(Main.java:53)

Expected Results
----------------

The following output should be produced by EmfFormatter#objToStr(gpms):

GeneralProcessModellingSystem {
    cref VariableTypeEntity variableTypeEntity VariableTypeEntity {
        attr EString name 'GasConcentration'
        attr EDouble default '1.0'
        attr EDouble lowerBound '0.0'
        attr EDouble upperBound '10.0'
        attr EString unit 'mol/m3'
    }
}

The Serializer#serialize() call should return the String:

    GasConcentration = 1.0 : 0.0 : 10.0 UNIT = "mol/m3"

Speculation as to cause
-----------------------

The 'lowerBound' feature is being considered transient because 0.0 is the
default value for EDouble.

Workarounds
-----------

1. Use EDoubleObject instead of EDouble in the grammar file.
2. Define a custom org.eclipse.xtext.serializer.sequencer.ITransientValueService
   that returns ValueTransient.NO.
3. Use the old Serializer (not tested)
Comment 1 Moritz Eysholdt CLA 2012-05-18 09:09:59 EDT
hi Thomas,

thank you for your detailed bug report.

I can confirm your observation that 0.0 has been marked as ValueTransient.YES by default. The status ValueTransient.YES explicitly disallows the serializer to serialize that value.

(In reply to comment #0)
> Speculation as to cause
> -----------------------
> 
> The 'lowerBound' feature is being considered transient because 0.0 is the
> default value for EDouble.

I've fixed the DefaultTransientValueService so that default-values of EAttributes are now ValueTransient.PREFERABLY. This means that the serializer should not serialize that value, but is allowed to do so if it is required by the grammar. EAttributes with return type EString and default value null, however, remain ValueTransient.YES since Xtext's common.Terminal's STRING can not handle null.

Your expectation of a changed output of the EMFFormatter is, however, not coming true. The EMFFormatter solely relies on the API of EMF. It'll show the value if EMF returns eIsSet(attribute) == true for it.

This fix will be available with the Juno RC1 release of Xtext.
Comment 2 Eclipse Webmaster CLA 2017-10-31 10:46:38 EDT
Requested via bug 522520.

-M.
Comment 3 Eclipse Webmaster CLA 2017-10-31 10:57:53 EDT
Requested via bug 522520.

-M.