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

Bug 339935

Summary: Not able to avoid xsi:type in instance serializations with no target namespace in schema
Product: [Modeling] EMF Reporter: Nalini Ganapati <nalinig>
Component: XML/XMIAssignee: Ed Merks <Ed.Merks>
Status: RESOLVED WORKSFORME QA Contact:
Severity: normal    
Priority: P3    
Version: unspecified   
Target Milestone: ---   
Hardware: PC   
OS: Windows XP   
Whiteboard:
Attachments:
Description Flags
Test xsd to reproduce the problem none

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.