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

Bug 321765

Summary: Invalid Hibernate config generated for XSD with @EmbeddedId annotation
Product: [Modeling] EMF Reporter: Ed Peters <ed.peters>
Component: TeneoAssignee: Martin Taal <mtaal>
Status: RESOLVED FIXED QA Contact:
Severity: normal    
Priority: P3 CC: d.nikita.e, kevin.page
Version: unspecified   
Target Milestone: ---   
Hardware: PC   
OS: Windows 7   
Whiteboard:
Attachments:
Description Flags
XSD used to reproduce
none
Stack trace from Hibernate
none
Generated Hibernate mapping none

Description Ed Peters CLA 2010-08-04 14:04:19 EDT
Build Identifier: 1.1.2-v201007191154

I tried to use the attached XSD to create a Data Store, and I got the attached exception.  It seems like the Hibernate mapping file that got generated (also attached) was not valid.  (There is a test case for this in the Appian/Teneo repository at Assembla.)

Reproducible: Always

Steps to Reproduce:
1. create a data store with the supplied XSD
2. check out the resulting exception
Comment 1 Ed Peters CLA 2010-08-04 14:04:54 EDT
Created attachment 175856 [details]
XSD used to reproduce
Comment 2 Ed Peters CLA 2010-08-04 14:05:17 EDT
Created attachment 175857 [details]
Stack trace from Hibernate
Comment 3 Ed Peters CLA 2010-08-04 14:05:41 EDT
Created attachment 175858 [details]
Generated Hibernate mapping
Comment 4 Martin Taal CLA 2010-08-18 08:41:35 EDT
Fix available in cvs, will be in the next build
Comment 5 Martin Taal CLA 2010-08-18 10:22:42 EDT
Fix is available in build of today on interim update site:
http://download.eclipse.org/modeling/emf/teneo/updates/1.2.0/interim/
Comment 6 Kevin Page CLA 2011-07-27 14:33:39 EDT
Build Identifier: 1.2.0.v201107080556

Hi Martin,

This seems to still be an issue.  I saw a similar SAXParseException with the same XSD from the Appian/Teneo Assembla test project, although the generated hibernate mapping is now different:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping auto-import="false">
	<class entity-name="Employee" abstract="false" lazy="false" name="org.eclipse.emf.ecore.impl.DynamicEObjectImpl" table="`employee`">
		<meta attribute="eclassName" inherit="false">Employee</meta>
		<meta attribute="epackage" inherit="false">urn:appian:jpa</meta>
		<composite-id name="employeePK" class="org.eclipse.emf.teneo.hibernate.mapping.SerializableDynamicEObjectImpl" access="org.eclipse.emf.teneo.hibernate.mapping.property.EReferencePropertyHandler">
			<meta attribute="eclassName" inherit="false">EmployeePK</meta>
			<meta attribute="epackage" inherit="false">urn:appian:jpa</meta>
		</composite-id>
		<property name="title" lazy="false" insert="true" update="true" not-null="true" unique="false" type="java.lang.String">
			<column not-null="true" unique="false" name="`title`"/>
		</property>
		<property name="salary" lazy="false" insert="true" update="true" not-null="true" unique="false" type="java.math.BigInteger">
			<column not-null="true" unique="false" name="`salary`"/>
		</property>
	</class>
</hibernate-mapping>



org.hibernate.InvalidMappingException: Unable to read XML
	at org.hibernate.util.xml.MappingReader.readMappingDocument(MappingReader.java:101)
	at org.hibernate.cfg.Configuration.add(Configuration.java:510)
	at org.hibernate.cfg.Configuration.add(Configuration.java:506)
	at org.hibernate.cfg.Configuration.addXML(Configuration.java:655)
	at org.eclipse.emf.teneo.hibernate.HbSessionDataStore.mapModel(HbSessionDataStore.java:226)
	at org.eclipse.emf.teneo.hibernate.HbSessionDataStore.initialize(HbSessionDataStore.java:98)
	at com.appiancorp.jpa.AbstractTestBase.createDataStore(AbstractTestBase.java:158)
	at com.appiancorp.jpa.AbstractTestBase.processXsd(AbstractTestBase.java:179)
	at com.appiancorp.jpa.JpaAnnotationTest.testEmbeddedId(JpaAnnotationTest.java:36)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
	at java.lang.reflect.Method.invoke(Method.java:597)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
	at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
	at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:31)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:73)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:46)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:180)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:41)
	at org.junit.runners.ParentRunner$1.evaluate(ParentRunner.java:173)
	at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
	at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:31)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:220)
	at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:49)
	at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Caused by: org.xml.sax.SAXParseException: The content of element type "composite-id" is incomplete, it must match "(meta*,(key-property|key-many-to-one)+,generator?)".
	at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.createSAXParseException(ErrorHandlerWrapper.java:195)
	at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.error(ErrorHandlerWrapper.java:131)
	at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:384)
	at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:318)
	at com.sun.org.apache.xerces.internal.impl.dtd.XMLDTDValidator.handleEndElement(XMLDTDValidator.java:2017)
	at com.sun.org.apache.xerces.internal.impl.dtd.XMLDTDValidator.endElement(XMLDTDValidator.java:901)
	at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanEndElement(XMLDocumentFragmentScannerImpl.java:1782)
	at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(XMLDocumentFragmentScannerImpl.java:2938)
	at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:648)
	at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(XMLNSDocumentScannerImpl.java:140)
	at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:511)
	at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:808)
	at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:737)
	at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:119)
	at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1205)
	at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(SAXParserImpl.java:522)
	at org.dom4j.io.SAXReader.read(SAXReader.java:465)
	at org.hibernate.util.xml.MappingReader.readMappingDocument(MappingReader.java:75)
	... 32 more
