Issue Details (XML | Word | Printable)

Key: NUCRDBMS-115
Type: New Feature New Feature
Status: Closed Closed
Resolution: Fixed
Priority: Minor Minor
Assignee: Unassigned
Reporter: Martin Taal
Votes: 0
Watchers: 1
Operations

If you were logged in you would be able to see more operations.
DataNucleus Store RDBMS

Support embedded inherited objects, and embedded reference/interface objects

Created: 31/Oct/05 06:24 PM   Updated: 09/Dec/11 03:15 PM   Resolved: 22/Nov/11 04:30 PM
Component/s: Schema
Affects Version/s: None
Fix Version/s: 3.0.4


 Description  « Hide
 Hi,
I have a member which is declared in java with an interface type. This member should be embedded. I try to combine embedded with implementation-classes to let jpox know which implementation class I am using for the interface. The enhancer fails with the message that the member is declared with a type (the interface type) which is not persistence capable. Which is true as it is an interface. However because I also specify the implementation-classes extension I hoped that this would help, but it doesn't apparently.

Did I do something wrong in my metadata (see below) or is it possible for jpox to
use the implementation-classes also for embedded elements?

Thanks for any help here!

gr. Martin

<jdo>

<package name="org.elver.store.test.emf.annotations.component">

<class name="ComponentOne" identity-type="datastore" requires-extent="true"
detachable="true" persistence-modifier="persistence-capable"
embedded-only="true" table="ComponentOne">

<inheritance strategy="new-table">
<discriminator column="CLASS_DISCRIMINATOR" strategy="class-name" index="true"/>
</inheritance>

<field name="firstName" persistence-modifier="persistent">
</field>

<field name="age" persistence-modifier="persistent">
</field>
<field name="hairColor" persistence-modifier="persistent" null-value="none">
<column allows-null="true"/>
</field>
</class>

</package>

<package name="org.elver.store.test.emf.annotations.component.impl">

<class name="ItemImpl" identity-type="datastore" requires-extent="true"
detachable="true" persistence-modifier="persistence-capable" table="Item">

<implements name="org.elver.store.test.emf.annotations.component.Item"/>

<implements name="org.eclipse.emf.ecore.EObject"/>

<implements name="org.eclipse.emf.common.notify.Notifier"/>

<inheritance strategy="new-table">
<discriminator column="CLASS_DISCRIMINATOR" strategy="class-name" index="true"/>
</inheritance>

<field name="emfComponent" persistence-modifier="persistent" dependent="true" delete-action="restrict" embedded="true">
<extension vendor-name="jpox" key="implementation-classes"
value="org.elver.store.test.emf.annotations.component.impl.EMFComponentImpl" />
<embedded>

<field name="firstName" persistence-modifier="persistent" null-value="exception">
</field>

<field name="age" persistence-modifier="persistent">
</field>
</embedded>
</field>

<field name="nonEmfComponent" persistence-modifier="persistent" dependent="true" delete-action="restrict">
<collection element-type="org.elver.store.test.emf.annotations.component.ComponentOne" dependent-element="true"/>
<element>
<embedded>

<field name="firstName" persistence-modifier="persistent">
</field>

<field name="age" persistence-modifier="persistent">
</field>
</embedded>
</element>
<order column="ITEMNONEMFCOMPONENT_IDX"/>
<foreign-key delete-action="restrict" update-action="cascade"/>
</field>
</class>

<class name="EMFComponentImpl" identity-type="datastore" requires-extent="true"
detachable="true" persistence-modifier="persistence-capable"
embedded-only="true" table="EMFComponent">

<implements name="org.elver.store.test.emf.annotations.component.EMFComponent"/>

<implements name="org.eclipse.emf.ecore.EObject"/>

<implements name="org.eclipse.emf.common.notify.Notifier"/>

<inheritance strategy="new-table">
<discriminator column="CLASS_DISCRIMINATOR" strategy="class-name" index="true"/>
</inheritance>

<field name="firstName" persistence-modifier="persistent" null-value="exception">
</field>

<field name="age" persistence-modifier="persistent">
</field>
<field name="ageESet" persistence-modifier="persistent" null-value="none">
<column allows-null="true"/>
</field>
</class>

</package>

</jdo>

Sort Order: Ascending order - Click to sort in descending order
Andy Jefferson added a comment - 22/Nov/05 09:53 AM
As mentioned in the JPOX docs, embedded inheritance and embedded reference fields are not supported and are very low priority.

Andy Jefferson added a comment - 15/Jun/07 03:15 PM
Taken from [ENHANCER-94]
Five classes:
 base classe A
 B inherits from A, C inherits from B
 D inherits from A, E inherits from D

Inheritance strategy:
 A new-table
 B subclass-table, C new-table
 D new-table, E superclass-table

E references one C (embedded).
 
org.jpox.metadata.InvalidMetaDataException: Class org.jpox.test.C has field B.dimension declared in MetaData, but this field doesnt exist in the class!
at org.jpox.metadata.EmbeddedMetaData.populate(EmbeddedMetaData.java:316)
at org.jpox.metadata.AbstractPropertyMetaData.populate(AbstractPropertyMetaData.java:909)
at org.jpox.enhancer.bcel.metadata.BCELFieldMetaData.populate(BCELFieldMetaData.java:287)
at org.jpox.metadata.ClassMetaData.populatePropertyMetaData(ClassMetaData.java:562)
at org.jpox.metadata.ClassMetaData.populate(ClassMetaData.java:258)
at org.jpox.metadata.MetaDataManager.populateFileMetaData(MetaDataManager.java:1547)
at org.jpox.metadata.MetaDataManager.initialise(MetaDataManager.java:291)
at org.jpox.enhancer.JPOXEnhancer.getFileMetaDataForInput(JPOXEnhancer.java:716)
at org.jpox.enhancer.JPOXEnhancer.main(JPOXEnhancer.java:531)

