public class Client
{
String name;
...
}
The basic idea is as follows. We want to define the metadata programmatically for our class
PersistenceManagerFactory pmf = JDOHelper.getPersistenceManagerFactory(propsFile);
...
JDOMetadata md = pmf.newMetadata();
So our PMF has created a new metadata object to work with. This corresponds to the top level of a metadata file. We can now add packages and classes as required to define the persistence. So something like this ...
PackageMetadata pmd = md.newPackageMetadata("org.datanucleus");
so we have a package for our class. Now let's define the persistence of the class :-
ClassMetadata cmd = pmd.newClassMetadata("Client");
cmd.setTable("CLIENT").setDetachable(true);
cmd.setIdentityType(IdentityType.DATASTORE);
cmd.setPersistenceModifier(ClassPersistenceModifier.PERSISTENCE_CAPABLE);
and the class needs persistence for the field "name" defining (since we don't want to accept default persistence specifications) :-
FieldMetadata fmd = cmd.newFieldMetadata("name");
fmd.setNullValue(NullValue.DEFAULT).setColumn("client_name");
fmd.setIndexed(true).setUnique(true);
and of course we can define everything else as required, so to persist it into its own table, and to have versioning, etc :-
InheritanceMetadata inhmd = cmd.newInheritanceMetadata();
inhmd.setStrategy(InheritanceStrategy.NEW_TABLE);
DiscriminatorMetadata dmd = inhmd.newDiscriminatorMetadata();
dmd.setColumn("disc").setValue("Client");
dmd.setStrategy(DiscriminatorStrategy.VALUE_MAP).setIndexed(Indexed.TRUE);
VersionMetadata vermd = cmd.newVersionMetadata();
vermd.setStrategy(VersionStrategy.VERSION_NUMBER);
vermd.setColumn("version").setIndexed(Indexed.TRUE);
All that remains to do is enable this metadata in our persistence process
pmf.registerMetadata(md);
Key points :
- you get your starting object (JDOMetadata) from the PMF.
- you only need to add fields and attributes that are non-defaulted. As with a metadata file, all fields of standard types are by default persistent
- you can chain mutator operations. I've split them above for readability, but they could have been on a single line.
- once populated you register the start object with the PMF. Thereafter when that class is used in persistence it will use that metadata definition.
- If a class is already known to the PMF (has its file-based metadata registered) then you can't redefine it using this API.
The logical next step is to be able to view the metadata defined in XML or annotations. You can do this as follows
ComponentMetadata compmd = pmf.getMetadata("mydomain.MyClass");
and you can now interrogate the metadata of this class (cast it to ClassMetadata or InterfaceMetadata). Please note that it is not supported being able to change metadata that is already registered, just view it.
Final point worth making is that the DataNucleus implementation of these metadata classes will output the (approximate) XML text representation when you call "toString()" on the metadata object, so for example the metadata generation above results in
<jdo>
<package name="org.datanucleus">
<class name="Client" type="datastore" modifier="persistence-capable" table="CLIENT" detachable="true">
<inheritance strategy="new-table">
<discriminator strategy="value-map" column="disc" value="Client" indexed="true">
</discriminator>
</inheritance>
<version strategy="version-number" indexed="true" column="version">
</version>
<field name="name" column="client_name" indexed="true" unique="true">
</field>
</class>
</package>
</jdo>
so you also have an easy way of converting your API generated metadata into XML should you wish to transfer it to a file for later use.
This is now in DataNucleus SVN trunk. You need the latest Apache JDO API jar (also in DataNucleus SVN, and in the nightly build repositories).