Comment 7 Martin Taal CLA 2011-08-03 15:49:42 EDT
Hi Kevin,
Sorry for the later reply, it kind of slipped through my fingers.

The problem is that the generated mapping does not have a key-property or key-many-to-one inside the composite-id. The only reason for this can be if the referenced eclass (which models the composite id) does not have any efeatures.'

I checked and Teneo has a testcase for this one which passes. The testmodel I use is the one attached by Ed. Can you post the snippet here with your model which has the embeddedId annotation and the referenced complextype which has the composite ids?

gr. Martin
Comment 8 Kevin Page CLA 2011-08-03 16:23:30 EDT
(In reply to comment #7)
> Hi Kevin,
> Sorry for the later reply, it kind of slipped through my fingers.
> 
> The problem is that the generated mapping does not have a key-property or
> key-many-to-one inside the composite-id. The only reason for this can be if the
> referenced eclass (which models the composite id) does not have any efeatures.'
> 
> I checked and Teneo has a testcase for this one which passes. The testmodel I
> use is the one attached by Ed. Can you post the snippet here with your model
> which has the embeddedId annotation and the referenced complextype which has
> the composite ids?
> 
> gr. Martin

Hi Martin,

Thanks for taking a look.  I used the model attached above, "XSD used to reproduce".  In my test case, I get the model XSD as a String and then use the following Java code to load the model (please excuse the mess, I inlined the functions we were using to make this example simpler).  The exception occurs during initialize() on the last line:

    InputStream xsdIs = IOUtils.toInputStream(xsdStr, "UTF-8");
    ResourceSet resourceSet = new ResourceSetImpl();
    resourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap().put(
      "*", new XSDResourceFactoryImpl());
    XSDResourceImpl resource = (XSDResourceImpl) resourceSet.createResource(
      URI.createURI("*.xsd"));
    resource.load(xsdIs, null);
    XSDSchema schema = resource.getSchema();
    schema.update(false);
    XSDEcoreBuilder builder = new XSDEcoreBuilder();
    builder.generate(schema);
    Map<String, EPackage> resultPackages = builder.getTargetNamespaceToEPackageMap();
    EPackage.Registry resultReg = new EPackageRegistryImpl();
    resultReg.putAll(resultPackages);
    EPackage ePackage = resultReg.getEPackage("urn:appian:jpa");
    EPackage[] ePackages = new EPackage[] {resultReg.getEPackage("urn:appian:jpa")};
    HbSessionDataStore ds = new HbSessionDataStore();
    
    Properties hbdsProps = new Properties();
    hbdsProps.setProperty(Environment.DRIVER, "com.mysql.jdbc.Driver");
    hbdsProps.setProperty(Environment.URL,
      "jdbc:mysql://localhost/TestDB?useUnicode=true&characterEncoding=UTF-8");
    hbdsProps.setProperty(Environment.USER, "test");
    hbdsProps.setProperty(Environment.DIALECT,
      org.hibernate.dialect.MySQLInnoDBDialect.class.getName());

    // Hibernate properties.
    hbdsProps.setProperty(Environment.CURRENT_SESSION_CONTEXT_CLASS, "thread");
    hbdsProps.setProperty(Environment.HBM2DDL_AUTO, "create-drop");

    // Teneo properties.
    hbdsProps.setProperty(PersistenceOptions.MAP_DOCUMENT_ROOT, "false");
    hbdsProps.setProperty(PersistenceOptions.JOIN_COLUMN_NAMING_STRATEGY, "unique");
    hbdsProps.setProperty(PersistenceOptions.JOIN_TABLE_NAMING_STRATEGY, "ejb3");
    hbdsProps.setProperty(PersistenceOptions.JOIN_TABLE_FOR_NON_CONTAINED_ASSOCIATIONS, "true");
    hbdsProps.setProperty(PersistenceOptions.ALWAYS_VERSION, "false");
    hbdsProps.setProperty(PersistenceOptions.INHERITANCE_MAPPING, InheritanceType.TABLE_PER_CLASS.toString());
    hbdsProps.setProperty(PersistenceOptions.EXTRA_ANNOTATION_SOURCES, "appian.jpa");

    ds.setDataStoreProperties(hbdsProps);
    ds.setEPackages(ePackages);
    ds.setPackageRegistry(resultReg);
    ds.initialize();
Comment 9 Martin Taal CLA 2011-08-03 16:42:02 EDT
If you have the teneo source code. Can you do some debugging?

Can you put a breakpoint in this method:
IdMapper.processEmbeddedId

and then specifically the for loop at lone 153, it does not seem to walk over the efeatures, or they are not there. Can you see what happens there?

gr. Martin
Comment 10 Kevin Page CLA 2011-08-03 17:00:39 EDT
It looks like aClass.getPaEStructuralFeatures() is empty on line 153, where aClass is the "EmployeePK" class.

Stepping into PAnnotatedEClassImpl.getPaEStructuralFeatures(), I see that the instance member "paEStructuralFeatures" is an empty EObjectContainmentWithInverseEList.

Putting a breakpoint on PAnnotatedEClassImpl.getPaEStructuralFeatures() line 323 where paEStructuralFeatures is set, it looks like this line is called for EmployeePK by the following call stack:

HbAnnotatedEClassImpl(PAnnotatedEClassImpl).getPaEStructuralFeatures() line: 323	
HbEAnnotationParserImporter(EAnnotationParserImporter).process(PAnnotatedEClass) line: 86	
HbEAnnotationParserImporter(EAnnotationParserImporter).process(PAnnotatedEPackage) line: 76	
HbEAnnotationParserImporter(EAnnotationParserImporter).process(PAnnotatedModel) line: 68	
PersistenceMappingBuilder.buildMapping(List<EPackage>, PersistenceOptions, ExtensionManager) line: 142	
PersistenceMappingBuilder.buildMapping(EPackage[], PersistenceOptions, ExtensionManager) line: 73	
HbSessionDataStore(HbDataStore).mapEPackages() line: 1025	
HbSessionDataStore.mapModel() line: 192	
HbSessionDataStore.initialize() line: 98	

In constructing the EObjectContainmentWithInverseEList, the parameters are:

dataClass: org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEStructuralFeature
owner: EClass/EmployeePK
featureID: 4
inverseFeatureID: 9

I'm not sure where this list gets added to, it's empty at this point.

Thanks,

Kevin
Comment 11 Martin Taal CLA 2011-08-03 17:07:31 EDT
Hi Kevin,
My feel is that the actual eclass can not be found, so something with the model, the aClass has a reference to an EClass (something like modelElement). Can you check if that EClass has estructural features? And that the epackage of the eclass is valid and as you expect?

gr. Martin
Comment 12 Martin Taal CLA 2011-08-03 18:19:33 EDT
Hi Kevin,
In addition to my previous remark, can you check that the epackages read from the xsd are correct and that the EClass referenced by the aClass is indeed part of the exact instance read from the epackage (not sure if you know the java debugger in eclipse shows the instance id).

I will be away without email connection until saturday. If this is really getting high priority you can always call me on my cell. Marco has my mobile number, it is listed in the bottom of the emails I have sent him.

gr. Martin
Comment 13 Kevin Page CLA 2011-08-04 10:59:11 EDT
(In reply to comment #12)
> Hi Kevin,
> In addition to my previous remark, can you check that the epackages read from
> the xsd are correct and that the EClass referenced by the aClass is indeed part
> of the exact instance read from the epackage (not sure if you know the java
> debugger in eclipse shows the instance id).
> 
> I will be away without email connection until saturday. If this is really
> getting high priority you can always call me on my cell. Marco has my mobile
> number, it is listed in the bottom of the emails I have sent him.
> 
> gr. Martin

It looks like the attached "XSD used to reproduce" was using was missing the "xsd:sequence" element for the EmployeePK type.  Once I added that, the structural features showed up correctly and there was no error reading the hibernate mapping XML.  Thanks for your help!