Home » Modeling » EMF » EMF or Teneo: Unable to not specify optional enumeration
EMF or Teneo: Unable to not specify optional enumeration [message #1112353] |
Thu, 19 September 2013 13:27 |
Rob Mising name Messages: 118 Registered: July 2010 |
Senior Member |
|
|
Hi Ed, Martin,
I wasn't sure which camp this falls into, as the problem is highlighted when I was doing some testing with Teneo - but the fix I think is possible, is in the EMF Templates.
If I have a schema as follows (Simplified version of what I was running):
<xsd:simpleType name="TreadPattern" ecore:name="TreadPattern">
<xsd:restriction base="xsd:string">
<xsd:enumeration value="WAVYLINES" ecore:name="WAVYLINES"/>
<xsd:enumeration value="CRISSCROSS" ecore:name="CRISSCROSS"/>
<xsd:enumeration value="SPIRALS" ecore:name="SPIRALS"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:complexType name="Wheel" ecore:name="Wheel">
<xsd:sequence>
<xsd:element name="diameter" minOccurs="0" maxOccurs="1" ecore:name="diameter">
<xsd:simpleType>
<xsd:restriction base="xsd:integer">
<xsd:totalDigits value="10"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="tyre" type="Tyre" minOccurs="1" maxOccurs="1" ecore:name="tyre"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="Tyre" ecore:name="Tyre">
<xsd:sequence>
<xsd:element name="treadPattern" type="tns3:TreadPattern" minOccurs="0" maxOccurs="1" ecore:name="treadPattern"/>
</xsd:sequence>
</xsd:complexType>
<xsd:element name="WheelElement" type="Wheel"/>
<xsd:element name="TyreElement" type="Tyre"/>
So the treadPattern is an optional element of type enumeration.
If I construct and then persist a Wheel, where there is a Tyre (required as part of the schema) but there is no tread pattern specified (as it is optional).
When it goes to persist it I get an exception:
Caused by: java.lang.IllegalArgumentException: The value 'null' is not a valid enumerator of 'TreadPattern'
at com.example.gdcomp.impl.GdcompFactoryImpl.createTreadPatternFromString(GdcompFactoryImpl.java:705)
at com.example.gdcomp.impl.GdcompFactoryImpl.createTreadPatternObjectFromString(GdcompFactoryImpl.java:1726)
at com.example.gdcomp.impl.GdcompFactoryImpl.createFromString(GdcompFactoryImpl.java:224)
at org.eclipse.emf.teneo.hibernate.mapping.DefaultToStringUserType.deepCopy(DefaultToStringUserType.java:77)
at org.hibernate.type.CustomType.deepCopy(CustomType.java:179)
at org.hibernate.type.TypeFactory.deepCopy(TypeFactory.java:374)
at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:280)
at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:181)
at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:121)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:187)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:172)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:94)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:70)
at org.hibernate.impl.SessionImpl.fireSaveOrUpdate(SessionImpl.java:508)
at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:500)
This is because the create...FromString method is trying to convert a value that is "null", and the existing template will throw an exception if null is passed into it.
public TreadPattern createTreadPatternFromString(EDataType eDataType, String initialValue)
{
TreadPattern result = TreadPattern.get(initialValue);
if (result == null) throw new IllegalArgumentException("The value '" + initialValue + "' is not a valid enumerator of '" + eDataType.getName() + "'");
return result;
}
I have managed to work around this problem by adding to the FactoryClass.javajet template, so that it checks for null as an argument - and return null in this case rather than throw an exception. (Approx line 346)
public <%=genDataType.getImportedParameterizedObjectInstanceClassName()%> create<%=genDataType.getName()%>FromString(<%=genModel.getImportedName("org.eclipse.emf.ecore.EDataType")%> eDataType, String initialValue)
{
<%if (genDataType instanceof GenEnum) {%>
<%if (genPackage.isDataTypeConverters()) {%>
return create<%=genDataType.getName()%>(initialValue);
<%} else {%>
<%// ** START CUSTOM CHANGE ** %>
// If the argument passed in is null, return null
if( initialValue == null )
{
return null;
}
<%// ** END CUSTOM CHANGE ** %>
<%=((GenEnum)genDataType).getImportedInstanceClassName()%> result = <%=((GenEnum)genDataType).getImportedInstanceClassName()%>.get(initialValue);
if (result == null) throw new IllegalArgumentException("The value '" + initialValue + "' is not a valid enumerator of '" + eDataType.getName() + "'");<%=genModel.getNonNLS()%><%=genModel.getNonNLS(2)%><%=genModel.getNonNLS(3)%>
return result;
<%}%>
I would be very interested to hear both of your thoughts, and if this change is a safe one to make?
Thanks, Rob
|
|
|
Re: EMF or Teneo: Unable to not specify optional enumeration [message #1112368 is a reply to message #1112353] |
Thu, 19 September 2013 13:51 |
Ed Merks Messages: 33140 Registered: July 2009 |
Senior Member |
|
|
Rob,
I'll wait for Martin to comment. From a purely EMF point of view,
EEnums are treated like primitive types that don't support a null
value. I.e., an EAttribute of type EEnum can't return a null value
from the getter and even trying to set it to null will set it to the
feature's default value which will be the first EEnumLiteral unless
another literal is explicitly set as the EAttribute's default. So I'm
not sure where the null comes from; of course I see the call from
deepCopy, but I can't comment on why it has null as a literal value...
On 19/09/2013 3:27 PM, Rob Mising name wrote:
> Hi Ed, Martin,
>
> I wasn't sure which camp this falls into, as the problem is
> highlighted when I was doing some testing with Teneo - but the fix I
> think is possible, is in the EMF Templates.
>
> If I have a schema as follows (Simplified version of what I was running):
>
> <xsd:simpleType name="TreadPattern" ecore:name="TreadPattern">
> <xsd:restriction base="xsd:string">
> <xsd:enumeration value="WAVYLINES" ecore:name="WAVYLINES"/>
> <xsd:enumeration value="CRISSCROSS" ecore:name="CRISSCROSS"/>
> <xsd:enumeration value="SPIRALS" ecore:name="SPIRALS"/>
> </xsd:restriction>
> </xsd:simpleType>
> <xsd:complexType name="Wheel" ecore:name="Wheel">
> <xsd:sequence>
> <xsd:element name="diameter" minOccurs="0" maxOccurs="1"
> ecore:name="diameter">
> <xsd:simpleType>
> <xsd:restriction base="xsd:integer">
> <xsd:totalDigits value="10"/>
> </xsd:restriction>
> </xsd:simpleType>
> </xsd:element>
> <xsd:element name="tyre" type="Tyre" minOccurs="1"
> maxOccurs="1" ecore:name="tyre"/>
> </xsd:sequence>
> </xsd:complexType>
> <xsd:complexType name="Tyre" ecore:name="Tyre">
> <xsd:sequence>
> <xsd:element name="treadPattern" type="tns3:TreadPattern"
> minOccurs="0" maxOccurs="1" ecore:name="treadPattern"/>
> </xsd:sequence>
> </xsd:complexType>
> <xsd:element name="WheelElement" type="Wheel"/>
> <xsd:element name="TyreElement" type="Tyre"/>
>
> So the treadPattern is an optional element of type enumeration.
>
> If I construct and then persist a Wheel, where there is a Tyre
> (required as part of the schema) but there is no tread pattern
> specified (as it is optional).
>
> When it goes to persist it I get an exception:
>
>
> Caused by: java.lang.IllegalArgumentException: The value 'null' is not
> a valid enumerator of 'TreadPattern'
> at
> com.example.gdcomp.impl.GdcompFactoryImpl.createTreadPatternFromString(GdcompFactoryImpl.java:705)
> at
> com.example.gdcomp.impl.GdcompFactoryImpl.createTreadPatternObjectFromString(GdcompFactoryImpl.java:1726)
> at
> com.example.gdcomp.impl.GdcompFactoryImpl.createFromString(GdcompFactoryImpl.java:224)
> at
> org.eclipse.emf.teneo.hibernate.mapping.DefaultToStringUserType.deepCopy(DefaultToStringUserType.java:77)
> at org.hibernate.type.CustomType.deepCopy(CustomType.java:179)
> at org.hibernate.type.TypeFactory.deepCopy(TypeFactory.java:374)
> at
> org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:280)
> at
> org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:181)
> at
> org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:121)
> at
> org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:187)
> at
> org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:172)
> at
> org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:94)
> at
> org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:70)
> at
> org.hibernate.impl.SessionImpl.fireSaveOrUpdate(SessionImpl.java:508)
> at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:500)
>
>
> This is because the create...FromString method is trying to convert a
> value that is "null", and the existing template will throw an
> exception if null is passed into it.
>
> public TreadPattern createTreadPatternFromString(EDataType eDataType,
> String initialValue)
> {
> TreadPattern result = TreadPattern.get(initialValue);
> if (result == null) throw new IllegalArgumentException("The value
> '" + initialValue + "' is not a valid enumerator of '" +
> eDataType.getName() + "'");
> return result;
> }
>
>
> I have managed to work around this problem by adding to the
> FactoryClass.javajet template, so that it checks for null as an
> argument - and return null in this case rather than throw an
> exception. (Approx line 346)
>
> public
> <%=genDataType.getImportedParameterizedObjectInstanceClassName()%>
> create<%=genDataType.getName()%>FromString(<%=genModel.getImportedName("org.eclipse.emf.ecore.EDataType")%>
> eDataType, String initialValue)
> {
> <%if (genDataType instanceof GenEnum) {%>
> <%if (genPackage.isDataTypeConverters()) {%>
> return create<%=genDataType.getName()%>(initialValue);
> <%} else {%>
> <%// ** START CUSTOM CHANGE ** %>
> // If the argument passed in is null, return null
> if( initialValue == null )
> {
> return null;
> }
> <%// ** END CUSTOM CHANGE ** %>
> <%=((GenEnum)genDataType).getImportedInstanceClassName()%> result =
> <%=((GenEnum)genDataType).getImportedInstanceClassName()%>.get(initialValue);
> if (result == null) throw new IllegalArgumentException("The
> value '" + initialValue + "' is not a valid enumerator of '" +
> eDataType.getName() +
> "'");<%=genModel.getNonNLS()%><%=genModel.getNonNLS(2)%><%=genModel.getNonNLS(3)%>
> return result;
> <%}%>
>
>
> I would be very interested to hear both of your thoughts, and if this
> change is a safe one to make?
>
> Thanks, Rob
>
>
>
>
Ed Merks
Professional Support: https://www.macromodeling.com/
|
|
| |
Re: EMF or Teneo: Unable to not specify optional enumeration [message #1112383 is a reply to message #1112374] |
Thu, 19 September 2013 14:43 |
Ed Merks Messages: 33140 Registered: July 2009 |
Senior Member |
|
|
Rob,
No, I don't imagine your work around would cause problems. It's a
scenario I don't expect would normally arise and I can't forsee anything
would be broken because of a failure to throw an exception rather than
returning null.
On 19/09/2013 4:05 PM, Rob Mising name wrote:
> Ed Merks wrote on Thu, 19 September 2013 14:51
>> I'll wait for Martin to comment. From a purely EMF point of view,
>> EEnums are treated like primitive types that don't support a null
>> value. I.e., an EAttribute of type EEnum can't return a null value
>> from the getter and even trying to set it to null will set it to the
>> feature's default value which will be the first EEnumLiteral unless
>> another literal is explicitly set as the EAttribute's default. So
>> I'm not sure where the null comes from; of course I see the call from
>> deepCopy, but I can't comment on why it has null as a literal value...
>
>
> Hi Ed,
>
> Thanks for the speedy reply. I know it would not be ideal (or pure in
> the EMF world), but do you think doing the template change locally on
> my system would be OK (and safe) in this case? (Just as a temporary
> work-around)
>
> Thanks
>
> Rob
>
Ed Merks
Professional Support: https://www.macromodeling.com/
|
|
|
Re: EMF or Teneo: Unable to not specify optional enumeration [message #1112518 is a reply to message #1112383] |
Thu, 19 September 2013 20:42 |
Martin Taal Messages: 5468 Registered: July 2009 |
Senior Member |
|
|
Hi Rob,
It seems that Teneo does not recognize the datatype as an enum (therefore the default string user type is being used it
seems). Teneo has a EnumUserType and a EnumUserIntegerType for enums. Can you make a small model which shows the same
error? (looks like a bug)
gr. Martin
On 09/19/2013 04:43 PM, Ed Merks wrote:
> Rob,
>
> No, I don't imagine your work around would cause problems. It's a scenario I don't expect would normally arise and I
> can't forsee anything would be broken because of a failure to throw an exception rather than returning null.
>
>
> On 19/09/2013 4:05 PM, Rob Mising name wrote:
>> Ed Merks wrote on Thu, 19 September 2013 14:51
>>> I'll wait for Martin to comment. From a purely EMF point of view, EEnums are treated like primitive types that don't
>>> support a null value. I.e., an EAttribute of type EEnum can't return a null value from the getter and even trying
>>> to set it to null will set it to the feature's default value which will be the first EEnumLiteral unless another
>>> literal is explicitly set as the EAttribute's default. So I'm not sure where the null comes from; of course I see
>>> the call from deepCopy, but I can't comment on why it has null as a literal value...
>>
>>
>> Hi Ed,
>>
>> Thanks for the speedy reply. I know it would not be ideal (or pure in the EMF world), but do you think doing the
>> template change locally on my system would be OK (and safe) in this case? (Just as a temporary work-around)
>>
>> Thanks
>>
>> Rob
>>
>
--
With Regards, Martin Taal
Springsite/Elver.org
Office: Hardwareweg 4, 3821 BV Amersfoort
Postal: Nassaulaan 7, 3941 EC Doorn
The Netherlands
Cell: +31 (0)6 288 48 943
Tel: +31 (0)84 420 2397
Fax: +31 (0)84 225 9307
Mail: mtaal@xxxxxxxx - mtaal@xxxxxxxx
Web: www.springsite.com - www.elver.org
|
|
| |
Goto Forum:
Current Time: Thu Apr 25 11:44:12 GMT 2024
Powered by FUDForum. Page generated in 0.02934 seconds
|