| Summary: | Java code generation writes unwanted defaults for attributes based on wrapped-primitive types | ||
|---|---|---|---|
| Product: | [Modeling] EMF | Reporter: | Ben Tenne <tenne.ben> |
| Component: | Tools | Assignee: | Dave Steinberg <davidms> |
| Status: | CLOSED FIXED | QA Contact: | |
| Severity: | normal | ||
| Priority: | P3 | CC: | Ed.Merks, tenne.ben |
| Version: | unspecified | ||
| Target Milestone: | --- | ||
| Hardware: | PC | ||
| OS: | Windows 7 | ||
| Whiteboard: | |||
CORRECTION. Sorry, the XSD fragment presented at the beginning of the description should have looked like this:
<xs:complexType name="Wrap">
<xs:sequence>
<xs:element name="plank">
<xs:simpleType>
<xs:restriction base="xs:int">
<xs:maxInclusive value="100"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
...
Here's a potential workaround involving an edit to the Class.javajet template.
It seems that this returns the wrong value (e.g. zero for an Integer that has no default):
genFeature.getStaticDefaultValue()
...whereas this correctly returns null when there's no default in the Ecore model and the Java type is an Object (i.e. it would return 0 for an int, which is fine):
genFeature.getEcoreFeature().getDefaultValue()
So, it seems I can get around the problem by replacing the script fragment that writes the default value:
<%=staticDefaultValue%>
...with this:
<%=(genFeature.getEcoreFeature().getDefaultValue() ==
null?null:staticDefaultValue)%>
This topic has been previously discussed here: http://www.eclipse.org/forums/index.php?t=msg&th=161681&start=0&S=3ddddf8f5526bf2b36af8723b6a10d53
The problem was walking up the data type's extended metadata derivation path until reaching a type in XMLTypePackage (so that we can use XMLTypeFactory to process the literal default value of a feature). That traversal goes from a wrapper type to a primitive type, but the intrinsic default value for the primitive type should not be applied as the intrinsic default for the wrapper type. An additional guard is added so that it now produces null. The changes are available in EMF 2.7 M7 or an earlier build. |
Build Identifier: 20100617-1415 This suspected bug concerns unwanted default values in Java code generated from Ecore models derived from XSD (via XSDEcoreBuilder). Consider the following XSD fragment: <xs:complexType name="Wrap"> <xs:sequence> <xs:element name="plank" type="xs:int"/> ... Here are two fragments from the corresponding Ecore generated by XSDEcoreBuilder: <eClassifiers xsi:type="ecore:EDataType" name="PlankType" instanceClassName="int"> <eAnnotations source="http:///org/eclipse/emf/ecore/util/ExtendedMetaData"> <details key="name" value="plank_._type"/> <details key="baseType" value="http://www.eclipse.org/emf/2003/XMLType#int"/> <details key="maxInclusive" value="100"/> </eAnnotations> </eClassifiers> <eClassifiers xsi:type="ecore:EDataType" name="PlankTypeObject" instanceClassName="java.lang.Integer"> <eAnnotations source="http:///org/eclipse/emf/ecore/util/ExtendedMetaData"> <details key="name" value="plank_._type:Object"/> <details key="baseType" value="plank_._type"/> </eAnnotations> </eClassifiers> <eClassifiers xsi:type="ecore:EClass" name="Wrap"> ... <eStructuralFeatures xsi:type="ecore:EAttribute" name="plank" lowerBound="1" eType="#//PlankType" unsettable="true"> <eAnnotations source="http:///org/eclipse/emf/ecore/util/ExtendedMetaData"> <details key="kind" value="element"/> <details key="name" value="plank"/> <details key="namespace" value="##targetNamespace"/> </eAnnotations> </eStructuralFeatures> Note that two EDataTypes have been generated: PlankType (int) and PlankTypeObject (Integer) but only the first is referenced. I believe this is by-design; If I altered my original schema to declare nillable="true" for plank, then PlankTypeObject will be used instead, allowing it to accommodate a value of null. For reasons that I won't go into here, I want _all_ my attributes capable of taking null. To achieve this, I've overridden behaviour in XSDEcoreBuilder and made it so the object-wrapped type is always used: i.e. In my previous example, plank will always have type 'PlankTypeObject' (i.e. 'PlankType' will never be used). I also set unsettable=false for the attribute. However, when I generate the model code from this, I get: protected static final Integer PLANK_EDEFAULT = 0; protected Integer plank = PLANK_EDEFAULT; i.e. The default is zero, but my model specified no value. I was expecting it to be null. One problem this causes is that, if I create an instance and call setPlank(null), a subsequent call to eIsSet for the feature returns true (as isSet considers an attribute (non-unsettable) to be set if its value differs from its default). In my case, I want to check if plank's set by evaluating getPlank()!=null, which, of course, will misleadingly return true. Incidentally, I've noticed that EMF 2.6 will only generate PlankType/PlankTypeObject if plank's type is a restriction (thus my 'maxInclusive=100'). Otherwise, plank would be of type http://www.eclipse.org/emf/2003/XMLType#//Int and the problem does _not_ occur in that case (i.e. the default is correctly declared null). I'm actually working with EMF 2.4.x and in that version, PlankType/PlankTypeObject are _always_ created. I'm assuming this was a deliberate efficiency improvement between 2.4 and 2.6. For reasons beyond my control, I can't move EMF version at the moment, so I'd be very interested in any work-around ideas. Note: Although I've used int/Integer in this example, the same applies to boolean/Boolean and double/Double. Thanks in advance for any thoughts on this. Ben. Reproducible: Always Steps to Reproduce: See Details.