Home » Modeling » EMF » Deserializing object based on complexType when elements are present in schema
Deserializing object based on complexType when elements are present in schema [message #499195] |
Fri, 20 November 2009 11:24 |
Ben Tenne Messages: 50 Registered: October 2009 |
Member |
|
|
I'm hoping someone can help me understand some behaviour I'm seeing. I'm not suggesting there's a bug here, I just don't fully grasp what's happening.
Consider this simple XML Schema:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="http://testing.com/hello" targetNamespace="http://testing.com/hello">
<xs:complexType name="Car">
<xs:sequence>
<xs:element name="colour" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
Transforming to EMF, I have a class to represent Car.
I then instantiate my Car class and serialize it to XML with the following options (which are all necessary for various reasons for the system I'm working on):
XMLResource.OPTION_EXTENDED_META_DATA = Boolean.TRUE
XMLResource.OPTION_SAVE_TYPE_INFORMATION = Boolean.TRUE
XMLResource.OPTION_KEEP_DEFAULT_CONTENT = Boolean.TRUE
XMLResource.OPTION_ENCODING = "UTF-8"
This results in the following XML
<?xml version="1.0" encoding="UTF-8"?>
<hello:Car xmlns:hello="http://testing.com/hello">
<colour>Purple</colour>
</hello:Car>
I then deserialize this with the following options set:
XMLResource.OPTION_EXTENDED_META_DATA = Boolean.TRUE
XMLResource.OPTION_DEFER_ATTACHMENT = Boolean.TRUE
XMLResource.OPTION_USE_PARSER_POOL = (my pool instance)
XMLResource.OPTION_USE_DEPRECATED_METHODS = Boolean.FALSE
Deserialization gives me a Car object, just like the one I started with. Everything is fine so far.
I now alter my schema:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="http://testing.com/hello" targetNamespace="http://testing.com/hello">
<xs:element name="myElement" type="xs:int"/>
<xs:complexType name="Car">
<xs:sequence>
<xs:element name="colour" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
(i.e. I've added the 'myElement' declaration within the root)
If I repeat my serialization and deserialization, as I did before, then the serialization results in the same XML, but deserialization fails with:
org.eclipse.emf.ecore.xmi.FeatureNotFoundException: Feature 'Car' not found. (, 2, 51)
at org.eclipse.emf.ecore.xmi.impl.XMLHandler.reportUnknownFeature(XMLHandler.java:1976)
at org.eclipse.emf.ecore.xmi.impl.XMLHandler.handleUnknownFeature(XMLHandler.java:1940)
at org.eclipse.emf.ecore.xmi.impl.XMLHandler.handleFeature(XMLHandler.java:1884)
at org.eclipse.emf.ecore.xmi.impl.XMLHandler.createDocumentRoot(XMLHandler.java:1443)
[snip]
I suspect there's a reasonable explanation for this, but my question is: Why does introduction of an element within the schema affect the way my object (derived from a complexType) is deserialized?
I've found that setting XMLResource.OPTION_EXTENDED_META_DATA = Boolean.FALSE makes the problem go away, but I'm not sure that's a solution as (a) We set that option to resolve earlier issues and (b) my EMF book tells me it's required for Ecore derived from XML Schema.
Any comments much appreciated.
Ben.
|
|
| |
Re: Deserializing object based on complexType when elements are present in schema [message #499251 is a reply to message #499195] |
Fri, 20 November 2009 14:54 |
Ed Merks Messages: 33217 Registered: July 2009 |
Senior Member |
|
|
This is a multi-part message in MIME format.
--------------030901090605030009020102
Content-Type: text/plain; charset=UTF-8; format=flowed
Content-Transfer-Encoding: 7bit
Ben,
Comments below.
Ben Tenne wrote:
> I'm hoping someone can help me understand some behaviour I'm seeing.
> I'm not suggesting there's a bug here, I just don't fully grasp what's
> happening.
>
> Consider this simple XML Schema:
>
> <?xml version="1.0" encoding="UTF-8"?>
> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
> xmlns="http://testing.com/hello"
> targetNamespace="http://testing.com/hello">
> <xs:complexType name="Car">
> <xs:sequence>
> <xs:element name="colour" type="xs:string"/>
> </xs:sequence>
> </xs:complexType>
> </xs:schema>
>
> Transforming to EMF, I have a class to represent Car.
>
> I then instantiate my Car class and serialize it to XML with the
> following options (which are all necessary for various reasons for the
> system I'm working on):
>
> XMLResource.OPTION_EXTENDED_META_DATA = Boolean.TRUE
> XMLResource.OPTION_SAVE_TYPE_INFORMATION = Boolean.TRUE
> XMLResource.OPTION_KEEP_DEFAULT_CONTENT = Boolean.TRUE
> XMLResource.OPTION_ENCODING = "UTF-8"
>
>
> This results in the following XML
>
> <?xml version="1.0" encoding="UTF-8"?>
> <hello:Car xmlns:hello="http://testing.com/hello">
> <colour>Purple</colour>
> </hello:Car>
In the absence of a DocumentRoot, the complex type's name will be used
to serialize the instance; unfortunately that doesn't actually conform
to the schema. And of course given your schema, there is no possible
conforming serialization because there are no global element declarations.
>
> I then deserialize this with the following options set:
>
> XMLResource.OPTION_EXTENDED_META_DATA = Boolean.TRUE
> XMLResource.OPTION_DEFER_ATTACHMENT = Boolean.TRUE
> XMLResource.OPTION_USE_PARSER_POOL = (my pool instance)
> XMLResource.OPTION_USE_DEPRECATED_METHODS = Boolean.FALSE
>
>
> Deserialization gives me a Car object, just like the one I started
> with. Everything is fine so far.
>
> I now alter my schema:
>
> <?xml version="1.0" encoding="UTF-8"?>
> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
> xmlns="http://testing.com/hello"
> targetNamespace="http://testing.com/hello">
>
>
> <xs:element name="myElement" type="xs:int"/>
>
>
> <xs:complexType name="Car">
> <xs:sequence>
> <xs:element name="colour" type="xs:string"/>
> </xs:sequence>
> </xs:complexType>
> </xs:schema>
>
> (i.e. I've added the 'myElement' declaration within the root)
So now that you've added a global element, there's a document root...
>
> If I repeat my serialization and deserialization, as I did before,
> then the serialization results in the same XML, but deserialization
> fails with:
Now, because there is a document root, it notices that there is no Car
feature in the document root, so it's upset that this isn't conforming
to your schema.
>
> org.eclipse.emf.ecore.xmi.FeatureNotFoundException: Feature 'Car' not
> found. (, 2, 51)
> at
> org.eclipse.emf.ecore.xmi.impl.XMLHandler.reportUnknownFeatu re(XMLHandler.java:1976)
>
> at
> org.eclipse.emf.ecore.xmi.impl.XMLHandler.handleUnknownFeatu re(XMLHandler.java:1940)
>
> at
> org.eclipse.emf.ecore.xmi.impl.XMLHandler.handleFeature(XMLH andler.java:1884)
>
> at
> org.eclipse.emf.ecore.xmi.impl.XMLHandler.createDocumentRoot (XMLHandler.java:1443)
>
> [snip]
>
> I suspect there's a reasonable explanation for this, but my question
> is: Why does introduction of an element within the schema affect the
> way my object (derived from a complexType) is deserialized?
>
> I've found that setting XMLResource.OPTION_EXTENDED_META_DATA =
> Boolean.FALSE makes the problem go away, but I'm not sure that's a
> solution as (a)
Because then it's more of an XMI type of serialization and document
roots have no special significance.
> We set that option to resolve earlier issues and (b) my EMF book tells
> me it's required for Ecore derived from XML Schema.
>
> Any comments much appreciated.
You really need a global element of a type that matches the type of
instance you want to serialize at the root. You might be interested in
this option and the corresponding one needed to deserialize:
/**
* When {@link #OPTION_EXTENDED_META_DATA} is used,
* this load option set to Boolean.TRUE will direct the
deserializer to suppress creating a document root instance.
* This option is typically used in combination with {@link
#OPTION_ELEMENT_HANDLER}.
* @since 2.4
*/
String OPTION_SUPPRESS_DOCUMENT_ROOT = "SUPPRESS_DOCUMENT_ROOT";
>
> Ben.
--------------030901090605030009020102
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: 8bit
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta content="text/html;charset=UTF-8" http-equiv="Content-Type">
</head>
<body bgcolor="#ffffff" text="#000000">
Ben,<br>
<br>
Comments below.<br>
<br>
<br>
Ben Tenne wrote:
<blockquote cite="mid:he5u9r$frl$1@build.eclipse.org" type="cite">I'm
hoping someone can help me understand some behaviour I'm seeing. I'm
not suggesting there's a bug here, I just don't fully grasp what's
happening.
<br>
<br>
Consider this simple XML Schema:
<br>
<br>
<?xml version="1.0" encoding="UTF-8"?>
<br>
<xs:schema xmlns:xs=<a class="moz-txt-link-rfc2396E" href="http://www.w3.org/2001/XMLSchema">"http://www.w3.org/2001/XMLSchema"</a>
xmlns=<a class="moz-txt-link-rfc2396E" href="http://testing.com/hello">"http://testing.com/hello"</a>
targetNamespace=<a class="moz-txt-link-rfc2396E" href="http://testing.com/hello">"http://testing.com/hello"</a>>
<br>
<xs:complexType name="Car">
<br>
<xs:sequence>
<br>
<xs:element name="colour" type="xs:string"/>
<br>
</xs:sequence>
<br>
</xs:complexType>
<br>
</xs:schema>
<br>
<br>
Transforming to EMF, I have a class to represent Car.
<br>
<br>
I then instantiate my Car class and serialize it to XML with the
following options (which are all necessary for various reasons for the
system I'm working on):
<br>
<br>
XMLResource.OPTION_EXTENDED_META_DATA = Boolean.TRUE
<br>
XMLResource.OPTION_SAVE_TYPE_INFORMATION = Boolean.TRUE
<br>
XMLResource.OPTION_KEEP_DEFAULT_CONTENT = Boolean.TRUE
<br>
XMLResource.OPTION_ENCODING = "UTF-8"
<br>
<br>
<br>
This results in the following XML
<br>
<br>
<?xml version="1.0" encoding="UTF-8"?>
<br>
<hello:Car xmlns:hello=<a class="moz-txt-link-rfc2396E" href="http://testing.com/hello">"http://testing.com/hello"</a>>
<br>
<colour>Purple</colour>
<br>
</hello:Car>
<br>
</blockquote>
In the absence of a DocumentRoot, the complex type's name will be used
to serialize the instance; unfortunately that doesn't actually conform
to the schema. And of course given your schema, there is no possible
conforming serialization because there are no global element
declarations.<br>
<blockquote cite="mid:he5u9r$frl$1@build.eclipse.org" type="cite"><br>
I then deserialize this with the following options set:
<br>
<br>
XMLResource.OPTION_EXTENDED_META_DATA = Boolean.TRUE <br>
XMLResource.OPTION_DEFER_ATTACHMENT = Boolean.TRUE
<br>
XMLResource.OPTION_USE_PARSER_POOL = (my pool instance)
<br>
XMLResource.OPTION_USE_DEPRECATED_METHODS = Boolean.FALSE
<br>
<br>
<br>
Deserialization gives me a Car object, just like the one I started
with. Everything is fine so far.
<br>
<br>
I now alter my schema:
<br>
<br>
<?xml version="1.0" encoding="UTF-8"?>
<br>
<xs:schema xmlns:xs=<a class="moz-txt-link-rfc2396E" href="http://www.w3.org/2001/XMLSchema">"http://www.w3.org/2001/XMLSchema"</a>
xmlns=<a class="moz-txt-link-rfc2396E" href="http://testing.com/hello">"http://testing.com/hello"</a>
targetNamespace=<a class="moz-txt-link-rfc2396E" href="http://testing.com/hello">"http://testing.com/hello"</a>>
<br>
<br>
<br>
<xs:element name="myElement" type="xs:int"/>
<br>
<br>
<br>
<xs:complexType name="Car">
<br>
<xs:sequence>
<br>
<xs:element name="colour" type="xs:string"/>
<br>
</xs:sequence>
<br>
</xs:complexType>
<br>
</xs:schema>
<br>
<br>
(i.e. I've added the 'myElement' declaration within the root)
<br>
</blockquote>
So now that you've added a global element, there's a document root...<br>
<blockquote cite="mid:he5u9r$frl$1@build.eclipse.org" type="cite"><br>
If I repeat my serialization and deserialization, as I did before, then
the serialization results in the same XML, but deserialization fails
with:
<br>
</blockquote>
Now, because there is a document root, it notices that there is no Car
feature in the document root, so it's upset that this isn't conforming
to your schema.<br>
<blockquote cite="mid:he5u9r$frl$1@build.eclipse.org" type="cite"><br>
org.eclipse.emf.ecore.xmi.FeatureNotFoundException: Feature 'Car' not
found. (, 2, 51)
<br>
at
org.eclipse.emf.ecore.xmi.impl.XMLHandler.reportUnknownFeatu re(XMLHandler.java:1976)
<br>
at
org.eclipse.emf.ecore.xmi.impl.XMLHandler.handleUnknownFeatu re(XMLHandler.java:1940)
<br>
at
org.eclipse.emf.ecore.xmi.impl.XMLHandler.handleFeature(XMLH andler.java:1884)
<br>
at
org.eclipse.emf.ecore.xmi.impl.XMLHandler.createDocumentRoot (XMLHandler.java:1443)
<br>
[snip]
<br>
<br>
I suspect there's a reasonable explanation for this, but my question
is: Why does introduction of an element within the schema affect the
way my object (derived from a complexType) is deserialized?
<br>
<br>
I've found that setting XMLResource.OPTION_EXTENDED_META_DATA =
Boolean.FALSE makes the problem go away, but I'm not sure that's a
solution as (a)</blockquote>
Because then it's more of an XMI type of serialization and document
roots have no special significance.<br>
<blockquote cite="mid:he5u9r$frl$1@build.eclipse.org" type="cite"> We
set that option to resolve earlier issues and (b) my EMF book tells me
it's required for Ecore derived from XML Schema.
<br>
<br>
Any comments much appreciated.
<br>
</blockquote>
You really need a global element of a type that matches the type of
instance you want to serialize at the root. You might be interested
in this option and the corresponding one needed to deserialize:<br>
<blockquote> /**<br>
* When {@link #OPTION_EXTENDED_META_DATA} is used, <br>
* this load option set to Boolean.TRUE will direct the deserializer
to suppress creating a document root instance.<br>
* This option is typically used in combination with {@link
#OPTION_ELEMENT_HANDLER}.<br>
* @since 2.4<br>
*/<br>
String OPTION_SUPPRESS_DOCUMENT_ROOT = "SUPPRESS_DOCUMENT_ROOT";<br>
</blockquote>
<br>
<blockquote cite="mid:he5u9r$frl$1@build.eclipse.org" type="cite"><br>
Ben.
<br>
</blockquote>
</body>
</html>
--------------030901090605030009020102--
Ed Merks
Professional Support: https://www.macromodeling.com/
|
|
| |
Re: Deserializing object based on complexType when elements are present in schema [message #500244 is a reply to message #499195] |
Wed, 25 November 2009 13:39 |
Ben Tenne Messages: 50 Registered: October 2009 |
Member |
|
|
Hello again.
As discussed above, I'm now using OPTION_ELEMENT_HANDLER on save. Consider this schema:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified" xmlns="http://example.com/extension" targetNamespace="http://example.com/extension">
<xs:element name="CustomerElement" type="Customer"/>
<xs:complexType name="Customer">
<xs:sequence>
<xs:element name="customerId" type="xs:string"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="PersonalCustomer">
<xs:complexContent>
<xs:extension base="Customer">
<xs:sequence>
<xs:element name="personalId" type="xs:int"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:complexType name="BusinessCustomer">
<xs:complexContent>
<xs:extension base="Customer">
<xs:sequence>
<xs:element name="businessName" type="xs:string"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:schema>
So, we have a Customer complex type acting as super-type to PersonalCustomer and BusinessCustomer. I've defined a single element, CustomerElement, of type Customer.
If I create a BusinessCustomer and serialize it, I get the following XML. ElementHandlerImpl can't find an exactly-matching feature in DocumentRoot to match BusinessCustomer, so walks up the hierarchy, hits Customer and ends up using a CustomerElement. The trouble is, in the absense of an xsi:type attribute on the root (I'm using OPTION_SAVE_TYPE_INFORMATION on save, but it has no effect here), there is no record of the fact a BusinessCustomer is being referenced as a Customer:
<?xml version="1.0" encoding="UTF-8"?>
<extension:CustomerElement xmlns:extension="http://example.com/extension">
<extension:customerId>123</extension:customerId>
<extension:businessName>Ringo Sammon</extension:businessName>
</extension:CustomerElement>
This won't validate against my schema and fails deserialization:
org.eclipse.emf.ecore.resource.Resource$IOWrappedException: Feature 'businessName' not found. (, 4, 27)
at org.eclipse.emf.ecore.xmi.impl.XMLLoadImpl.handleErrors(XMLLoadImpl.java:83)
at org.eclipse.emf.ecore.xmi.impl.XMLLoadImpl.load(XMLLoadImpl.java:191)
at org.eclipse.emf.ecore.xmi.impl.XMLResourceImpl.doLoad(XMLResourceImpl.java:180)
[snip]
If I alter the serialized XML as follow, it will then validate against my schema (I use XMLSpy for such validation) and deserialize correctly:
<?xml version="1.0" encoding="UTF-8"?>
<extension:CustomerElement xmlns:extension="http://example.com/extension" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="extension:BusinessCustomer">
<extension:customerId>123</extension:customerId>
<extension:businessName>Ringo Sammon</extension:businessName>
</extension:CustomerElement>
I realise that adding an element to my schema and making its type BusinessCustomer will resolve this, but looking at the source for ElementHandlerImpl, I got this impression that my scenario would be supported as-is.
Thanks in advance for any help.
Cheers,
Ben.
|
|
|
Re: Deserializing object based on complexType when elements are present in schema [message #500275 is a reply to message #500244] |
Wed, 25 November 2009 14:38 |
Ed Merks Messages: 33217 Registered: July 2009 |
Senior Member |
|
|
Ben,
Yes, it looks like at the top level, it's not doing any checking to see
if an xsi:type is needed. Perhaps you can create a good (failing) test
case and open a bugzilla with that.
Ben Tenne wrote:
> Hello again.
>
> As discussed above, I'm now using OPTION_ELEMENT_HANDLER on save.
> Consider this schema:
>
> <?xml version="1.0" encoding="UTF-8"?>
> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
> elementFormDefault="qualified" attributeFormDefault="unqualified"
> xmlns="http://example.com/extension"
> targetNamespace="http://example.com/extension">
> <xs:element name="CustomerElement" type="Customer"/>
> <xs:complexType name="Customer">
> <xs:sequence>
> <xs:element name="customerId" type="xs:string"/>
> </xs:sequence>
> </xs:complexType>
> <xs:complexType name="PersonalCustomer">
> <xs:complexContent>
> <xs:extension base="Customer">
> <xs:sequence>
> <xs:element name="personalId" type="xs:int"/>
> </xs:sequence>
> </xs:extension>
> </xs:complexContent>
> </xs:complexType>
> <xs:complexType name="BusinessCustomer">
> <xs:complexContent>
> <xs:extension base="Customer">
> <xs:sequence>
> <xs:element name="businessName" type="xs:string"/>
> </xs:sequence>
> </xs:extension>
> </xs:complexContent>
> </xs:complexType>
> </xs:schema>
>
> So, we have a Customer complex type acting as super-type to
> PersonalCustomer and BusinessCustomer. I've defined a single element,
> CustomerElement, of type Customer.
>
> If I create a BusinessCustomer and serialize it, I get the following
> XML. ElementHandlerImpl can't find an exactly-matching feature in
> DocumentRoot to match BusinessCustomer, so walks up the hierarchy,
> hits Customer and ends up using a CustomerElement. The trouble is, in
> the absense of an xsi:type attribute on the root (I'm using
> OPTION_SAVE_TYPE_INFORMATION on save, but it has no effect here),
> there is no record of the fact a BusinessCustomer is being referenced
> as a Customer:
>
> <?xml version="1.0" encoding="UTF-8"?>
> <extension:CustomerElement
> xmlns:extension="http://example.com/extension">
> <extension:customerId>123</extension:customerId>
> <extension:businessName>Ringo Sammon</extension:businessName>
> </extension:CustomerElement>
>
> This won't validate against my schema and fails deserialization:
>
> org.eclipse.emf.ecore.resource.Resource$IOWrappedException: Feature
> 'businessName' not found. (, 4, 27)
> at
> org.eclipse.emf.ecore.xmi.impl.XMLLoadImpl.handleErrors(XMLL oadImpl.java:83)
>
> at
> org.eclipse.emf.ecore.xmi.impl.XMLLoadImpl.load(XMLLoadImpl. java:191)
> at
> org.eclipse.emf.ecore.xmi.impl.XMLResourceImpl.doLoad(XMLRes ourceImpl.java:180)
>
> [snip]
>
> If I alter the serialized XML as follow, it will then validate against
> my schema (I use XMLSpy for such validation) and deserialize correctly:
>
> <?xml version="1.0" encoding="UTF-8"?>
> <extension:CustomerElement
> xmlns:extension="http://example.com/extension"
> xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
> xsi:type="extension:BusinessCustomer">
> <extension:customerId>123</extension:customerId>
> <extension:businessName>Ringo Sammon</extension:businessName>
> </extension:CustomerElement>
>
> I realise that adding an element to my schema and making its type
> BusinessCustomer will resolve this, but looking at the source for
> ElementHandlerImpl, I got this impression that my scenario would be
> supported as-is.
>
> Thanks in advance for any help.
>
> Cheers,
> Ben.
Ed Merks
Professional Support: https://www.macromodeling.com/
|
|
| |
Goto Forum:
Current Time: Mon Sep 23 06:08:34 GMT 2024
Powered by FUDForum. Page generated in 0.03420 seconds
|