Andy Jefferson added a comment - 15/Jun/07 03:16 PM
Provided testcase from user "nicolas" on [ENHANCER-94]

Andy Jefferson added a comment - 07/Aug/07 09:54 AM
CVS HEAD had some changes recently to allow some level of interface fields being embedded, but was in the context of "persistent-interfaces" which is differend to your situation. You could try a nightly build to see what the situation is now

Martin Taal added a comment - 19/Aug/07 09:59 PM
Hi Andy,
Thanks, I am still at version 1.1.8 and it will be a while (few months) before I move Teneo over to the newest jpox version (1.2). I will probably retry it then.

gr. Martin

Guido Anzuoni added a comment - 27/Feb/09 04:55 PM
I am trying to add support for derived embedded objects as for http://www.jpox.org/servlet/forum/viewthread_thread,5462
I have modified org.datanucleus.metadata.EmbeddedMetaData populate() method traversing inheritance tree instead of searching in the candidate class only:

              Field cls_field = null;
                Class tgtcls = embeddedClass;
                while (tgtcls != null && cls_field == null) {
try
{
cls_field = tgtcls.getDeclaredField(fieldFmd.getName());
}
catch (Exception e)
{

tgtcls = tgtcls.getSuperclass();
if (!PersistenceCapable.class.isAssignableFrom(tgtcls)) {
// MetaData field doesn't exist in the class!
throw new InvalidMetaDataException(LOCALISER,
"044071", embeddedClass.getName(), fieldFmd.getFullFieldName());
}
}


Well, I can create the table, persist object and retrieve instances without problems in case of 1 -> 1 (container -> embedded) relationship.
Is it a correct approach ?

Andy Jefferson added a comment - 27/Feb/09 05:38 PM
What about during enhancement ? is the embedded object superclass PC yet ? Don't think so.
Use metadata to know if the embedded class superclass is persistent. Be careful when loading metadata of other classes during populate/initialise since they probably won't be initialised at that point and so you cant refer to some attributes (pcSuperclassName for example)

Guido Anzuoni added a comment - 28/Feb/09 12:08 AM
Yes, you are right, even if I am not sure how I obtained enhanced classes (maybe when I was simply navigating up to java.lang.Object class)
I have modified the inheritance traversal as:
                Field cls_field = null;
                Class tgtcls = embeddedClass;
                AbstractClassMetaData tgtCmd = embCmd;
                while (tgtcls != null && cls_field == null) {
                 if (!tgtCmd.isPopulated()) {
                 tgtCmd.populate(clr, primary);
                 }
                 if (!tgtCmd.isInitialised()) {
                 tgtCmd.initialise(clr);
                 }
                
try
{
cls_field = tgtcls.getDeclaredField(fieldFmd.getName());
}
catch (Exception e)
{

tgtcls = tgtcls.getSuperclass();
tgtCmd = embCmd.getMetaDataManager().getMetaDataForClass(tgtcls, clr);
if (!PersistenceCapable.class.isAssignableFrom(tgtcls) && tgtCmd == null) {
// MetaData field doesn't exist in the class!
throw new InvalidMetaDataException(LOCALISER,
"044071", embeddedClass.getName(), fieldFmd.getFullFieldName());
}
}
                }

and now seems to be OK.
Anyway, considering the runtime aspects only, what do you think about the approach ?
Tables are automatically created, but I guess that using schema tool wont make any difference.
I have tried both <embedded/> tag and explicit specification of columns for members of subclass and superclass.
I not sure but I am quite confident to be not so far from the solution...

Andy Jefferson added a comment - 28/Feb/09 10:19 AM
Don't populate/initialise ANY other metadata from within populate/initialise of a different class. The only place this should be done is when we have a class and it populates/initialises its superclass. Adding populate/initialise of other classes will result in cyclic relations, and we just removed all such things just before 1.1.0. You only need to know if the particular class is persistable, so no need to do anything with the metadata is there?

No problem with the basic approach of going up to superclasses and filling in the fields/properties default mapping info.

Guido Anzuoni added a comment - 05/Mar/09 12:10 PM
Patch to allow inheritance in embedded objects.
Standard test case missing, even if tested in local env with 1-1 relation

Andy Jefferson added a comment - 13/Mar/09 06:29 PM
Thx for the patch.
Tests required :
"test.jdo.rdbms.datastore" SchemaTest - test the schema generation (datastore id)
"test.jdo.rdbms.application" SchemaTest - test the schema generation (app id)
"test.jdo.orm.datastore" EmbeddedTest - test the persistence (datastore id)
"test.jdo.orm.application" EmbeddedTest - test the persistence (app id)

Andy Jefferson added a comment - 11/Nov/10 06:01 PM
Testcase from thread 5918 that makes use of inheritance and embedded PC objects. Run schematool

Andy Jefferson added a comment - 15/Nov/11 11:42 AM
test.samples now has classes org.jpox.samples.embedded.FittedKitchen, Oven and MultifunctionOven. These are adequate to demonstrate that the schema is *not* correctly generated for embedded inheritance ... need a discriminator column adding, yet this is not currently done.

Andy Jefferson added a comment - 22/Nov/11 04:30 PM
SVN trunk now supports simple inherited embedded classes. Remaining problem is that JDO doesn't yet allow specification of a discriminator for determination of the inherited type, so it falls back to the discriminator of the type itself (in metadata) if it was specified.