/**********************************************************************
Copyright (c) 2006 Andy Jefferson and others. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Contributors:
...
**********************************************************************/
package org.datanucleus.api.jdo.metadata;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import javax.jdo.annotations.Column;
import javax.jdo.annotations.DiscriminatorStrategy;
import javax.jdo.annotations.Embedded;
import javax.jdo.annotations.Extension;
import javax.jdo.annotations.FetchGroup;
import javax.jdo.annotations.FetchPlan;
import javax.jdo.annotations.ForeignKey;
import javax.jdo.annotations.ForeignKeyAction;
import javax.jdo.annotations.IdGeneratorStrategy;
import javax.jdo.annotations.Index;
import javax.jdo.annotations.InheritanceStrategy;
import javax.jdo.annotations.Join;
import javax.jdo.annotations.NullValue;
import javax.jdo.annotations.PersistenceModifier;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.Query;
import javax.jdo.annotations.SequenceStrategy;
import javax.jdo.annotations.Unique;
import javax.jdo.annotations.VersionStrategy;
import org.datanucleus.ClassLoaderResolver;
import org.datanucleus.exceptions.NucleusException;
import org.datanucleus.metadata.AbstractClassMetaData;
import org.datanucleus.metadata.AbstractMemberMetaData;
import org.datanucleus.metadata.ArrayMetaData;
import org.datanucleus.metadata.ClassMetaData;
import org.datanucleus.metadata.ClassPersistenceModifier;
import org.datanucleus.metadata.CollectionMetaData;
import org.datanucleus.metadata.ColumnMetaData;
import org.datanucleus.metadata.ContainerMetaData;
import org.datanucleus.metadata.DiscriminatorMetaData;
import org.datanucleus.metadata.ElementMetaData;
import org.datanucleus.metadata.EmbeddedMetaData;
import org.datanucleus.metadata.ExtensionMetaData;
import org.datanucleus.metadata.FetchGroupMetaData;
import org.datanucleus.metadata.FetchPlanMetaData;
import org.datanucleus.metadata.FieldMetaData;
import org.datanucleus.metadata.FieldPersistenceModifier;
import org.datanucleus.metadata.ForeignKeyMetaData;
import org.datanucleus.metadata.IdentityMetaData;
import org.datanucleus.metadata.IdentityStrategy;
import org.datanucleus.metadata.IdentityType;
import org.datanucleus.metadata.IndexMetaData;
import org.datanucleus.metadata.IndexedValue;
import org.datanucleus.metadata.InheritanceMetaData;
import org.datanucleus.metadata.InterfaceMetaData;
import org.datanucleus.metadata.JoinMetaData;
import org.datanucleus.metadata.KeyMetaData;
import org.datanucleus.metadata.MapMetaData;
import org.datanucleus.metadata.MetaData;
import org.datanucleus.metadata.MetaDataManager;
import org.datanucleus.metadata.OrderMetaData;
import org.datanucleus.metadata.PackageMetaData;
import org.datanucleus.metadata.PrimaryKeyMetaData;
import org.datanucleus.metadata.PropertyMetaData;
import org.datanucleus.metadata.QueryMetaData;
import org.datanucleus.metadata.SequenceMetaData;
import org.datanucleus.metadata.UniqueMetaData;
import org.datanucleus.metadata.ValueMetaData;
import org.datanucleus.metadata.VersionMetaData;
import org.datanucleus.metadata.annotations.AbstractAnnotationReader;
import org.datanucleus.metadata.annotations.AnnotationObject;
import org.datanucleus.metadata.annotations.Member;
import org.datanucleus.util.ClassUtils;
import org.datanucleus.util.NucleusLogger;
import org.datanucleus.util.StringUtils;
/**
* Implementation for Annotation Reader for java annotations using the JDO definition.
*/
public class JDOAnnotationReader extends AbstractAnnotationReader
{
/**
* Constructor.
* @param mgr MetaData manager
*/
public JDOAnnotationReader(MetaDataManager mgr)
{
super(mgr);
// We support JDO and DataNucleus annotations in this reader.
setSupportedAnnotationPackages(new String[] {"javax.jdo", "org.datanucleus"});
}
/**
* Method to process the "class" level annotations and create the outline ClassMetaData object
* @param pmd Parent PackageMetaData
* @param cls The class
* @param annotations Annotations for this class
* @param clr ClassLoader resolver
* @return The ClassMetaData/InterfaceMetaData (or null if no annotations)
*/
protected AbstractClassMetaData processClassAnnotations(PackageMetaData pmd, Class cls,
AnnotationObject[] annotations, ClassLoaderResolver clr)
{
if (pmd == null)
{
// TODO Localise this message
throw new NucleusException("No PackageMetaData specified to use for annotations");
}
AbstractClassMetaData cmd = null;
if (annotations != null && annotations.length > 0)
{
// Process @PersistenceCapable/@PersistenceAware to determine if persistable in any way
for (int i=0;i<annotations.length;i++)
{
String annName = annotations[i].getName();
if (annName.equals(JDOAnnotationUtils.PERSISTENCE_CAPABLE))
{
// PersistenceCapable class
HashMap<String, Object> annotationValues = annotations[i].getNameValueMap();
if (cmd != null && cmd.getPersistenceModifier() == ClassPersistenceModifier.PERSISTENCE_AWARE)
{
throw new NucleusException("Class " + cls.getName() +
" is annotated as @PersistenceAware yet it also has @PersistenceCapable!" +
" You cannot have both annotations!");
}
if (cls.isInterface())
{
cmd = new InterfaceMetaData(pmd, ClassUtils.getClassNameForClass(cls));
}
else
{
cmd = new ClassMetaData(pmd, ClassUtils.getClassNameForClass(cls));
}
cmd.setTable((String)annotationValues.get("table"));
cmd.setCatalog((String)annotationValues.get("catalog"));
cmd.setSchema((String)annotationValues.get("schema"));
cmd.setDetachable((String)annotationValues.get("detachable"));
cmd.setRequiresExtent((String)annotationValues.get("requiresExtent"));
String idClassName = null;
Class idClass = (Class)annotationValues.get("objectIdClass");
if (idClass != null && idClass != void.class)
{
idClassName = idClass.getName();
}
cmd.setObjectIdClass(idClassName);
cmd.setPersistenceModifier(ClassPersistenceModifier.PERSISTENCE_CAPABLE);
cmd.setEmbeddedOnly((String)annotationValues.get("embeddedOnly"));
javax.jdo.annotations.IdentityType idTypeVal = (javax.jdo.annotations.IdentityType)annotationValues.get("identityType");
String identityType = JDOAnnotationUtils.getIdentityTypeString(idTypeVal);
cmd.setIdentityType(IdentityType.getIdentityType(identityType));
cmd.setCacheable((String)annotationValues.get("cacheable"));
String serializeRead = (String)annotationValues.get("serializeRead");
if (serializeRead != null)
{
cmd.setSerializeRead(serializeRead.equals("true") ? true : false);
}
JDOAnnotationUtils.addExtensionsToMetaData(cmd,
(Extension[])annotationValues.get("extensions"));
// Members typically providing specification of overridden fields/properties
Persistent[] members = (Persistent[])annotationValues.get("members");
if (members != null)
{
// Add on the fields/properties direct to the metadata for the class/interface
for (int j=0;j<members.length;j++)
{
String memberName = members[j].name();
if (memberName.indexOf('.') > 0)
{
memberName = memberName.substring(memberName.lastIndexOf('.')+1);
}
boolean isField = isMemberOfClassAField(cls, memberName);
AbstractMemberMetaData fmd = getFieldMetaDataForPersistent(cmd, members[j], isField);
cmd.addMember(fmd);
}
}
}
else if (annName.equals(JDOAnnotationUtils.PERSISTENCE_AWARE))
{
// PersistenceAware class
if (cmd != null && cmd.getPersistenceModifier() == ClassPersistenceModifier.PERSISTENCE_CAPABLE)
{
throw new NucleusException("Class " + cls.getName() +
" is annotated as @PersistenceCapable yet it also has @PersistenceAware!" +
" You cannot have both annotations!");
}
cmd = new ClassMetaData(pmd, ClassUtils.getClassNameForClass(cls));
cmd.setPersistenceModifier(ClassPersistenceModifier.PERSISTENCE_AWARE);
}
}
if (cmd != null)
{
// Class is persistable so process remaining annotations
InheritanceMetaData inhmd = null;
DiscriminatorMetaData dismd = null;
IdentityMetaData idmd = null;
PrimaryKeyMetaData pkmd = null;
VersionMetaData vermd = null;
JoinMetaData[] joins = null;
QueryMetaData[] queries = null;
FetchPlanMetaData[] fetchPlans = null;
FetchGroupMetaData[] fetchGroups = null;
SequenceMetaData seqmd = null;
String cacheable = null;
boolean embeddedOnly = false;
ColumnMetaData[] unmappedColumns = null;
HashSet<IndexMetaData> indices = null;
HashSet<UniqueMetaData> uniqueKeys = null;
HashSet<ForeignKeyMetaData> fks = null;
HashSet<ExtensionMetaData> extensions = null;
for (int i=0;i<annotations.length;i++)
{
HashMap<String, Object> annotationValues = annotations[i].getNameValueMap();
String annName = annotations[i].getName();
if (annName.equals(JDOAnnotationUtils.EMBEDDED_ONLY))
{
embeddedOnly = true;
}
else if (annName.equals(JDOAnnotationUtils.VERSION))
{
VersionStrategy versionStrategy = (VersionStrategy)annotationValues.get("strategy");
String strategy = JDOAnnotationUtils.getVersionStrategyString(versionStrategy);
String indexed = (String)annotationValues.get("indexed");
String column = (String)annotationValues.get("column");
Column[] columns = (Column[])annotationValues.get("columns");
vermd = new VersionMetaData();
vermd.setStrategy(strategy);
vermd.setColumnName(column);
vermd.setIndexed(IndexedValue.getIndexedValue(indexed));
if (columns != null && columns.length > 0)
{
// Only use the first column
ColumnMetaData colmd =
JDOAnnotationUtils.getColumnMetaDataForColumnAnnotation(columns[0]);
vermd.addColumn(colmd);
}
JDOAnnotationUtils.addExtensionsToMetaData(vermd, (Extension[])annotationValues.get("extensions"));
}
else if (annName.equals(JDOAnnotationUtils.DATASTORE_IDENTITY))
{
String strategy = JDOAnnotationUtils.getIdentityStrategyString(
(IdGeneratorStrategy)annotationValues.get("strategy"));
String customStrategy = (String)annotationValues.get("customStrategy");
if (!StringUtils.isWhitespace(customStrategy))
{
// User has provided an extension strategy
strategy = customStrategy;
}
String sequence = (String)annotationValues.get("sequence");
String column = (String)annotationValues.get("column");
Column[] columns = (Column[])annotationValues.get("columns");
idmd = new IdentityMetaData();
idmd.setColumnName(column);
idmd.setValueStrategy(IdentityStrategy.getIdentityStrategy(strategy));
idmd.setSequence(sequence);
if (columns != null && columns.length > 0)
{
// Only use the first column
ColumnMetaData colmd =
JDOAnnotationUtils.getColumnMetaDataForColumnAnnotation(columns[0]);
idmd.addColumn(colmd);
}
JDOAnnotationUtils.addExtensionsToMetaData(idmd, (Extension[])annotationValues.get("extensions"));
}
else if (annName.equals(JDOAnnotationUtils.PRIMARY_KEY))
{
String pkName = (String)annotationValues.get("name");
String pkColumn = (String)annotationValues.get("column");
Column[] columns = (Column[])annotationValues.get("columns");
pkmd = new PrimaryKeyMetaData();
pkmd.setName(pkName);
pkmd.setColumnName(pkColumn);
if (columns != null && columns.length > 0)
{
for (int j=0;j<columns.length;j++)
{
pkmd.addColumn(JDOAnnotationUtils.getColumnMetaDataForColumnAnnotation(columns[j]));
}
}
}
else if (annName.equals(JDOAnnotationUtils.JOINS))
{
if (joins != null)
{
NucleusLogger.METADATA.warn(LOCALISER.msg("044210", cmd.getFullClassName()));
}
Join[] js = (Join[])annotationValues.get("value");
if (js != null && js.length > 0)
{
joins = new JoinMetaData[js.length];
for (int j=0;j<js.length;j++)
{
joins[j] = new JoinMetaData();
joins[j].setTable(js[j].table());
joins[j].setColumnName(js[j].column());
joins[j].setIndexed(IndexedValue.getIndexedValue(js[j].indexed()));
joins[j].setOuter(js[j].outer());
joins[j].setUnique(js[j].unique());
joins[j].setDeleteAction(JDOAnnotationUtils.getForeignKeyActionString(js[j].deleteAction()));
}
}
}
else if (annName.equals(JDOAnnotationUtils.JOIN))
{
if (joins != null)
{
NucleusLogger.METADATA.warn(LOCALISER.msg("044210", cmd.getFullClassName()));
}
joins = new JoinMetaData[1];
joins[0] = new JoinMetaData();
joins[0].setTable((String)annotationValues.get("table"));
joins[0].setColumnName((String)annotationValues.get("column"));
joins[0].setIndexed(IndexedValue.getIndexedValue((String)annotationValues.get("indexed")));
joins[0].setOuter((String)annotationValues.get("outer"));
joins[0].setUnique((String)annotationValues.get("unique"));
joins[0].setDeleteAction(((ForeignKeyAction)annotationValues.get("deleteAction")).toString());
JDOAnnotationUtils.addExtensionsToMetaData(joins[0], (Extension[])annotationValues.get("extensions"));
}
else if (annName.equals(JDOAnnotationUtils.INHERITANCE))
{
String strategy = JDOAnnotationUtils.getInheritanceStrategyString(
(InheritanceStrategy)annotationValues.get("strategy"));
String customStrategy = (String)annotationValues.get("customStrategy");
if (!StringUtils.isWhitespace(customStrategy))
{
// User has provided an extension strategy
strategy = customStrategy;
}
inhmd = new InheritanceMetaData();
inhmd.setStrategy(strategy);
}
else if (annName.equals(JDOAnnotationUtils.DISCRIMINATOR))
{
DiscriminatorStrategy discriminatorStrategy = (DiscriminatorStrategy)annotationValues.get("strategy");
String strategy = JDOAnnotationUtils.getDiscriminatorStrategyString(discriminatorStrategy);
String column = (String)annotationValues.get("column");
String indexed = (String)annotationValues.get("indexed");
String value = (String)annotationValues.get("value");
Column[] columns = (Column[])annotationValues.get("columns");
dismd = new DiscriminatorMetaData();
dismd.setColumnName(column);
dismd.setValue(value);
dismd.setStrategy(strategy);
dismd.setIndexed(indexed);
if (columns != null && columns.length > 0)
{
// Only use the first column
ColumnMetaData colmd =
JDOAnnotationUtils.getColumnMetaDataForColumnAnnotation(columns[0]);
dismd.setColumnMetaData(colmd);
}
}
else if (annName.equals(JDOAnnotationUtils.QUERIES))
{
if (queries != null)
{
NucleusLogger.METADATA.warn(LOCALISER.msg("044209", cmd.getFullClassName()));
}
Query[] qs = (Query[])annotationValues.get("value");
queries = new QueryMetaData[qs.length];
for (int j=0;j<queries.length;j++)
{
String lang = JDOAnnotationUtils.getQueryLanguageName(qs[j].language());
String resultClassName = (qs[j].resultClass() != null && qs[j].resultClass() != void.class ?
qs[j].resultClass().getName() : null);
queries[j] = new QueryMetaData(qs[j].name());
queries[j].setScope(cls.getName());
queries[j].setLanguage(lang);
queries[j].setUnmodifiable(qs[j].unmodifiable());
queries[j].setResultClass(resultClassName);
queries[j].setUnique(qs[j].unique());
queries[j].setFetchPlanName(qs[j].fetchPlan());
queries[j].setQuery(qs[j].value());
JDOAnnotationUtils.addExtensionsToMetaData(queries[j], qs[j].extensions());
}
}
else if (annName.equals(JDOAnnotationUtils.QUERY))
{
if (queries != null)
{
NucleusLogger.METADATA.warn(LOCALISER.msg("044209", cmd.getFullClassName()));
}
queries = new QueryMetaData[1];
String unmodifiable = "" + annotationValues.get("unmodifiable");
Class resultClassValue = (Class)annotationValues.get("resultClass");
String resultClassName =
(resultClassValue != null && resultClassValue != void.class ? resultClassValue.getName() : null);
String lang = JDOAnnotationUtils.getQueryLanguageName((String)annotationValues.get("language"));
queries[0] = new QueryMetaData((String)annotationValues.get("name"));
queries[0].setScope(cls.getName());
queries[0].setLanguage(lang);
queries[0].setUnmodifiable(unmodifiable);
queries[0].setResultClass(resultClassName);
queries[0].setUnique((String)annotationValues.get("unique"));
queries[0].setFetchPlanName((String)annotationValues.get("fetchPlan"));
queries[0].setQuery((String)annotationValues.get("value"));
JDOAnnotationUtils.addExtensionsToMetaData(queries[0], (Extension[])annotationValues.get("extensions"));
}
else if (annName.equals(JDOAnnotationUtils.FETCHPLANS))
{
if (fetchPlans != null)
{
NucleusLogger.METADATA.warn(LOCALISER.msg("044207", cmd.getFullClassName()));
}
FetchPlan[] plans = (FetchPlan[])annotationValues.get("value");
fetchPlans = new FetchPlanMetaData[plans.length];
for (int j=0;j<plans.length;j++)
{
fetchPlans[j] = new FetchPlanMetaData(plans[j].name());
fetchPlans[j].setMaxFetchDepth(plans[j].maxFetchDepth());
fetchPlans[j].setFetchSize(plans[j].fetchSize());
int numGroups = plans[j].fetchGroups().length;
for (int k=0;k<numGroups;k++)
{
FetchGroupMetaData fgmd = new FetchGroupMetaData(plans[j].fetchGroups()[k]);
fetchPlans[j].addFetchGroup(fgmd);
}
}
}
else if (annName.equals(JDOAnnotationUtils.FETCHPLAN))
{
if (fetchPlans != null)
{
NucleusLogger.METADATA.warn(LOCALISER.msg("044207", cmd.getFullClassName()));
}
fetchPlans = new FetchPlanMetaData[1];
int maxFetchDepth = ((Integer)annotationValues.get("maxFetchDepth")).intValue();
int fetchSize = ((Integer)annotationValues.get("fetchSize")).intValue();
fetchPlans[0] = new FetchPlanMetaData((String)annotationValues.get("name"));
fetchPlans[0].setMaxFetchDepth(maxFetchDepth);
fetchPlans[0].setFetchSize(fetchSize);
}
else if (annName.equals(JDOAnnotationUtils.FETCHGROUPS))
{
if (fetchGroups != null)
{
NucleusLogger.METADATA.warn(LOCALISER.msg("044208", cmd.getFullClassName()));
}
FetchGroup[] groups = (FetchGroup[])annotationValues.get("value");
fetchGroups = new FetchGroupMetaData[groups.length];
for (int j=0;j<groups.length;j++)
{
fetchGroups[j] = new FetchGroupMetaData(groups[j].name());
fetchGroups[j].setPostLoad(groups[j].postLoad());
int numFields = groups[j].members().length;
for (int k=0;k<numFields;k++)
{
FieldMetaData fmd = new FieldMetaData(fetchGroups[j],
groups[j].members()[k].name());
fmd.setRecursionDepth(groups[j].members()[k].recursionDepth());
fetchGroups[j].addMember(fmd);
}
int numGroups = groups[j].fetchGroups().length;
for (int k=0;k<numGroups;k++)
{
FetchGroupMetaData subgrp = new FetchGroupMetaData(groups[j].fetchGroups()[k]);
fetchGroups[j].addFetchGroup(subgrp);
}
}
}
else if (annName.equals(JDOAnnotationUtils.FETCHGROUP))
{
if (fetchGroups != null)
{
NucleusLogger.METADATA.warn(LOCALISER.msg("044208", cmd.getFullClassName()));
}
fetchGroups = new FetchGroupMetaData[1];
fetchGroups[0] = new FetchGroupMetaData((String)annotationValues.get("name"));
fetchGroups[0].setPostLoad((String)annotationValues.get("postLoad"));
Persistent[] fields = (Persistent[])annotationValues.get("members");
if (fields != null)
{
for (int j=0;j<fields.length;j++)
{
FieldMetaData fmd = new FieldMetaData(fetchGroups[0],
fields[j].name());
fmd.setRecursionDepth(fields[j].recursionDepth());
fetchGroups[0].addMember(fmd);
}
}
}
else if (annName.equals(JDOAnnotationUtils.SEQUENCE))
{
String seqName = (String)annotationValues.get("name");
String seqStrategy = JDOAnnotationUtils.getSequenceStrategyString(
(SequenceStrategy)annotationValues.get("strategy"));
String seqSeq = (String)annotationValues.get("datastoreSequence");
Class seqFactory = (Class)annotationValues.get("factoryClass");
String seqFactoryClassName = null;
if (seqFactory != null && seqFactory != void.class)
{
seqFactoryClassName = seqFactory.getName();
}
Integer seqSize = (Integer)annotationValues.get("allocationSize");
Integer seqStart = (Integer)annotationValues.get("initialValue");
seqmd = new SequenceMetaData(seqName, seqStrategy);
seqmd.setFactoryClass(seqFactoryClassName);
seqmd.setDatastoreSequence(seqSeq);
if (seqSize != null)
{
seqmd.setAllocationSize(seqSize);
}
if (seqStart != null)
{
seqmd.setInitialValue(seqStart);
}
JDOAnnotationUtils.addExtensionsToMetaData(seqmd, (Extension[])annotationValues.get("extensions"));
}
else if (annName.equals(JDOAnnotationUtils.INDICES))
{
// Multiple Indices for the class
Index[] values = (Index[])annotationValues.get("value");
if (values != null && values.length > 0)
{
indices = new HashSet<IndexMetaData>(values.length);
for (int j=0;j<values.length;j++)
{
IndexMetaData idxmd = JDOAnnotationUtils.getIndexMetaData(values[j].name(), values[j].table(),
"" + values[j].unique(), values[j].members(), values[j].columns());
if (idxmd.getNumberOfColumns() == 0 && idxmd.getNumberOfMembers() == 0)
{
NucleusLogger.METADATA.warn(LOCALISER.msg("044204", cls.getName()));
}
else
{
indices.add(idxmd);
}
}
}
}
else if (annName.equals(JDOAnnotationUtils.INDEX))
{
// Single Index for the class
String name = (String)annotationValues.get("name");
String table = (String)annotationValues.get("table");
String unique = (String)annotationValues.get("unique");
String[] members = (String[])annotationValues.get("members");
Column[] columns = (Column[])annotationValues.get("columns");
IndexMetaData idxmd = JDOAnnotationUtils.getIndexMetaData(name, table, unique, members, columns);
if (idxmd.getNumberOfColumns() == 0 && idxmd.getNumberOfMembers() == 0)
{
NucleusLogger.METADATA.warn(LOCALISER.msg("044204", cls.getName()));
}
else
{
indices = new HashSet<IndexMetaData>(1);
indices.add(idxmd);
}
}
else if (annName.equals(JDOAnnotationUtils.UNIQUES))
{
// Multiple Unique Constraints for the class
Unique[] values = (Unique[])annotationValues.get("value");
if (values != null && values.length > 0)
{
uniqueKeys = new HashSet<UniqueMetaData>(values.length);
for (int j=0;j<values.length;j++)
{
UniqueMetaData unimd = JDOAnnotationUtils.getUniqueMetaData(values[j].name(),
values[j].table(), "" + values[j].deferred(), values[j].members(), values[j].columns());
if (unimd.getNumberOfColumns() == 0 && unimd.getNumberOfMembers() == 0)
{
NucleusLogger.METADATA.warn(LOCALISER.msg("044205", cls.getName()));
}
else
{
uniqueKeys.add(unimd);
}
}
}
}
else if (annName.equals(JDOAnnotationUtils.UNIQUE))
{
// Single Unique constraint for the class
String name = (String)annotationValues.get("name");
String table = (String)annotationValues.get("table");
String deferred = (String)annotationValues.get("deferred");
String[] members = (String[])annotationValues.get("members");
Column[] columns = (Column[])annotationValues.get("columns");
UniqueMetaData unimd = JDOAnnotationUtils.getUniqueMetaData(name, table, deferred, members, columns);
if (unimd.getNumberOfColumns() == 0 && unimd.getNumberOfMembers() == 0)
{
NucleusLogger.METADATA.warn(LOCALISER.msg("044205", cls.getName()));
}
else
{
uniqueKeys = new HashSet<UniqueMetaData>(1);
uniqueKeys.add(unimd);
}
}
else if (annName.equals(JDOAnnotationUtils.FOREIGNKEYS))
{
// Multiple FKs for the class
ForeignKey[] values = (ForeignKey[])annotationValues.get("value");
if (values != null && values.length > 0)
{
fks = new HashSet<ForeignKeyMetaData>(values.length);
for (int j=0;j<values.length;j++)
{
String deleteAction = JDOAnnotationUtils.getForeignKeyActionString(values[j].deleteAction());
String updateAction = JDOAnnotationUtils.getForeignKeyActionString(values[j].updateAction());
ForeignKeyMetaData fkmd = JDOAnnotationUtils.getFKMetaData(values[j].name(),
values[j].table(), values[j].unique(), "" + values[j].deferred(),
deleteAction, updateAction, values[j].members(), values[j].columns());
if (fkmd.getNumberOfColumns() == 0 && fkmd.getNumberOfMembers() == 0)
{
NucleusLogger.METADATA.warn(LOCALISER.msg("044206", cls.getName()));
}
else
{
fks.add(fkmd);
}
}
}
}
else if (annName.equals(JDOAnnotationUtils.FOREIGNKEY))
{
// Single FK constraint for the class
String name = (String)annotationValues.get("name");
String table = (String)annotationValues.get("table");
String unique = (String)annotationValues.get("unique");
String deferred = (String)annotationValues.get("deferred");
String deleteAction = JDOAnnotationUtils.getForeignKeyActionString(
(ForeignKeyAction)annotationValues.get("deleteAction"));
String updateAction = JDOAnnotationUtils.getForeignKeyActionString(
(ForeignKeyAction)annotationValues.get("updateAction"));
String[] members = (String[])annotationValues.get("members");
Column[] columns = (Column[])annotationValues.get("columns");
ForeignKeyMetaData fkmd = JDOAnnotationUtils.getFKMetaData(name, table, unique, deferred,
deleteAction, updateAction, members, columns);
if (fkmd.getNumberOfColumns() == 0 && fkmd.getNumberOfMembers() == 0)
{
NucleusLogger.METADATA.warn(LOCALISER.msg("044206", cls.getName()));
}
else
{
fks = new HashSet<ForeignKeyMetaData>(1);
fks.add(fkmd);
}
}
else if (annName.equals(JDOAnnotationUtils.COLUMNS))
{
// Unmapped column specification
Column[] cols = (Column[])annotationValues.get("value");
if (cols != null && cols.length > 0)
{
unmappedColumns = new ColumnMetaData[cols.length];
for (int j=0;j<cols.length;j++)
{
unmappedColumns[j] =
JDOAnnotationUtils.getColumnMetaDataForColumnAnnotation(cols[j]);
JDOAnnotationUtils.addExtensionsToMetaData(unmappedColumns[j], cols[j].extensions());
}
}
}
else if (annName.equals(JDOAnnotationUtils.CACHEABLE))
{
String cache = (String)annotationValues.get("value");
if (cache != null)
{
cacheable = cache;
}
}
else if (annName.equals(JDOAnnotationUtils.EXTENSIONS))
{
Extension[] values = (Extension[])annotationValues.get("value");
if (values != null && values.length > 0)
{
extensions = new HashSet<ExtensionMetaData>(values.length);
for (int j=0;j<values.length;j++)
{
ExtensionMetaData extmd = new ExtensionMetaData(values[j].vendorName(),
values[j].key().toString(), values[j].value().toString());
extensions.add(extmd);
}
}
}
else if (annName.equals(JDOAnnotationUtils.EXTENSION))
{
ExtensionMetaData extmd = new ExtensionMetaData((String)annotationValues.get("vendorName"),
(String)annotationValues.get("key"), (String)annotationValues.get("value"));
extensions = new HashSet<ExtensionMetaData>(1);
extensions.add(extmd);
}
else
{
if (!annName.equals(JDOAnnotationUtils.PERSISTENCE_CAPABLE) &&
!annName.equals(JDOAnnotationUtils.PERSISTENCE_AWARE))
{
NucleusLogger.METADATA.error(LOCALISER.msg("044203", cls.getName(),
annotations[i].getName()));
}
}
}
// Either PersistenceCapable, PersistenceAware or PersistentInterface so build up the metadata
NucleusLogger.METADATA.info(LOCALISER.msg("044200", cls.getName(), "JDO"));
if (cmd instanceof ClassMetaData)
{
pmd.addClass((ClassMetaData)cmd);
}
else if (cmd instanceof InterfaceMetaData)
{
pmd.addInterface((InterfaceMetaData)cmd);
}
if (embeddedOnly)
{
cmd.setEmbeddedOnly(true);
}
if (idmd != null)
{
// Datastore identity
idmd.setParent(cmd);
cmd.setIdentityMetaData(idmd);
}
if (pkmd != null)
{
// Primary Key
pkmd.setParent(cmd);
cmd.setPrimaryKeyMetaData(pkmd);
}
if (vermd != null)
{
// Version
vermd.setParent(cmd);
cmd.setVersionMetaData(vermd);
}
if (inhmd != null)
{
// Inheritance
if (dismd != null)
{
inhmd.setDiscriminatorMetaData(dismd);
}
inhmd.setParent(cmd);
cmd.setInheritanceMetaData(inhmd);
}
else if (dismd != null)
{
inhmd = new InheritanceMetaData();
inhmd.setDiscriminatorMetaData(dismd);
cmd.setInheritanceMetaData(inhmd);
}
if (joins != null && joins.length > 0)
{
// Joins
for (int i=0;i<joins.length;i++)
{
cmd.addJoin(joins[i]);
}
}
if (queries != null && queries.length > 0)
{
// Named Queries
for (int i=0;i<queries.length;i++)
{
queries[i].setParent(cmd);
cmd.addQuery(queries[i]);
}
}
if (fetchGroups != null && fetchGroups.length > 0)
{
// Fetch Groups
for (int i=0;i<fetchGroups.length;i++)
{
fetchGroups[i].setParent(cmd);
cmd.addFetchGroup(fetchGroups[i]);
}
}
if (seqmd != null)
{
// Sequence - currently only allowing 1 per class (should really be on the package)
cmd.getPackageMetaData().addSequence(seqmd);
}
if (indices != null)
{
Iterator iter = indices.iterator();
while (iter.hasNext())
{
IndexMetaData idxmd = (IndexMetaData)iter.next();
idxmd.setParent(cmd);
cmd.addIndex(idxmd);
}
}
if (uniqueKeys != null)
{
Iterator iter = uniqueKeys.iterator();
while (iter.hasNext())
{
UniqueMetaData unimd = (UniqueMetaData)iter.next();
unimd.setParent(cmd);
cmd.addUniqueConstraint(unimd);
}
}
if (fks != null)
{
Iterator iter = fks.iterator();
while (iter.hasNext())
{
ForeignKeyMetaData fkmd = (ForeignKeyMetaData)iter.next();
fkmd.setParent(cmd);
cmd.addForeignKey(fkmd);
}
}
if (unmappedColumns != null)
{
for (int i=0;i<unmappedColumns.length;i++)
{
ColumnMetaData colmd = unmappedColumns[i];
colmd.setParent(cmd);
cmd.addUnmappedColumn(colmd);
}
}
if (cacheable != null && cacheable.equalsIgnoreCase("false"))
{
cmd.setCacheable(false);
}
if (extensions != null)
{
Iterator<ExtensionMetaData> iter = extensions.iterator();
while (iter.hasNext())
{
ExtensionMetaData extmd = iter.next();
cmd.addExtension(extmd.getVendorName(), extmd.getKey(), extmd.getValue());
}
}
}
}
return cmd;
}
/**
* Convenience method to process the annotations for a field/property.
* The passed annotations may have been specified on the field or on the getter methods.
* @param cmd The ClassMetaData/InterfaceMetaData to update
* @param member The field/property
* @param annotations Annotations for the field/property
* @param propertyAccessor if there are properties for this class
* @return The FieldMetaData/PropertyMetaData that was added (if any)
*/
protected AbstractMemberMetaData processMemberAnnotations(AbstractClassMetaData cmd, Member member,
AnnotationObject[] annotations, boolean propertyAccessor)
{
AbstractMemberMetaData mmd = null;
if (annotations != null && annotations.length > 0)
{
boolean primaryKey = false;
boolean serialised = false;
boolean nonPersistentField = false;
boolean transactionalField = false;
String cacheable = null;
Class[] elementTypes = null;
String embeddedElement = null;
String serializedElement = null;
String dependentElement = null;
Class keyType = null;
String embeddedKey = null;
String serializedKey = null;
String dependentKey = null;
Class valueType = null;
String embeddedValue = null;
String serializedValue = null;
String dependentValue = null;
String embeddedOwnerField = null;
String embeddedNullIndicatorColumn = null;
String embeddedNullIndicatorValue = null;
Persistent[] embeddedMembers = null;
Persistent[] embeddedElementMembers = null;
Persistent[] embeddedKeyMembers = null;
Persistent[] embeddedValueMembers = null;
ColumnMetaData[] colmds = null;
JoinMetaData joinmd = null;
ElementMetaData elemmd = null;
KeyMetaData keymd = null;
ValueMetaData valuemd = null;
OrderMetaData ordermd = null;
IndexMetaData idxmd = null;
UniqueMetaData unimd = null;
ForeignKeyMetaData fkmd = null;
HashSet<ExtensionMetaData> extensions = null;
for (int i=0;i<annotations.length;i++)
{
String annName = annotations[i].getName();
HashMap<String, Object> annotationValues = annotations[i].getNameValueMap();
if (annName.equals(JDOAnnotationUtils.PERSISTENT))
{
String pk = "" + annotationValues.get("primaryKey");
String dfg = (String)annotationValues.get("defaultFetchGroup");
String nullValue = JDOAnnotationUtils.getNullValueString((NullValue)annotationValues.get("nullValue"));
String embedded = (String)annotationValues.get("embedded");
String serialized = (String)annotationValues.get("serialized");
String dependent = (String)annotationValues.get("dependent");
String valueStrategy = JDOAnnotationUtils.getIdentityStrategyString(
(IdGeneratorStrategy)annotationValues.get("valueStrategy"));
String customValueStrategy = (String)annotationValues.get("customValueStrategy");
if (!StringUtils.isWhitespace(customValueStrategy))
{
// User has provided an extension strategy
valueStrategy = customValueStrategy;
}
String modifier = JDOAnnotationUtils.getFieldPersistenceModifierString(
(PersistenceModifier)annotationValues.get("persistenceModifier"));
if (modifier == null)
{
modifier = FieldPersistenceModifier.PERSISTENT.toString();
}
String sequence = (String)annotationValues.get("sequence");
String mappedBy = (String)annotationValues.get("mappedBy");
String table = (String)annotationValues.get("table");
String column = (String)annotationValues.get("column");
String loadFetchGroup = (String)annotationValues.get("loadFetchGroup");
String fieldTypeName = null;
int recursionDepth = ((Integer)annotationValues.get("recursionDepth")).intValue();
cacheable = (String)annotationValues.get("cacheable");
Class[] fieldTypes = (Class[])annotationValues.get("types");
if (fieldTypes != null && fieldTypes.length > 0)
{
StringBuilder typeStr = new StringBuilder();
for (int j=0;j<fieldTypes.length;j++)
{
if (typeStr.length() > 0)
{
typeStr.append(',');
}
if (fieldTypes[j] != null && fieldTypes[j] != void.class)
{
typeStr.append(fieldTypes[j].getName());
}
}
fieldTypeName = typeStr.toString();
}
dependentElement = (String)annotationValues.get("dependentElement");
serializedElement = (String)annotationValues.get("serializedElement");
embeddedElement = (String)annotationValues.get("embeddedElement");
dependentKey = (String)annotationValues.get("dependentKey");
serializedKey = (String)annotationValues.get("serializedKey");
embeddedKey = (String)annotationValues.get("embeddedKey");
dependentValue = (String)annotationValues.get("dependentValue");
serializedValue = (String)annotationValues.get("serializedValue");
embeddedValue = (String)annotationValues.get("embeddedValue");
if (member.isProperty())
{
// Property
mmd = new PropertyMetaData(cmd, member.getName());
}
else
{
// Field
mmd = new FieldMetaData(cmd, member.getName());
}
mmd.setPersistenceModifier(modifier);
mmd.setDefaultFetchGroup(dfg);
mmd.setPrimaryKey(pk);
mmd.setEmbedded(embedded);
mmd.setSerialised(serialized);
mmd.setDependent(dependent);
mmd.setNullValue(org.datanucleus.metadata.NullValue.getNullValue(nullValue));
mmd.setMappedBy(mappedBy);
mmd.setColumn(column);
mmd.setTable(table);
mmd.setRecursionDepth(recursionDepth);
mmd.setLoadFetchGroup(loadFetchGroup);
mmd.setValueStrategy(valueStrategy);
mmd.setSequence(sequence);
mmd.setFieldTypes(fieldTypeName);
// Add any columns defined on the @Persistent
Column[] columns = (Column[])annotationValues.get("columns");
if (columns != null && columns.length > 0)
{
for (int j=0;j<columns.length;j++)
{
mmd.addColumn(JDOAnnotationUtils.getColumnMetaDataForColumnAnnotation(columns[j]));
}
}
JDOAnnotationUtils.addExtensionsToMetaData(mmd, (Extension[])annotationValues.get("extensions"));
}
else if (annName.equals(JDOAnnotationUtils.PRIMARY_KEY))
{
primaryKey = true;
if (cmd.getIdentityType() == IdentityType.DATASTORE)
{
// ClassMetaData was created as DATASTORE so change it to APPLICATION
cmd.setIdentityType(IdentityType.APPLICATION);
}
}
else if (annName.equals(JDOAnnotationUtils.SERIALIZED))
{
serialised = true;
}
else if (annName.equals(JDOAnnotationUtils.NOTPERSISTENT))
{
nonPersistentField = true;
}
else if (annName.equals(JDOAnnotationUtils.TRANSACTIONAL))
{
transactionalField = true;
}
else if (annName.equals(JDOAnnotationUtils.COLUMNS))
{
// Multiple column specification
Column[] cols = (Column[])annotationValues.get("value");
if (cols != null && cols.length > 0)
{
colmds = new ColumnMetaData[cols.length];
for (int j=0;j<cols.length;j++)
{
colmds[j] = JDOAnnotationUtils.getColumnMetaDataForColumnAnnotation(cols[j]);
JDOAnnotationUtils.addExtensionsToMetaData(colmds[j], cols[j].extensions());
}
}
}
else if (annName.equals(JDOAnnotationUtils.COLUMN))
{
// Single column specification
colmds = new ColumnMetaData[1];
colmds[0] = JDOAnnotationUtils.getColumnMetaDataForAnnotations(annotationValues);
JDOAnnotationUtils.addExtensionsToMetaData(colmds[0], (Extension[])annotationValues.get("extensions"));
}
else if (annName.equals(JDOAnnotationUtils.JOIN))
{
String joinColumn = (String)annotationValues.get("column");
String joinOuter = (String)annotationValues.get("outer");
String deleteAction = JDOAnnotationUtils.getForeignKeyActionString(
(ForeignKeyAction)annotationValues.get("deleteAction"));
String pkName = (String)annotationValues.get("primaryKey");
String fkName = (String)annotationValues.get("foreignKey");
String generateFK = (String)annotationValues.get("generateForeignKey");
String indexed = (String)annotationValues.get("indexed");
String indexName = (String)annotationValues.get("index");
String unique = (String)annotationValues.get("unique");
String uniqueName = (String)annotationValues.get("uniqueKey");
String generatePK = (String)annotationValues.get("generatePrimaryKey");
if (!StringUtils.isWhitespace(uniqueName))
{
unique = "true";
}
if (!StringUtils.isWhitespace(indexName))
{
indexed = "true";
}
Column[] joinColumns = (Column[])annotationValues.get("columns");
joinmd = new JoinMetaData();
joinmd.setColumnName(joinColumn);
joinmd.setOuter(joinOuter);
joinmd.setIndexed(IndexedValue.getIndexedValue(indexed));
joinmd.setUnique(unique);
joinmd.setDeleteAction(deleteAction);
if (!StringUtils.isWhitespace(pkName))
{
PrimaryKeyMetaData pkmd = new PrimaryKeyMetaData();
pkmd.setName(pkName);
joinmd.setPrimaryKeyMetaData(pkmd);
}
else if (generatePK != null && generatePK.equalsIgnoreCase("true"))
{
joinmd.setPrimaryKeyMetaData(new PrimaryKeyMetaData());
}
if (!StringUtils.isWhitespace(fkName))
{
ForeignKeyMetaData joinFkmd = joinmd.getForeignKeyMetaData();
if (joinFkmd == null)
{
joinFkmd = new ForeignKeyMetaData();
joinFkmd.setName(fkName);
joinmd.setForeignKeyMetaData(joinFkmd);
}
else
{
joinFkmd.setName(fkName);
}
}
else if (generateFK != null && generateFK.equalsIgnoreCase("true"))
{
joinmd.setForeignKeyMetaData(new ForeignKeyMetaData());
}
if (!StringUtils.isWhitespace(indexName))
{
IndexMetaData joinIdxmd = joinmd.getIndexMetaData();
if (joinIdxmd == null)
{
joinIdxmd = new IndexMetaData();
joinmd.setIndexMetaData(joinIdxmd);
}
joinIdxmd.setName(indexName);
}
if (!StringUtils.isWhitespace(uniqueName))
{
UniqueMetaData joinUnimd = joinmd.getUniqueMetaData();
if (joinUnimd == null)
{
joinUnimd = new UniqueMetaData();
joinmd.setUniqueMetaData(joinUnimd);
}
joinUnimd.setName(uniqueName);
}
if (joinColumns != null && joinColumns.length > 0)
{
for (int j=0;j<joinColumns.length;j++)
{
joinmd.addColumn(JDOAnnotationUtils.getColumnMetaDataForColumnAnnotation(joinColumns[j]));
}
}
JDOAnnotationUtils.addExtensionsToMetaData(joinmd, (Extension[])annotationValues.get("extensions"));
}
else if (annName.equals(JDOAnnotationUtils.ELEMENT))
{
// Element of a Collection/Array
elementTypes = (Class[])annotationValues.get("types");
embeddedElement = (String)annotationValues.get("embedded");
serializedElement = (String)annotationValues.get("serialized");
dependentElement = (String)annotationValues.get("dependent");
String elementColumn = (String)annotationValues.get("column");
String elementDeleteAction = JDOAnnotationUtils.getForeignKeyActionString(
(ForeignKeyAction)annotationValues.get("deleteAction"));
String elementUpdateAction = JDOAnnotationUtils.getForeignKeyActionString(
(ForeignKeyAction)annotationValues.get("updateAction"));
String elementMappedBy = (String)annotationValues.get("mappedBy");
Column[] elementColumns = (Column[])annotationValues.get("columns");
String fkName = (String)annotationValues.get("foreignKey");
String generateFK = (String)annotationValues.get("generateForeignKey");
String indexed = (String)annotationValues.get("indexed");
String indexName = (String)annotationValues.get("index");
String unique = (String)annotationValues.get("unique");
String uniqueName = (String)annotationValues.get("uniqueKey");
if (!StringUtils.isWhitespace(uniqueName))
{
unique = "true";
}
if (!StringUtils.isWhitespace(indexName))
{
indexed = "true";
}
elemmd = new ElementMetaData();
elemmd.setColumnName(elementColumn);
elemmd.setDeleteAction(elementDeleteAction);
elemmd.setUpdateAction(elementUpdateAction);
elemmd.setIndexed(IndexedValue.getIndexedValue(indexed));
elemmd.setUnique(unique);
elemmd.setMappedBy(elementMappedBy);
if (!StringUtils.isWhitespace(fkName))
{
ForeignKeyMetaData elemFkmd = elemmd.getForeignKeyMetaData();
if (elemFkmd == null)
{
elemFkmd = new ForeignKeyMetaData();
elemFkmd.setName(fkName);
elemmd.setForeignKeyMetaData(elemFkmd);
}
else
{
elemFkmd.setName(fkName);
}
}
else if (generateFK != null && generateFK.equalsIgnoreCase("true"))
{
elemmd.setForeignKeyMetaData(new ForeignKeyMetaData());
}
if (!StringUtils.isWhitespace(indexName))
{
IndexMetaData elemIdxmd = elemmd.getIndexMetaData();
if (elemIdxmd == null)
{
elemIdxmd = new IndexMetaData();
elemmd.setIndexMetaData(elemIdxmd);
}
elemIdxmd.setName(indexName);
}
if (!StringUtils.isWhitespace(uniqueName))
{
UniqueMetaData elemUnimd = elemmd.getUniqueMetaData();
if (elemUnimd == null)
{
elemUnimd = new UniqueMetaData();
elemmd.setUniqueMetaData(elemUnimd);
}
elemUnimd.setName(uniqueName);
}
if (elementColumns != null && elementColumns.length > 0)
{
for (int j=0;j<elementColumns.length;j++)
{
elemmd.addColumn(JDOAnnotationUtils.getColumnMetaDataForColumnAnnotation(elementColumns[j]));
}
}
JDOAnnotationUtils.addExtensionsToMetaData(elemmd, (Extension[])annotationValues.get("extensions"));
Embedded[] embeddedMappings = (Embedded[])annotationValues.get("embeddedMapping");
if (embeddedMappings != null && embeddedMappings.length > 0)
{
// Embedded element
EmbeddedMetaData embmd = new EmbeddedMetaData();
embmd.setOwnerMember(embeddedMappings[0].ownerMember());
embmd.setNullIndicatorColumn(embeddedMappings[0].nullIndicatorColumn());
embmd.setNullIndicatorValue(embeddedMappings[0].nullIndicatorValue());
elemmd.setEmbeddedMetaData(embmd);
embeddedElementMembers = embeddedMappings[0].members();
// Delay addition of embeddedElementMembers til completion of this loop so we have the element type
}
}
else if (annName.equals(JDOAnnotationUtils.KEY))
{
// Key of a Map
Class[] keyTypes = (Class[])annotationValues.get("types");
if (keyTypes != null && keyTypes.length > 0)
{
// TODO Support more than 1 value
keyType = keyTypes[0];
}
embeddedKey = (String)annotationValues.get("embedded");
serializedKey = (String)annotationValues.get("serialized");
dependentKey = (String)annotationValues.get("dependent");
String keyColumn = (String)annotationValues.get("column");
String keyDeleteAction = JDOAnnotationUtils.getForeignKeyActionString(
(ForeignKeyAction)annotationValues.get("deleteAction"));
String keyUpdateAction = JDOAnnotationUtils.getForeignKeyActionString(
(ForeignKeyAction)annotationValues.get("updateAction"));
String keyMappedBy = (String)annotationValues.get("mappedBy");
Column[] keyColumns = (Column[])annotationValues.get("columns");
String fkName = (String)annotationValues.get("foreignKey");
String generateFK = (String)annotationValues.get("generateForeignKey");
String indexed = (String)annotationValues.get("indexed");
String indexName = (String)annotationValues.get("index");
String unique = (String)annotationValues.get("unique");
String uniqueName = (String)annotationValues.get("uniqueKey");
if (!StringUtils.isWhitespace(uniqueName))
{
unique = "true";
}
if (!StringUtils.isWhitespace(indexName))
{
indexed = "true";
}
keymd = new KeyMetaData();
keymd.setColumnName(keyColumn);
keymd.setDeleteAction(keyDeleteAction);
keymd.setUpdateAction(keyUpdateAction);
keymd.setIndexed(IndexedValue.getIndexedValue(indexed));
keymd.setUnique(unique);
keymd.setMappedBy(keyMappedBy);
if (!StringUtils.isWhitespace(fkName))
{
ForeignKeyMetaData keyFkmd = keymd.getForeignKeyMetaData();
if (keyFkmd == null)
{
keyFkmd = new ForeignKeyMetaData();
keyFkmd.setName(fkName);
keymd.setForeignKeyMetaData(keyFkmd);
}
else
{
keyFkmd.setName(fkName);
}
}
else if (generateFK != null && generateFK.equalsIgnoreCase("true"))
{
keymd.setForeignKeyMetaData(new ForeignKeyMetaData());
}
if (!StringUtils.isWhitespace(indexName))
{
IndexMetaData keyIdxmd = keymd.getIndexMetaData();
if (keyIdxmd == null)
{
keyIdxmd = new IndexMetaData();
keymd.setIndexMetaData(keyIdxmd);
}
keyIdxmd.setName(indexName);
}
if (!StringUtils.isWhitespace(uniqueName))
{
UniqueMetaData keyUnimd = keymd.getUniqueMetaData();
if (keyUnimd == null)
{
keyUnimd = new UniqueMetaData();
keymd.setUniqueMetaData(keyUnimd);
}
keyUnimd.setName(uniqueName);
}
if (keyColumns != null && keyColumns.length > 0)
{
for (int j=0;j<keyColumns.length;j++)
{
keymd.addColumn(JDOAnnotationUtils.getColumnMetaDataForColumnAnnotation(keyColumns[j]));
}
}
JDOAnnotationUtils.addExtensionsToMetaData(keymd, (Extension[])annotationValues.get("extensions"));
Embedded[] embeddedMappings = (Embedded[])annotationValues.get("embeddedMapping");
if (embeddedMappings != null && embeddedMappings.length > 0)
{
// Embedded key
EmbeddedMetaData embmd = new EmbeddedMetaData();
embmd.setOwnerMember(embeddedMappings[0].ownerMember());
embmd.setNullIndicatorColumn(embeddedMappings[0].nullIndicatorColumn());
embmd.setNullIndicatorValue(embeddedMappings[0].nullIndicatorValue());
keymd.setEmbeddedMetaData(embmd);
embeddedKeyMembers = embeddedMappings[0].members();
// Delay addition of embeddedKeyMembers til completion of this loop so we have the key type
}
}
else if (annName.equals(JDOAnnotationUtils.VALUE))
{
// Value of a Map
Class[] valueTypes = (Class[])annotationValues.get("types");
if (valueTypes != null && valueTypes.length > 0)
{
// TODO Support more than 1 value
valueType = valueTypes[0];
}
embeddedValue = (String)annotationValues.get("embedded");
serializedValue = (String)annotationValues.get("serialized");
dependentValue = (String)annotationValues.get("dependent");
String valueColumn = (String)annotationValues.get("column");
String valueDeleteAction = JDOAnnotationUtils.getForeignKeyActionString(
(ForeignKeyAction)annotationValues.get("deleteAction"));
String valueUpdateAction = JDOAnnotationUtils.getForeignKeyActionString(
(ForeignKeyAction)annotationValues.get("updateAction"));
String valueMappedBy = (String)annotationValues.get("mappedBy");
Column[] valueColumns = (Column[])annotationValues.get("columns");
String fkName = (String)annotationValues.get("foreignKey");
String generateFK = (String)annotationValues.get("generateForeignKey");
String indexed = (String)annotationValues.get("indexed");
String indexName = (String)annotationValues.get("index");
String unique = (String)annotationValues.get("unique");
String uniqueName = (String)annotationValues.get("uniqueKey");
if (!StringUtils.isWhitespace(uniqueName))
{
unique = "true";
}
if (!StringUtils.isWhitespace(indexName))
{
indexed = "true";
}
valuemd = new ValueMetaData();
valuemd.setColumnName(valueColumn);
valuemd.setDeleteAction(valueDeleteAction);
valuemd.setUpdateAction(valueUpdateAction);
valuemd.setIndexed(IndexedValue.getIndexedValue(indexed));
valuemd.setUnique(unique);
valuemd.setMappedBy(valueMappedBy);
if (!StringUtils.isWhitespace(fkName))
{
ForeignKeyMetaData valueFkmd = valuemd.getForeignKeyMetaData();
if (valueFkmd == null)
{
valueFkmd = new ForeignKeyMetaData();
valueFkmd.setName(fkName);
valuemd.setForeignKeyMetaData(valueFkmd);
}
else
{
valueFkmd.setName(fkName);
}
}
else if (generateFK != null && generateFK.equalsIgnoreCase("true"))
{
valuemd.setForeignKeyMetaData(new ForeignKeyMetaData());
}
if (!StringUtils.isWhitespace(indexName))
{
IndexMetaData valueIdxmd = valuemd.getIndexMetaData();
if (valueIdxmd == null)
{
valueIdxmd = new IndexMetaData();
valuemd.setIndexMetaData(valueIdxmd);
}
valueIdxmd.setName(indexName);
}
if (!StringUtils.isWhitespace(uniqueName))
{
UniqueMetaData valueUnimd = valuemd.getUniqueMetaData();
if (valueUnimd == null)
{
valueUnimd = new UniqueMetaData();
valuemd.setUniqueMetaData(valueUnimd);
}
valueUnimd.setName(uniqueName);
}
if (valueColumns != null && valueColumns.length > 0)
{
for (int j=0;j<valueColumns.length;j++)
{
valuemd.addColumn(JDOAnnotationUtils.getColumnMetaDataForColumnAnnotation(valueColumns[j]));
}
}
JDOAnnotationUtils.addExtensionsToMetaData(valuemd, (Extension[])annotationValues.get("extensions"));
Embedded[] embeddedMappings = (Embedded[])annotationValues.get("embeddedMapping");
if (embeddedMappings != null && embeddedMappings.length > 0)
{
// Embedded value
EmbeddedMetaData embmd = new EmbeddedMetaData();
embmd.setOwnerMember(embeddedMappings[0].ownerMember());
embmd.setNullIndicatorColumn(embeddedMappings[0].nullIndicatorColumn());
embmd.setNullIndicatorValue(embeddedMappings[0].nullIndicatorValue());
valuemd.setEmbeddedMetaData(embmd);
embeddedValueMembers = embeddedMappings[0].members();
// Delay addition of embeddedValueMembers til completion of this loop so we have the value type
}
}
else if (annName.equals(JDOAnnotationUtils.ORDER))
{
String orderColumn = (String)annotationValues.get("column");
String orderMappedBy = (String)annotationValues.get("mappedBy");
Column[] orderColumns = (Column[])annotationValues.get("columns");
ordermd = new OrderMetaData();
ordermd.setColumnName(orderColumn);
ordermd.setMappedBy(orderMappedBy);
if (orderColumns != null && orderColumns.length > 0)
{
for (int j=0;j<orderColumns.length;j++)
{
ordermd.addColumn(JDOAnnotationUtils.getColumnMetaDataForColumnAnnotation(orderColumns[j]));
}
}
JDOAnnotationUtils.addExtensionsToMetaData(ordermd, (Extension[])annotationValues.get("extensions"));
}
else if (annName.equals(JDOAnnotationUtils.EMBEDDED))
{
embeddedOwnerField = (String)annotationValues.get("ownerMember");
embeddedNullIndicatorColumn = (String)annotationValues.get("nullIndicatorColumn");
embeddedNullIndicatorValue = (String)annotationValues.get("nullIndicatorValue");
embeddedMembers = (Persistent[])annotationValues.get("members");
}
else if (annName.equals(JDOAnnotationUtils.INDEX))
{
// Index for the field
String name = (String)annotationValues.get("name");
String table = (String)annotationValues.get("table");
String unique = (String)annotationValues.get("unique");
String[] members = (String[])annotationValues.get("members");
Column[] columns = (Column[])annotationValues.get("columns");
idxmd = JDOAnnotationUtils.getIndexMetaData(name, table, unique, members, columns);
}
else if (annName.equals(JDOAnnotationUtils.UNIQUE))
{
// Unique for the field
String name = (String)annotationValues.get("name");
String table = (String)annotationValues.get("table");
String deferred = (String)annotationValues.get("deferred");
String[] members = (String[])annotationValues.get("members");
Column[] columns = (Column[])annotationValues.get("columns");
unimd = JDOAnnotationUtils.getUniqueMetaData(name, table, deferred, members, columns);
}
else if (annName.equals(JDOAnnotationUtils.FOREIGNKEY))
{
// ForeignKey for field
String name = (String)annotationValues.get("name");
String table = (String)annotationValues.get("table");
String unique = (String)annotationValues.get("unique");
String deferred = (String)annotationValues.get("deferred");
String deleteAction = JDOAnnotationUtils.getForeignKeyActionString(
(ForeignKeyAction)annotationValues.get("deleteAction"));
String updateAction = JDOAnnotationUtils.getForeignKeyActionString(
(ForeignKeyAction)annotationValues.get("updateAction"));
String[] members = (String[])annotationValues.get("members");
Column[] columns = (Column[])annotationValues.get("columns");
fkmd = JDOAnnotationUtils.getFKMetaData(name, table, unique, deferred, deleteAction, updateAction,
members, columns);
}
else if (annName.equals(JDOAnnotationUtils.CACHEABLE))
{
String cache = (String)annotationValues.get("value");
if (cache != null)
{
cacheable = cache;
}
}
else if (annName.equals(JDOAnnotationUtils.EXTENSIONS))
{
Extension[] values = (Extension[])annotationValues.get("value");
if (values != null && values.length > 0)
{
extensions = new HashSet<ExtensionMetaData>(values.length);
for (int j=0;j<values.length;j++)
{
ExtensionMetaData extmd = new ExtensionMetaData(values[j].vendorName(),
values[j].key().toString(), values[j].value().toString());
extensions.add(extmd);
}
}
}
else if (annName.equals(JDOAnnotationUtils.EXTENSION))
{
ExtensionMetaData extmd = new ExtensionMetaData((String)annotationValues.get("vendorName"),
(String)annotationValues.get("key"), (String)annotationValues.get("value"));
extensions = new HashSet<ExtensionMetaData>(1);
extensions.add(extmd);
}
else
{
NucleusLogger.METADATA.error(LOCALISER.msg("044203",
member.getName(), annotations[i].getName()));
}
}
if (mmd == null &&
(transactionalField || nonPersistentField || primaryKey || colmds != null || serialised ||
embeddedOwnerField != null || embeddedNullIndicatorColumn != null || embeddedNullIndicatorValue != null ||
embeddedMembers != null ||
elemmd != null || keymd != null || valuemd != null || ordermd != null ||
idxmd != null || unimd != null || fkmd != null || joinmd != null ||
extensions != null))
{
// @Persistent not supplied but other relevant annotations defined, so add default metadata element
if (member.isProperty())
{
mmd = new PropertyMetaData(cmd, member.getName());
}
else
{
mmd = new FieldMetaData(cmd, member.getName());
}
if (primaryKey)
{
mmd.setPersistenceModifier(FieldPersistenceModifier.PERSISTENT.toString());
mmd.setPrimaryKey("" + primaryKey);
}
if (serialised)
{
mmd.setPersistenceModifier(FieldPersistenceModifier.PERSISTENT.toString());
}
}
if (mmd != null)
{
cmd.addMember(mmd);
if (primaryKey)
{
mmd.setPrimaryKey(true);
}
if (serialised)
{
mmd.setSerialised(true);
}
if (nonPersistentField)
{
mmd.setNotPersistent();
}
if (transactionalField)
{
mmd.setTransactional();
}
// Add any embedded info
if (embeddedOwnerField != null || embeddedNullIndicatorColumn != null ||
embeddedNullIndicatorValue != null || embeddedMembers != null)
{
EmbeddedMetaData embmd = new EmbeddedMetaData();
embmd.setOwnerMember(embeddedOwnerField);
embmd.setNullIndicatorColumn(embeddedNullIndicatorColumn);
embmd.setNullIndicatorValue(embeddedNullIndicatorValue);
mmd.setEmbeddedMetaData(embmd);
if (embeddedMembers != null && embeddedMembers.length > 0)
{
for (int j=0;j<embeddedMembers.length;j++)
{
// Add the metadata for the embedded field/property to the embedded metadata
String memberName = embeddedMembers[j].name();
if (memberName.indexOf('.') > 0)
{
memberName = memberName.substring(memberName.lastIndexOf('.')+1);
}
AbstractMemberMetaData embfmd = getFieldMetaDataForPersistent(embmd, embeddedMembers[j],
isMemberOfClassAField(member.getType(), memberName));
embmd.addMember(embfmd);
}
}
}
// If the field is a container then add its container element
ContainerMetaData contmd = null;
if (Collection.class.isAssignableFrom(member.getType()))
{
Class collectionElementType = null;
StringBuilder elementTypeStr = new StringBuilder();
if (elementTypes != null && elementTypes.length > 0 && elementTypes[0] != void.class)
{
// User-specified element type(s)
for (int j=0;j<elementTypes.length;j++)
{
if (elementTypeStr.length() > 0)
{
elementTypeStr.append(',');
}
elementTypeStr.append(elementTypes[j].getName());
}
collectionElementType = elementTypes[0]; // Use the first only
}
else
{
// Try to derive element type from generics info
collectionElementType =
ClassUtils.getCollectionElementType(member.getType(), member.getGenericType());
}
contmd = new CollectionMetaData();
CollectionMetaData collmd = (CollectionMetaData)contmd;
collmd.setElementType(elementTypeStr.toString());
collmd.setEmbeddedElement(embeddedElement);
collmd.setSerializedElement(serializedElement);
collmd.setDependentElement(dependentElement);
// Add any embedded element mappings
if (embeddedElementMembers != null)
{
EmbeddedMetaData embmd = elemmd.getEmbeddedMetaData();
for (int j=0;j<embeddedElementMembers.length;j++)
{
// Add the metadata for the embedded element to the embedded metadata
String memberName = embeddedElementMembers[j].name();
if (memberName.indexOf('.') > 0)
{
memberName = memberName.substring(memberName.lastIndexOf('.')+1);
}
AbstractMemberMetaData embfmd = getFieldMetaDataForPersistent(embmd,
embeddedElementMembers[j],
isMemberOfClassAField(collectionElementType, memberName));
embmd.addMember(embfmd);
}
}
}
else if (member.getType().isArray())
{
StringBuilder elementTypeStr = new StringBuilder();
if (elementTypes != null && elementTypes.length > 0 && elementTypes[0] != void.class)
{
// User-specified element type(s)
for (int j=0;j<elementTypes.length;j++)
{
if (elementTypeStr.length() > 0)
{
elementTypeStr.append(',');
}
elementTypeStr.append(elementTypes[j].getName());
}
}
else
{
// Derive from component type
elementTypeStr.append(member.getType().getComponentType().getName());
}
contmd = new ArrayMetaData();
ArrayMetaData arrmd = (ArrayMetaData)contmd;
arrmd.setElementType(elementTypeStr.toString());
arrmd.setEmbeddedElement(embeddedElement);
arrmd.setSerializedElement(serializedElement);
arrmd.setDependentElement(dependentElement);
}
else if (Map.class.isAssignableFrom(member.getType()))
{
Class mapKeyType = null;
if (keyType != null && keyType != void.class)
{
// User-specified key type
mapKeyType = keyType;
}
else
{
// Try to derive key type from generics info
mapKeyType = ClassUtils.getMapKeyType(member.getType(), member.getGenericType());
}
Class mapValueType = null;
if (valueType != null && valueType != void.class)
{
// User-specified value type
mapValueType = valueType;
}
else
{
// Try to derive value type from generics info
mapValueType = ClassUtils.getMapValueType(member.getType(), member.getGenericType());
}
contmd = new MapMetaData();
MapMetaData mapmd = (MapMetaData)contmd;
mapmd.setKeyType((mapKeyType != null ? mapKeyType.getName() : null));
mapmd.setEmbeddedKey(embeddedKey);
mapmd.setSerializedKey(serializedKey);
mapmd.setDependentKey(dependentKey);
mapmd.setValueType((mapValueType != null ? mapValueType.getName() : null));
mapmd.setEmbeddedValue(embeddedValue);
mapmd.setSerializedValue(serializedValue);
mapmd.setDependentValue(dependentValue);
if (embeddedKeyMembers != null)
{
// Add any embedded key mappings
EmbeddedMetaData embmd = keymd.getEmbeddedMetaData();
for (int j=0;j<embeddedKeyMembers.length;j++)
{
// Add the metadata for the embedded key to the embedded metadata
String memberName = embeddedKeyMembers[j].name();
if (memberName.indexOf('.') > 0)
{
memberName = memberName.substring(memberName.lastIndexOf('.')+1);
}
AbstractMemberMetaData embfmd = getFieldMetaDataForPersistent(embmd, embeddedKeyMembers[j],
isMemberOfClassAField(mapKeyType, memberName));
embmd.addMember(embfmd);
}
}
if (embeddedValueMembers != null)
{
// Add any embedded value mappings
EmbeddedMetaData embmd = valuemd.getEmbeddedMetaData();
for (int j=0;j<embeddedValueMembers.length;j++)
{
// Add the metadata for the embedded value to the embedded metadata
String memberName = embeddedValueMembers[j].name();
if (memberName.indexOf('.') > 0)
{
memberName = memberName.substring(memberName.lastIndexOf('.')+1);
}
AbstractMemberMetaData embfmd = getFieldMetaDataForPersistent(embmd, embeddedValueMembers[j],
isMemberOfClassAField(mapValueType, memberName));
embmd.addMember(embfmd);
}
}
}
if (contmd != null)
{
mmd.setContainer(contmd);
if (elemmd != null)
{
elemmd.setParent(mmd);
mmd.setElementMetaData(elemmd);
if (elemmd.getMappedBy() != null && mmd.getMappedBy() == null)
{
// With collection/array this is the same as mapped-by on the field
mmd.setMappedBy(elemmd.getMappedBy());
}
}
if (keymd != null)
{
keymd.setParent(mmd);
mmd.setKeyMetaData(keymd);
}
if (valuemd != null)
{
valuemd.setParent(mmd);
mmd.setValueMetaData(valuemd);
}
if (ordermd != null)
{
ordermd.setParent(mmd);
mmd.setOrderMetaData(ordermd);
}
}
if (joinmd != null)
{
mmd.setJoinMetaData(joinmd);
}
if (colmds != null)
{
for (int i=0;i<colmds.length;i++)
{
mmd.addColumn(colmds[i]);
}
}
if (idxmd != null)
{
mmd.setIndexMetaData(idxmd);
}
if (unimd != null)
{
mmd.setUniqueMetaData(unimd);
}
if (fkmd != null)
{
mmd.setForeignKeyMetaData(fkmd);
}
if (cacheable != null && cacheable.equalsIgnoreCase("false"))
{
mmd.setCacheable(false);
}
if (extensions != null)
{
Iterator<ExtensionMetaData> iter = extensions.iterator();
while (iter.hasNext())
{
ExtensionMetaData extmd = iter.next();
mmd.addExtension(extmd.getVendorName(), extmd.getKey(), extmd.getValue());
}
}
}
}
return mmd;
}
/**
* Method to take the passed in outline ClassMetaData and process the annotations for
* method adding any necessary MetaData to the ClassMetaData.
* @param cmd The ClassMetaData/InterfaceMetaData (to be updated)
* @param method The method
*/
protected void processMethodAnnotations(AbstractClassMetaData cmd, Method method)
{
//do nothing
}
/**
* Convenience method to create MetaData for a @Persistent annotation
* representing a field or property.
* @param parent Parent MetaData
* @param member The @Persistent annotation
* @param isField Whether this is a field (otherwise is a property)
* @return The metadata for the field/property
*/
private AbstractMemberMetaData getFieldMetaDataForPersistent(MetaData parent, Persistent member, boolean isField)
{
String modifier = JDOAnnotationUtils.getFieldPersistenceModifierString(member.persistenceModifier());
String nullValue = JDOAnnotationUtils.getNullValueString(member.nullValue());
String valueStrategy = JDOAnnotationUtils.getIdentityStrategyString(member.valueStrategy());
String fieldTypeName = null;
Class[] fieldTypes = member.types();
if (fieldTypes != null && fieldTypes.length > 0)
{
StringBuilder typeStr = new StringBuilder();
for (int j=0;j<fieldTypes.length;j++)
{
if (typeStr.length() > 0)
{
typeStr.append(',');
}
if (fieldTypes[j] != null && fieldTypes[j] != void.class)
{
typeStr.append(fieldTypes[j].getName());
}
}
fieldTypeName = typeStr.toString();
}
AbstractMemberMetaData fmd = null;
if (isField)
{
fmd = new FieldMetaData(parent, member.name());
}
else
{
fmd = new PropertyMetaData(parent, member.name());
}
fmd.setPersistenceModifier(modifier);
fmd.setDefaultFetchGroup(member.defaultFetchGroup());
fmd.setPrimaryKey("" + member.primaryKey());
fmd.setEmbedded(member.embedded());
fmd.setSerialised(member.serialized());
fmd.setDependent(member.dependent());
fmd.setNullValue(org.datanucleus.metadata.NullValue.getNullValue(nullValue));
fmd.setMappedBy(member.mappedBy());
fmd.setColumn(member.column());
fmd.setTable(member.table());
fmd.setLoadFetchGroup(member.loadFetchGroup());
fmd.setValueStrategy(valueStrategy);
fmd.setSequence(member.sequence());
fmd.setFieldTypes(fieldTypeName);
// Add any columns defined on the @Persistent
Column[] columns = member.columns();
if (columns != null && columns.length > 0)
{
for (int j=0;j<columns.length;j++)
{
fmd.addColumn(JDOAnnotationUtils.getColumnMetaDataForColumnAnnotation(columns[j]));
}
}
return fmd;
}
/**
* Convenience method that tries to find if a specified member name (field or property) is for a field.
* @param cls The class
* @param memberName Name of the member
* @return Whether it is a field (else it's a property).
*/
private boolean isMemberOfClassAField(Class cls, String memberName)
{
try
{
cls.getDeclaredField(memberName);
}
catch (NoSuchFieldException nsfe)
{
return false;
}
// TODO It is possible that a memberName is a field AND a property. What do we do then ?
return true;
}
}