Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.
Bug 339935 - Not able to avoid xsi:type in instance serializations with no target namespace in schema
Summary: Not able to avoid xsi:type in instance serializations with no target namespac...
Status: RESOLVED WORKSFORME
Alias: None
Product: EMF
Classification: Modeling
Component: XML/XMI (show other bugs)
Version: unspecified   Edit
Hardware: PC Windows XP
: P3 normal (vote)
Target Milestone: ---   Edit
Assignee: Ed Merks CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2011-03-14 14:27 EDT by Nalini Ganapati CLA
Modified: 2011-03-19 00:10 EDT (History)
0 users

See Also:


Attachments
Test xsd to reproduce the problem (1.41 KB, application/octet-stream)
2011-03-14 14:29 EDT, Nalini Ganapati CLA
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Nalini Ganapati CLA 2011-03-14 14:27:28 EDT
Build Identifier: M20100909-0800

When there is no targetNamespace specified in the schema, the elements under the root are serialized fine without the namespace, but all the other derived elements have the xsi:types.

Reproducible: Always

Steps to Reproduce:
To reproduce :
1. Use the attached xsd(based on the example xsd from http://wiki.eclipse.org/EMF/Recipes#Recipe:_Exploiting_Substitution_Groups_Without_Polluting_Your_Generated_API) file to base a genmodel and generate model, edit and editor code. 
2. Modify the generated resource factory to use the XMLResource.OPTION_ELEMENT_HANDLER option.
3. Bring up a runtime workbench.
4. Open the Test Model Wizard from the runtime workbench and select FileSystem as the initial model object.
5. Add a folder, then a file to this folder from the editor. Save.
6. Note that the serialized instance contains the xsi:type pollution for the file element.
Comment 1 Nalini Ganapati CLA 2011-03-14 14:29:26 EDT
Created attachment 191156 [details]
Test xsd to reproduce the problem
Comment 2 Ed Merks CLA 2011-03-14 17:04:48 EDT
If you use this in your generated factory the element handler will work better

  public TestResourceFactoryImpl()
  {
    super();
    extendedMetaData = 
      new BasicExtendedMetaData(new EPackageRegistryImpl(EPackage.Registry.INSTANCE))
      {
        {
          extendedMetaDataHolderCache = new HashMap<EModelElement, Object>();
        }
      };

Please try it and let me know...
Comment 3 Nalini Ganapati CLA 2011-03-14 17:34:13 EDT
Thanks. I just tried with the lines added to the TestResourceFactoryImpl constructor. The wizard created the filesystem as the intial model object, but the editor threw exceptions while loading -

org.eclipse.emf.ecore.xmi.PackageNotFoundException: Package with uri 'null' not found. (platform:/resource/p/My.test, 2, 14)
at org.eclipse.emf.ecore.xmi.impl.XMLHandler.createObjectByType(XMLHandler.java:1307)
	at org.eclipse.emf.ecore.xmi.impl.XMLHandler.createTopObject(XMLHandler.java:1468)
	at org.eclipse.emf.ecore.xmi.impl.XMLHandler.processElement(XMLHandler.java:1019)
	at org.eclipse.emf.ecore.xmi.impl.XMLHandler.startElement(XMLHandler.java:1001)
	at org.eclipse.emf.ecore.xmi.impl.XMLHandler.startElement(XMLHandler.java:712)
	at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.startElement(Unknown Source)
	at com.sun.org.apache.xerces.internal.parsers.AbstractXMLDocumentParser.emptyElement(Unknown Source)
	at com.sun.org.apache.xerces.internal.impl.dtd.XMLDTDValidator.emptyElement(Unknown Source)
	at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanStartElement(Unknown Source)
	at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl$ContentDriver.scanRootElementHook(Unknown Source)
...

and 

org.eclipse.emf.ecore.xmi.ClassNotFoundException: Class 'fileSystem' is not found or is abstract. (platform:/resource/p/My.test, 2, 14)
	at org.eclipse.emf.ecore.xmi.impl.XMLHandler.validateCreateObjectFromFactory(XMLHandler.java:2244)
	at org.eclipse.emf.ecore.xmi.impl.XMLHandler.validateCreateObjectFromFactory(XMLHandler.java:2235)
	at org.eclipse.emf.ecore.xmi.impl.XMLHandler.createObjectByType(XMLHandler.java:1332)
	at org.eclipse.emf.ecore.xmi.impl.XMLHandler.createTopObject(XMLHandler.java:1468)
...
Comment 4 Ed Merks CLA 2011-03-14 17:50:04 EDT
I tried the following in the generated example, so it looks to me like it properly saves and loads.  Your problem sounds like one of not using the generated resource factory.  Set a breakpoint in the resource factory to verify it's kicking in...

  public static void main(String[] args)
  {
    // Create a resource set to hold the resources.
    //
    ResourceSet resourceSet = new ResourceSetImpl();
    
    // Register the appropriate resource factory to handle all file extensions.
    //
    resourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap().put
      (Resource.Factory.Registry.DEFAULT_EXTENSION, 
       new TestResourceFactoryImpl());

    // Register the package to ensure it is available during loading.
    //
    resourceSet.getPackageRegistry().put
      (TestPackage.eNS_URI, 
       TestPackage.eINSTANCE);
        
    // If there are no arguments, emit an appropriate usage message.
    //
    if (args.length == 0)
    {
      System.out.println("Enter a list of file paths or URIs that have content like this:");
      try
      {
        Resource resource = resourceSet.createResource(URI.createURI("http:///My.test"));
        DocumentRoot documentRoot = TestFactory.eINSTANCE.createDocumentRoot();
        FileSystem fileSystem = TestFactory.eINSTANCE.createFileSystem();
        Folder folder = TestFactory.eINSTANCE.createFolder();
        Test.File file = TestFactory.eINSTANCE.createFile();
        Folder subfolder = TestFactory.eINSTANCE.createFolder();
        documentRoot.setFileSystem(fileSystem);
        fileSystem.getFolders().add(folder);
        folder.getMembers().add(file);
        folder.getMembers().add(subfolder);
        resource.getContents().add(documentRoot);
        resource.save(System.out, null);
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        resource.save(out, null);
        Resource resource2 = resourceSet.createResource(URI.createURI("http:///My2.test"));
        resource2.load(new ByteArrayInputStream(out.toByteArray()), null);
        resource2.save(System.out, null);
      }
      catch (IOException exception) 
      {
        exception.printStackTrace();
      }
    }
Comment 5 Nalini Ganapati CLA 2011-03-14 18:17:02 EDT
Thanks Ed. I just tried again and noticed that I had mistakenly commented out extendedMetaData.putPackage(null, TestPackage.eINSTANCE) in the constructor for the resource factory. So, it now works, both the scenario I described in comment 3 and with your suggestion in comment 4.

Is there any documentation that describes the usage of extendedMetaDataHolderCache?
Comment 6 Ed Merks CLA 2011-03-14 18:35:27 EDT
No, the BasicExtendedMeta has only the Javadoc.  I don't expect that you'd ever have figured out this was a good way to avoid the problem you were seeing. The problem is that ExtendedMetaData.INSTANCE returns different results from the local BasicExtendedMetaData instance. The local one has null in the registry by the global one doesn't (so the answer for getNamespace(EPackage) differs. But the caching is shared with the global instance.  It's a long story... Unfortunately there can be a great many separate packages all wanting to use the null namespace, so we have to do ugly things to support that...
Comment 7 Ed Merks CLA 2011-03-19 00:10:40 EDT
I think this is a reasonable workaround for an issue doesn't come up frequently.