You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openjpa.apache.org by mp...@apache.org on 2007/07/01 21:37:05 UTC
svn commit: r552358 [1/2] - in /openjpa/trunk:
openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/ant/
openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/
openjpa-jdbc/src/main/resources/org/apache/openjpa/jdbc/meta/
openjpa-kernel/src/main/java/o...
Author: mprudhom
Date: Sun Jul 1 12:37:04 2007
New Revision: 552358
URL: http://svn.apache.org/viewvc?view=rev&rev=552358
Log:
OPENJPA-239 Patch to support the generation of annotation mappings using the reverse mapping tool
Added:
openjpa/trunk/openjpa-persistence-jdbc/src/main/java/org/apache/openjpa/persistence/jdbc/AnnotationPersistenceMappingSerializer.java (with props)
openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/AnnotationBuilder.java (with props)
openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/AnnotationPersistenceMetaDataSerializer.java (with props)
Modified:
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/ant/ReverseMappingToolTask.java
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/ReverseMappingTool.java
openjpa/trunk/openjpa-jdbc/src/main/resources/org/apache/openjpa/jdbc/meta/localizer.properties
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/ee/RegistryManagedRuntime.java (props changed)
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/CodeGenerator.java
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/AbstractCFMetaDataFactory.java
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/MetaDataModes.java
openjpa/trunk/openjpa-lib/src/main/java/org/apache/openjpa/lib/util/CodeFormat.java
openjpa/trunk/openjpa-persistence-jdbc/src/main/java/org/apache/openjpa/persistence/jdbc/PersistenceMappingFactory.java
openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PersistenceMetaDataFactory.java
openjpa/trunk/openjpa-project/src/doc/manual/ref_guide_mapping.xml
Modified: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/ant/ReverseMappingToolTask.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/ant/ReverseMappingToolTask.java?view=diff&rev=552358&r1=552357&r2=552358
==============================================================================
--- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/ant/ReverseMappingToolTask.java (original)
+++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/ant/ReverseMappingToolTask.java Sun Jul 1 12:37:04 2007
@@ -123,6 +123,14 @@
}
/**
+ * Set whether to use generic collections on one-to-many and many-to-many
+ * relations instead of untyped collections.
+ */
+ public void setUseGenericCollections(boolean useGenericCollections) {
+ flags.useGenericCollections = useGenericCollections;
+ }
+
+ /**
* Set the SQL type map overrides.
*/
public void setTypeMap(String typeMap) {
@@ -202,6 +210,22 @@
}
/**
+ * Whether to generate annotations along with generated code. Defaults
+ * to false.
+ */
+ public void setGenerateAnnotations(boolean genAnnotations) {
+ flags.generateAnnotations = genAnnotations;
+ }
+
+ /**
+ * Whether to use field or property-based access on generated code.
+ * Defaults to field-based access.
+ */
+ public void setAccessType(AccessType accessType) {
+ flags.accessType = accessType.getValue();
+ }
+
+ /**
* Set a customizer class to use.
*/
public void setCustomizerClass(String customizerClass) {
@@ -255,6 +279,18 @@
return new String[]{
"package",
"class",
+ "none"
+ };
+ }
+ }
+
+ public static class AccessType
+ extends EnumeratedAttribute {
+
+ public String[] getValues() {
+ return new String[]{
+ "field",
+ "property"
};
}
}
Modified: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/ReverseMappingTool.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/ReverseMappingTool.java?view=diff&rev=552358&r1=552357&r2=552358
==============================================================================
--- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/ReverseMappingTool.java (original)
+++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/ReverseMappingTool.java Sun Jul 1 12:37:04 2007
@@ -136,9 +136,16 @@
*/
public static final int TABLE_SUBCLASS = 5;
+ public static final String LEVEL_NONE = "none";
public static final String LEVEL_PACKAGE = "package";
public static final String LEVEL_CLASS = "class";
+ /**
+ * Access type for generated source, defaults to field-based access.
+ */
+ public static final String ACCESS_TYPE_FIELD = "field";
+ public static final String ACCESS_TYPE_PROPERTY = "property";
+
private static Localizer _loc = Localizer.forPackage
(ReverseMappingTool.class);
@@ -176,6 +183,7 @@
private SchemaGroup _schema = null;
private boolean _nullAsObj = false;
private boolean _blobAsObj = false;
+ private boolean _useGenericColl = false;
private Properties _typeMap = null;
private boolean _useFK = false;
private boolean _useSchema = false;
@@ -186,6 +194,8 @@
private String _idSuffix = "Id";
private boolean _inverse = true;
private boolean _detachable = false;
+ private boolean _genAnnotations = false;
+ private String _accessType = ACCESS_TYPE_FIELD;
private CodeFormat _format = null;
private ReverseCustomizer _custom = null;
private String _discStrat = null;
@@ -196,6 +206,9 @@
// mess up certain customizers (bug 881)
private Set _abandonedFieldNames = null;
+ // generated annotations, key = metadata, val = list of annotations
+ private Map _annos = null;
+
/**
* Constructor. Supply configuration.
*/
@@ -327,6 +340,22 @@
}
/**
+ * Whether to use generic collections on one-to-many and many-to-many
+ * relations instead of untyped collections.
+ */
+ public boolean getUseGenericCollections() {
+ return _useGenericColl;
+ }
+
+ /**
+ * Whether to use generic collections on one-to-many and many-to-many
+ * relations instead of untyped collections.
+ */
+ public void setUseGenericCollections(boolean useGenericCollections) {
+ _useGenericColl = useGenericCollections;
+ }
+
+ /**
* Map of JDBC-name to Java-type-name entries that allows customization
* of reverse mapping columns to field types.
*/
@@ -479,6 +508,39 @@
}
/**
+ * Whether to generate annotations along with generated code. Defaults
+ * to false.
+ */
+ public boolean getGenerateAnnotations() {
+ return _genAnnotations;
+ }
+
+ /**
+ * Whether to generate annotations along with generated code. Defaults
+ * to false.
+ */
+ public void setGenerateAnnotations(boolean genAnnotations) {
+ _genAnnotations = genAnnotations;
+ }
+
+ /**
+ * Whether to use field or property-based access on generated code.
+ * Defaults to field-based access.
+ */
+ public String getAccessType() {
+ return _accessType;
+ }
+
+ /**
+ * Whether to use field or property-based access on generated code.
+ * Defaults to field-based access.
+ */
+ public void setAccessType(String accessType) {
+ this._accessType = ACCESS_TYPE_PROPERTY.equalsIgnoreCase(accessType) ?
+ ACCESS_TYPE_PROPERTY : ACCESS_TYPE_FIELD;
+ }
+
+ /**
* The code formatter for the generated Java code.
*/
public CodeFormat getCodeFormat() {
@@ -784,7 +846,11 @@
_log.info(_loc.get("class-code", mappings[i]));
ApplicationIdTool aid = newApplicationIdTool(mappings[i]);
- gen = new ReverseCodeGenerator(mappings[i], aid);
+ if (getGenerateAnnotations())
+ gen = new AnnotatedCodeGenerator(mappings[i], aid);
+ else
+ gen = new ReverseCodeGenerator(mappings[i], aid);
+
gen.generateCode();
if (output == null) {
@@ -852,6 +918,31 @@
return files;
}
+ public void buildAnnotations() {
+ Map output = new HashMap();
+ // pretend mappings are all resolved
+ ClassMapping[] mappings = getMappings();
+ for (int i = 0; i < mappings.length; i++)
+ mappings[i].setResolve(MODE_META | MODE_MAPPING, true);
+
+ // store in user's configured IO
+ MetaDataFactory mdf = _conf.newMetaDataFactoryInstance();
+ mdf.setRepository(getRepository());
+ mdf.setStoreDirectory(_dir);
+ mdf.store(mappings, new QueryMetaData[0], new SequenceMetaData[0],
+ MODE_META | MODE_MAPPING | MODE_ANN_MAPPING, output);
+ _annos = output;
+ }
+
+ /**
+ * Returns a list of stringified annotations for specified meta.
+ */
+ protected List getAnnotationsForMeta(Object meta) {
+ if (null == _annos)
+ return null;
+ return (List) _annos.get(meta);
+ }
+
/**
* Generate and write the application identity code.
*/
@@ -1619,6 +1710,7 @@
tool.setUseForeignKeyName(getUseForeignKeyName());
tool.setNullableAsObject(getNullableAsObject());
tool.setBlobAsObject(getBlobAsObject());
+ tool.setUseGenericCollections(getUseGenericCollections());
tool.setPrimaryKeyOnJoin(getPrimaryKeyOnJoin());
tool.setUseDataStoreIdentity(getUseDataStoreIdentity());
tool.setUseBuiltinIdentityClass(getUseBuiltinIdentityClass());
@@ -1626,6 +1718,7 @@
tool.setIdentityClassSuffix(getIdentityClassSuffix());
tool.setInverseRelations(getInverseRelations());
tool.setDetachable(getDetachable());
+ tool.setGenerateAnnotations(getGenerateAnnotations());
tool.setCustomizer(getCustomizer());
tool.setCodeFormat(getCodeFormat());
return tool;
@@ -1667,6 +1760,9 @@
* type instead.</li>
* <li><i>-blobAsObject/-bo <true/t | false/f></i>: Set to true
* to make all binary columns map to Object rather than byte[].</li>
+ * <li><i>-useGenericCollections/-gc <true/t | false/f></i>: Set to
+ * true to use generic collections on OneToMany and ManyToMany relations
+ * (requires JDK 1.5 or higher).</li>
* <li><i>-typeMap/-typ <types></i>: Default mapping of SQL type
* names to Java classes.</li>
* <li><i>-primaryKeyOnJoin/-pkj <true/t | false/f></i>: Set to true
@@ -1690,9 +1786,13 @@
* discriminator strategy to place on base classes.</li>
* <li><i>-versionStrategy/-vs <strategy></i>: The default
* version strategy to place on base classes.</li>
- * <li><i>-metadata/-md <class | package></i>: Specify the level the
- * metadata should be generated at. Defaults to generating a
+ * <li><i>-metadata/-md <class | package | none></i>: Specify the
+ * level the metadata should be generated at. Defaults to generating a
* single package-level metadata file.</li>
+ * <li><i>-annotations/-ann <true/t | false/f></i>: Set to true to
+ * generate JPA annotations in generated code.</li>
+ * <li><i>-accessType/-access <field | property></i>: Change access
+ * type for generated annotations. Defaults to field access.</li>
* <li><i>-customizerClass/-cc <class name></i>: The full class
* name of a {@link ReverseCustomizer} implementation to use to
* customize the reverse mapping process. Optional.</li>
@@ -1749,6 +1849,8 @@
("nullableAsObject", "no", flags.nullableAsObject);
flags.blobAsObject = opts.removeBooleanProperty
("blobAsObject", "bo", flags.blobAsObject);
+ flags.useGenericCollections = opts.removeBooleanProperty
+ ("useGenericCollections", "gc", flags.useGenericCollections);
flags.primaryKeyOnJoin = opts.removeBooleanProperty
("primaryKeyOnJoin", "pkj", flags.primaryKeyOnJoin);
flags.useDataStoreIdentity = opts.removeBooleanProperty
@@ -1768,7 +1870,11 @@
flags.versionStrategy = opts.removeProperty
("versionStrategy", "vs", flags.versionStrategy);
flags.metaDataLevel = opts.removeProperty
- ("metadata", "md", flags.metaDataLevel);
+ ("metadata", "md", flags.metaDataLevel);
+ flags.generateAnnotations = opts.removeBooleanProperty
+ ("annotations", "ann", flags.generateAnnotations);
+ flags.accessType = opts.removeProperty
+ ("accessType", "access", flags.accessType);
String typeMap = opts.removeProperty("typeMap", "typ", null);
if (typeMap != null)
@@ -1869,6 +1975,7 @@
tool.setUseForeignKeyName(flags.useForeignKeyName);
tool.setNullableAsObject(flags.nullableAsObject);
tool.setBlobAsObject(flags.blobAsObject);
+ tool.setUseGenericCollections(flags.useGenericCollections);
tool.setTypeMap(flags.typeMap);
tool.setPrimaryKeyOnJoin(flags.primaryKeyOnJoin);
tool.setUseDataStoreIdentity(flags.useDataStoreIdentity);
@@ -1877,16 +1984,24 @@
tool.setIdentityClassSuffix(flags.identityClassSuffix);
tool.setInverseRelations(flags.inverseRelations);
tool.setDetachable(flags.detachable);
+ tool.setGenerateAnnotations(flags.generateAnnotations);
+ tool.setAccessType(flags.accessType);
tool.setCustomizer(flags.customizer);
tool.setCodeFormat(flags.format);
// run
log.info(_loc.get("revtool-map"));
tool.run();
+ if (flags.generateAnnotations) {
+ log.info(_loc.get("revtool-gen-annos"));
+ tool.buildAnnotations();
+ }
log.info(_loc.get("revtool-write-code"));
tool.recordCode();
- log.info(_loc.get("revtool-write-metadata"));
- tool.recordMetaData(LEVEL_CLASS.equals(flags.metaDataLevel));
+ if (!LEVEL_NONE.equals(flags.metaDataLevel)) {
+ log.info(_loc.get("revtool-write-metadata"));
+ tool.recordMetaData(LEVEL_CLASS.equals(flags.metaDataLevel));
+ }
}
/**
@@ -1900,6 +2015,7 @@
public boolean useForeignKeyName = false;
public boolean nullableAsObject = false;
public boolean blobAsObject = false;
+ public boolean useGenericCollections = false;
public Properties typeMap = null;
public boolean primaryKeyOnJoin = false;
public boolean useDataStoreIdentity = false;
@@ -1908,6 +2024,8 @@
public String identityClassSuffix = "Id";
public boolean inverseRelations = true;
public boolean detachable = false;
+ public boolean generateAnnotations = false;
+ public String accessType = ACCESS_TYPE_FIELD;
public String metaDataLevel = LEVEL_PACKAGE;
public String discriminatorStrategy = null;
public String versionStrategy = null;
@@ -1983,8 +2101,8 @@
private class ReverseCodeGenerator
extends CodeGenerator {
- private final ClassMapping _mapping;
- private final ApplicationIdTool _appid;
+ protected final ClassMapping _mapping;
+ protected final ApplicationIdTool _appid;
public ReverseCodeGenerator(ClassMapping mapping,
ApplicationIdTool aid) {
@@ -2046,5 +2164,37 @@
return null;
return _custom.getFieldCode((FieldMapping) field);
}
+
+ protected boolean useGenericCollections() {
+ return _useGenericColl;
+ }
+ }
+
+ private class AnnotatedCodeGenerator
+ extends ReverseCodeGenerator {
+
+ public AnnotatedCodeGenerator (ClassMapping mapping,
+ ApplicationIdTool aid) {
+ super (mapping, aid);
+ }
+
+ public Set getImportPackages() {
+ Set pkgs = super.getImportPackages();
+ pkgs.add("javax.persistence");
+ return pkgs;
+ }
+
+ protected List getClassAnnotations() {
+ return getAnnotationsForMeta(_mapping);
+ }
+
+ protected List getFieldAnnotations(FieldMetaData field) {
+ return getAnnotationsForMeta(field);
+ }
+
+ protected boolean usePropertyBasedAccess () {
+ return ACCESS_TYPE_PROPERTY.equals(_accessType);
+ }
+
}
}
Modified: openjpa/trunk/openjpa-jdbc/src/main/resources/org/apache/openjpa/jdbc/meta/localizer.properties
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/resources/org/apache/openjpa/jdbc/meta/localizer.properties?view=diff&rev=552358&r1=552357&r2=552358
==============================================================================
--- openjpa/trunk/openjpa-jdbc/src/main/resources/org/apache/openjpa/jdbc/meta/localizer.properties (original)
+++ openjpa/trunk/openjpa-jdbc/src/main/resources/org/apache/openjpa/jdbc/meta/localizer.properties Sun Jul 1 12:37:04 2007
@@ -359,6 +359,7 @@
revtool-write-code: Writing generated class source code.
revtool-write-appid: Writing generated application identity classes.
revtool-write-metadata: Writing generated metadata.
+revtool-gen-annos: Generating annotations.
revtool-usage: Usage: java org.apache.openjpa.jdbc.meta.ReverseMappingTool\n\
\t[-properties/-p <properties file or resource>]\n\
\t[-<property name> <property value>]*\n\
@@ -369,6 +370,7 @@
\t[-useForeignKeyName/-fkn <true/t | false/f>]\n\
\t[-nullableAsObject/-no <true/t | false/f>]\n\
\t[-blobAsObject/-bo <true/t | false/f>]\n\
+ \t[-useGenericCollections/-gc <true/t | false/f>]\n\
\t[-typeMap/-type <types>]\n\
\t[-primaryKeyOnJoin/-pkj <true/t | false/f>]\n\
\t[-useDatastoreIdentity/-ds <true/t | false/f>]\n\
@@ -379,7 +381,9 @@
\t[-detachable/-det <true/t | false/f>]\n\
\t[-discriminatorStrategy/-ds <strategy>]\n\
\t[-versionStrategy/-vs <strategy>]\n\
- \t[-metadata/-md <package | class>]\n\
+ \t[-metadata/-md <package | class | none>]\n\
+ \t[-annotations/-ann <true/t | false/f>]\n\
+ \t[-accessType/-access <field | property>]\n\
\t[-customizerClass/-cc <full class name>]\n\
\t[-customizerProperties/-cp <properties file or resource>]\n\
\t[-customizer/-c.<property name> <property value>]*\n\
Propchange: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/ee/RegistryManagedRuntime.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/CodeGenerator.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/CodeGenerator.java?view=diff&rev=552358&r1=552357&r2=552358
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/CodeGenerator.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/CodeGenerator.java Sun Jul 1 12:37:04 2007
@@ -24,8 +24,10 @@
import java.util.Iterator;
import java.util.Set;
import java.util.TreeSet;
+import java.util.List;
import org.apache.commons.lang.StringUtils;
+import org.apache.commons.lang.WordUtils;
import org.apache.openjpa.conf.OpenJPAConfiguration;
import org.apache.openjpa.lib.util.CodeFormat;
import org.apache.openjpa.lib.util.Files;
@@ -307,27 +309,47 @@
propertyName = propertyName.substring(1);
String fieldType = Strings.getClassName(fmd.getDeclaredType());
+ String keyType = null;
+ String elementType = null;
+ String paramType = "";
+ if (useGenericCollections()) {
+ if (fmd.getDeclaredTypeCode() == JavaTypes.COLLECTION) {
+ Class elmCls = fmd.getElement().getDeclaredType();
+ elementType = Strings.getClassName(elmCls);
+ paramType = decs.getParametrizedType(
+ new String[] {elementType});
+ } else if (fmd.getDeclaredTypeCode() == JavaTypes.MAP) {
+ Class keyCls = fmd.getKey().getDeclaredType();
+ Class elmCls = fmd.getElement().getDeclaredType();
+ keyType = Strings.getClassName(keyCls);
+ elementType = Strings.getClassName(elmCls);
+ paramType = decs.getParametrizedType(
+ new String[] {keyType, elementType});
+ }
+ }
+
String fieldValue = getInitialValue(fmd);
if (fieldValue == null) {
if ("Set".equals(fieldType))
- fieldValue = "new HashSet" + decs.getParens();
+ fieldValue = "new HashSet" + paramType + decs.getParens();
else if ("TreeSet".equals(fieldType))
- fieldValue = "new TreeSet" + decs.getParens();
+ fieldValue = "new TreeSet" + paramType + decs.getParens();
else if ("Collection".equals(fieldType))
- fieldValue = "new ArrayList" + decs.getParens();
+ fieldValue = "new ArrayList" + paramType + decs.getParens();
else if ("Map".equals(fieldType))
- fieldValue = "new HashMap" + decs.getParens();
+ fieldValue = "new HashMap" + paramType + decs.getParens();
else if ("TreeMap".equals(fieldType))
- fieldValue = "new TreeMap" + decs.getParens();
- else if (fmd.getDeclaredTypeCode() == JavaTypes.COLLECTION
- || fmd.getDeclaredTypeCode() == JavaTypes.MAP)
- fieldValue = "new " + fieldType + decs.getParens();
+ fieldValue = "new TreeMap" + paramType + decs.getParens();
+ else if (fmd.getDeclaredTypeCode() == JavaTypes.COLLECTION ||
+ fmd.getDeclaredTypeCode() == JavaTypes.MAP)
+ fieldValue = "new " + fieldType + paramType + decs.getParens();
else
fieldValue = "";
}
if (fieldValue.length() > 0)
fieldValue = " = " + fieldValue;
+ boolean fieldAccess = !usePropertyBasedAccess();
String custom = getDeclaration(fmd);
if (decs.length() > 0)
decs.endl();
@@ -339,12 +361,18 @@
templ.setParameter("capFieldName", capFieldName);
templ.setParameter("propertyName", propertyName);
templ.setParameter("fieldType", fieldType);
+ templ.setParameter("keyType", keyType);
+ templ.setParameter("elementType", elementType);
templ.setParameter("fieldValue", fieldValue);
decs.append(templ.toString());
} else {
+ if (fieldAccess)
+ writeAnnotations(decs, getFieldAnnotations(fmd), 1);
decs.tab().append("private ").append(fieldType).
- append(" ").append(fieldName).append(fieldValue).
- append(";");
+ append(paramType).append(" ").append(fieldName).
+ append(fieldValue).append(";");
+ if (fieldAccess)
+ decs.endl();
}
custom = getFieldCode(fmd);
@@ -357,11 +385,16 @@
templ.setParameter("capFieldName", capFieldName);
templ.setParameter("propertyName", propertyName);
templ.setParameter("fieldType", fieldType);
+ templ.setParameter("keyType", keyType);
+ templ.setParameter("elementType", elementType);
templ.setParameter("fieldValue", fieldValue);
code.append(templ.toString());
} else {
// getter
- code.tab().append("public ").append(fieldType).append(" ");
+ if (!fieldAccess)
+ writeAnnotations(code, getFieldAnnotations(fmd), 1);
+ code.tab().append("public ").append(fieldType).append(paramType).
+ append(" ");
if ("boolean".equalsIgnoreCase(fieldType))
code.append("is");
else
@@ -374,8 +407,8 @@
// setter
code.tab().append("public void set").append(capFieldName);
- code.openParen(true).append(fieldType).append(" ").
- append(propertyName).closeParen();
+ code.openParen(true).append(fieldType).append(paramType).
+ append(" ").append(propertyName).closeParen();
code.openBrace(2).endl();
code.tab(2);
if (propertyName.equals(fieldName))
@@ -403,6 +436,7 @@
append(" * ").append(getClass().getName()).endl().
append(" */").endl();
+ writeAnnotations(code, getClassAnnotations(), 0);
code.append("public class ").append(className);
if (extendsName.length() > 0)
code.extendsDec(1).append(" ").append(extendsName);
@@ -427,6 +461,21 @@
}
/**
+ * Appends the given list of annotations to code buffer.
+ */
+ private void writeAnnotations (CodeFormat code, List ann,
+ int tabLevel) {
+ if (ann == null || ann.size() == 0)
+ return;
+ for (Iterator i = ann.iterator(); i.hasNext();) {
+ if (tabLevel > 0)
+ code.tab(tabLevel);
+ String s = (String) i.next();
+ code.append(s).endl();
+ }
+ }
+
+ /**
* Append the opening code-level brace to the code; this can be
* overridden to add code to the top of the class.
*/
@@ -503,6 +552,9 @@
* <li>${capFieldName}: The capitalized field name.</li>
* <li>${propertyName}: The field name without leading '_', if any.</li>
* <li>${fieldType}: The field's type name.</li>
+ * <li>${keyType}: Key type name for maps, null otherwise.</li>
+ * <li>${elementType}: Element type name for collections, null otherwise.
+ * </li>
* <li>${fieldValue}: The field's initial value, in the form
* " = <value>", or empty string if none.</li>
* </ul> Returns null by default.
@@ -521,6 +573,9 @@
* <li>${capFieldName}: The capitalized field name.</li>
* <li>${propertyName}: The field name without leading '_', if any.</li>
* <li>${fieldType}: The field's type name.</li>
+ * <li>${keyType}: Key type name for maps, null otherwise.</li>
+ * <li>${elementType}: Element type name for collections, null otherwise.
+ * </li>
* <li>${fieldValue}: The field's initial value, in the form
* "= <value>", or empty string if none.</li>
* </ul>
@@ -529,4 +584,37 @@
{
return null;
}
+
+ /**
+ * Whether to use property-based access on generated code.
+ * Defaults to false (field-based).
+ */
+ protected boolean usePropertyBasedAccess () {
+ return false;
+ }
+
+ /**
+ * Return class-level annotations. Returns null by default.
+ */
+ protected List getClassAnnotations() {
+ return null;
+ }
+
+ /**
+ * Return field-level annotations. Returns null by default.
+ */
+ protected List getFieldAnnotations(FieldMetaData field) {
+ return null;
+ }
+
+ /**
+ * Whether to use generic collections on one-to-many and many-to-many
+ * relations instead of untyped collections.
+ *
+ * Override in descendants to change default behavior.
+ */
+ protected boolean useGenericCollections() {
+ return false;
+ }
+
}
Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/AbstractCFMetaDataFactory.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/AbstractCFMetaDataFactory.java?view=diff&rev=552358&r1=552357&r2=552358
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/AbstractCFMetaDataFactory.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/AbstractCFMetaDataFactory.java Sun Jul 1 12:37:04 2007
@@ -192,7 +192,10 @@
Parser parser;
if (mode != MODE_QUERY) {
int sermode = (isMappingOnlyFactory()) ? mode : mode | MODE_META;
- ser = newSerializer();
+ if ((mode & MODE_ANN_MAPPING) != 0)
+ ser = newAnnotationSerializer();
+ else
+ ser = newSerializer();
ser.setMode(sermode);
if (metaFiles != null) {
parser = newParser(false);
@@ -231,7 +234,10 @@
for (int i = 0; !qFiles && i < queries.length; i++)
qFiles = queries[i].getSourceMode() == MODE_QUERY;
if (qFiles) {
- ser = newSerializer();
+ if ((mode & MODE_ANN_MAPPING) != 0)
+ ser = newAnnotationSerializer();
+ else
+ ser = newSerializer();
ser.setMode(MODE_QUERY);
if (queryFiles != null) {
parser = newParser(false);
@@ -542,6 +548,11 @@
* Create a new metadata serializer.
*/
protected abstract Serializer newSerializer();
+
+ /**
+ * Create a new annotation metadata serializer.
+ */
+ protected abstract Serializer newAnnotationSerializer();
/**
* Return the metadata that defines the given query, if any.
Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/MetaDataModes.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/MetaDataModes.java?view=diff&rev=552358&r1=552357&r2=552358
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/MetaDataModes.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/MetaDataModes.java Sun Jul 1 12:37:04 2007
@@ -32,4 +32,5 @@
public static final int MODE_MAPPING = 2;
public static final int MODE_QUERY = 4;
public static final int MODE_MAPPING_INIT = 8;
+ public static final int MODE_ANN_MAPPING = 16;
}
Modified: openjpa/trunk/openjpa-lib/src/main/java/org/apache/openjpa/lib/util/CodeFormat.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-lib/src/main/java/org/apache/openjpa/lib/util/CodeFormat.java?view=diff&rev=552358&r1=552357&r2=552358
==============================================================================
--- openjpa/trunk/openjpa-lib/src/main/java/org/apache/openjpa/lib/util/CodeFormat.java (original)
+++ openjpa/trunk/openjpa-lib/src/main/java/org/apache/openjpa/lib/util/CodeFormat.java Sun Jul 1 12:37:04 2007
@@ -308,6 +308,22 @@
return tabs.toString();
}
+
+ /**
+ * Returns parametrized type string for given type(s).
+ */
+ public String getParametrizedType(String[] typenames) {
+ StringBuffer buf = new StringBuffer ();
+ buf.append("<");
+ for (int i = 0; i < typenames.length; i++) {
+ if (i > 0)
+ buf.append(", ");
+ buf.append(typenames[i]);
+ }
+ buf.append(">");
+ return buf.toString();
+ }
+
/**
* Return the field name for given suggested name, possibly adding
* leading underscore.
Added: openjpa/trunk/openjpa-persistence-jdbc/src/main/java/org/apache/openjpa/persistence/jdbc/AnnotationPersistenceMappingSerializer.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/main/java/org/apache/openjpa/persistence/jdbc/AnnotationPersistenceMappingSerializer.java?view=auto&rev=552358
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/main/java/org/apache/openjpa/persistence/jdbc/AnnotationPersistenceMappingSerializer.java (added)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/main/java/org/apache/openjpa/persistence/jdbc/AnnotationPersistenceMappingSerializer.java Sun Jul 1 12:37:04 2007
@@ -0,0 +1,793 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+package org.apache.openjpa.persistence.jdbc;
+
+import org.apache.openjpa.persistence.AnnotationPersistenceMetaDataSerializer;
+import org.apache.openjpa.persistence.PersistenceStrategy;
+import org.apache.openjpa.persistence.AnnotationBuilder;
+import org.apache.openjpa.jdbc.meta.QueryResultMapping;
+import org.apache.openjpa.jdbc.meta.MappingRepository;
+import org.apache.openjpa.jdbc.meta.ClassMapping;
+import org.apache.openjpa.jdbc.meta.FieldMapping;
+import org.apache.openjpa.jdbc.meta.ClassMappingInfo;
+import org.apache.openjpa.jdbc.meta.DiscriminatorMappingInfo;
+import org.apache.openjpa.jdbc.meta.MappingInfo;
+import org.apache.openjpa.jdbc.meta.SequenceMapping;
+import org.apache.openjpa.jdbc.meta.ValueMappingInfo;
+import org.apache.openjpa.jdbc.meta.strats.FlatClassStrategy;
+import org.apache.openjpa.jdbc.meta.strats.VerticalClassStrategy;
+import org.apache.openjpa.jdbc.meta.strats.FullClassStrategy;
+import org.apache.openjpa.jdbc.meta.strats.EnumValueHandler;
+import org.apache.openjpa.jdbc.conf.JDBCConfiguration;
+import org.apache.openjpa.jdbc.schema.*;
+import org.apache.openjpa.jdbc.schema.Unique;
+import org.apache.openjpa.jdbc.sql.DBDictionary;
+import org.apache.openjpa.meta.MetaDataRepository;
+import org.apache.openjpa.meta.ClassMetaData;
+import org.apache.openjpa.meta.FieldMetaData;
+import org.apache.openjpa.meta.JavaTypes;
+import org.apache.openjpa.meta.SequenceMetaData;
+import org.apache.openjpa.meta.MetaDataModes;
+import org.apache.commons.lang.StringUtils;
+
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Map;
+import java.util.HashMap;
+import java.sql.Types;
+import java.lang.annotation.Annotation;
+
+import serp.util.Strings;
+
+import javax.persistence.TemporalType;
+import javax.persistence.EnumType;
+import javax.persistence.InheritanceType;
+import javax.persistence.Table;
+import javax.persistence.SecondaryTable;
+import javax.persistence.Inheritance;
+import javax.persistence.DiscriminatorValue;
+import javax.persistence.DiscriminatorColumn;
+import javax.persistence.JoinTable;
+import javax.persistence.Lob;
+import javax.persistence.Temporal;
+import javax.persistence.Enumerated;
+import javax.persistence.UniqueConstraint;
+import javax.persistence.TableGenerator;
+import javax.persistence.JoinColumns;
+import javax.persistence.JoinColumn;
+import javax.persistence.PrimaryKeyJoinColumn;
+import javax.persistence.PrimaryKeyJoinColumns;
+import javax.persistence.SqlResultSetMapping;
+import javax.persistence.EntityResult;
+import javax.persistence.FieldResult;
+import javax.persistence.ColumnResult;
+
+//@todo: javadocs
+
+/**
+ * Serializes persistence mappings as annotations.
+ *
+ * @since 1.0.0
+ * @author Steve Kim
+ * @author Gokhan Ergul
+ * @nojavadoc
+ */
+public class AnnotationPersistenceMappingSerializer
+ extends AnnotationPersistenceMetaDataSerializer {
+
+ private static final int TYPE_RESULTMAP = TYPE_QUERY + 1;
+
+ private List<QueryResultMapping> _results = null;
+ private boolean _sync = false;
+
+ private Map<QueryResultMapping, List<AnnotationBuilder>> _rsmAnnos = null;
+
+ /**
+ * Constructor. Supply configuration.
+ */
+ public AnnotationPersistenceMappingSerializer(JDBCConfiguration conf) {
+ super(conf);
+ }
+
+ /**
+ * Whether to automatically synchronize mapping info with data available
+ * from mapped components before serialization. Defaults to false.
+ */
+ public boolean getSyncMappingInfo() {
+ return _sync;
+ }
+
+ /**
+ * Whether to automatically synchronize mapping info with data available
+ * from mapped components before serialization. Defaults to false.
+ */
+ public void setSyncMappingInfo(boolean sync) {
+ _sync = sync;
+ }
+
+ /**
+ * Adds the given result set mapping to local cache.
+ */
+ public void addQueryResultMapping(QueryResultMapping meta) {
+ if (_results == null)
+ _results = new ArrayList<QueryResultMapping>();
+ _results.add(meta);
+ }
+
+ /**
+ * Removes given result set mapping from the local cache.
+ */
+ public boolean removeQueryResultMapping(QueryResultMapping meta) {
+ return _results != null && _results.remove(meta);
+ }
+
+ @Override
+ public void addAll(MetaDataRepository repos) {
+ super.addAll(repos);
+ for (QueryResultMapping res : ((MappingRepository) repos)
+ .getQueryResultMappings())
+ addQueryResultMapping(res);
+ }
+
+ @Override
+ public boolean removeAll(MetaDataRepository repos) {
+ boolean removed = super.removeAll(repos);
+ for (QueryResultMapping res : ((MappingRepository) repos)
+ .getQueryResultMappings())
+ removed |= removeQueryResultMapping(res);
+ return removed;
+ }
+
+ @Override
+ public void clear() {
+ super.clear();
+ if (_results != null)
+ _results.clear();
+ }
+
+ /**
+ * Add an annotation builder to list of builders for the specified
+ * class metadata.
+ */
+ protected void addAnnotation(AnnotationBuilder ab, QueryResultMapping meta) {
+ if (_rsmAnnos == null)
+ _rsmAnnos = new HashMap<QueryResultMapping, List<AnnotationBuilder>>();
+ List<AnnotationBuilder> list = _rsmAnnos.get(meta);
+ if (list == null) {
+ list = new ArrayList<AnnotationBuilder>();
+ _rsmAnnos.put(meta, list);
+ }
+ list.add(ab);
+ }
+
+ /**
+ * Creates an an annotation builder for the specified class metadata
+ * and adds it to list of builders.
+ */
+ protected AnnotationBuilder addAnnotation(
+ Class<? extends Annotation> annType, QueryResultMapping meta) {
+ AnnotationBuilder ab = newAnnotationBuilder(annType);
+ if (meta == null)
+ return ab;
+ addAnnotation(ab, meta);
+ return ab;
+ }
+
+
+ @Override
+ protected void serializeClass(ClassMetaData meta) {
+ if (_sync && isMappingMode() && meta instanceof ClassMapping) {
+ // sync if resolved and mapped
+ ClassMapping cls = (ClassMapping) meta;
+ if ((cls.getResolve() & MetaDataModes.MODE_MAPPING) != 0 &&
+ cls.isMapped()) {
+ cls.syncMappingInfo();
+ cls.getDiscriminator().syncMappingInfo();
+ cls.getVersion().syncMappingInfo();
+ FieldMapping[] fields;
+ if (cls.getEmbeddingMetaData() == null)
+ fields = cls.getDefinedFieldMappings();
+ else
+ fields = cls.getFieldMappings();
+ for (FieldMapping f : fields)
+ f.syncMappingInfo();
+ }
+ }
+ super.serializeClass(meta);
+ }
+
+ @Override
+ protected void serializeClassMappingContent(ClassMetaData mapping) {
+ ClassMapping cls = (ClassMapping) mapping;
+ ClassMappingInfo info = cls.getMappingInfo();
+ AnnotationBuilder abTable = addAnnotation(Table.class, mapping);
+ serializeTable(info.getTableName(), Strings
+ .getClassName(mapping.getDescribedType()), null,
+ info.getUniques(), abTable);
+ serializeColumns(info, ColType.PK_JOIN, null, abTable, cls);
+ for (String second : info.getSecondaryTableNames()) {
+ AnnotationBuilder abSecTable =
+ addAnnotation(SecondaryTable.class, mapping);
+ serializeTable(second, null, info, null, abSecTable);
+ }
+ }
+
+ @Override
+ protected void serializeInheritanceContent(ClassMetaData mapping) {
+ ClassMapping cls = (ClassMapping) mapping;
+ ClassMappingInfo info = cls.getMappingInfo();
+ DiscriminatorMappingInfo dinfo = cls.getDiscriminator()
+ .getMappingInfo();
+ String strat = info.getHierarchyStrategy();
+ if (null == strat)
+ return;
+ String itypecls = Strings.getClassName(InheritanceType.class);
+ AnnotationBuilder abInheritance =
+ addAnnotation(Inheritance.class, mapping);
+ if (FlatClassStrategy.ALIAS.equals(strat))
+ abInheritance.add("strategy", itypecls + ".SINGLE_TABLE");
+ else if (VerticalClassStrategy.ALIAS.equals(strat))
+ abInheritance.add("strategy", itypecls + ".JOINED");
+ else if (FullClassStrategy.ALIAS.equals(strat))
+ abInheritance.add("strategy", itypecls + ".TABLE_PER_CLASS");
+ if (dinfo.getValue() != null) {
+ AnnotationBuilder abDiscVal =
+ addAnnotation(DiscriminatorValue.class, mapping);
+ abDiscVal.add(null, dinfo.getValue());
+ }
+ AnnotationBuilder abDiscCol =
+ addAnnotation(DiscriminatorColumn.class, mapping);
+ serializeColumns(dinfo, ColType.DISC, null, abDiscCol, null);
+ }
+
+ /**
+ * Serialize table optionally listing primary-key-joins stored
+ * in the given {@link org.apache.openjpa.jdbc.meta.ClassMappingInfo}.
+ */
+ private void serializeTable(String table, String defaultName,
+ ClassMappingInfo secondaryInfo, Unique[] uniques,
+ AnnotationBuilder ab) {
+ List<Column> cols = null;
+ if (secondaryInfo != null)
+ cols = (List<Column>) secondaryInfo.getSecondaryTableJoinColumns
+ (table);
+
+ boolean print = (cols != null && cols.size() > 0) ||
+ (uniques != null && uniques.length > 0);
+ if (table != null
+ && (defaultName == null || !defaultName.equals(table))) {
+ print = true;
+ int index = table.indexOf('.');
+ if (index < 0)
+ ab.add("name", table);
+ else {
+ ab.add("schema", table.substring(0, index));
+ ab.add("name", table.substring(index + 1));
+ }
+ }
+ if (print) {
+ if (cols != null) {
+ for (Column col : cols)
+ serializeColumn(col, ColType.PK_JOIN,
+ null, false, ab, null);
+ }
+ if (uniques != null) {
+ for (Unique unique: uniques) {
+ AnnotationBuilder abUniqueConst =
+ newAnnotationBuilder(UniqueConstraint.class);
+ serializeUniqueConstraint(unique, abUniqueConst);
+ ab.add("uniqueConstraints", abUniqueConst);
+ }
+ }
+ }
+ }
+
+ @Override
+ protected boolean serializeAttributeOverride(FieldMetaData fmd,
+ FieldMetaData orig) {
+ if (orig == null || fmd == orig)
+ return false;
+
+ FieldMapping field = (FieldMapping) fmd;
+ FieldMapping field2 = (FieldMapping) orig;
+ if (field.getMappingInfo().hasSchemaComponents()
+ || field2.getMappingInfo().hasSchemaComponents())
+ return true;
+
+ ValueMappingInfo info = field.getValueInfo();
+ List<Column> cols = (List<Column>) info.getColumns();
+ if (cols == null || cols.size() == 0)
+ return false;
+ ValueMappingInfo info2 = field2.getValueInfo();
+ List<Column> cols2 = (List<Column>) info2.getColumns();
+ if (cols2 == null || cols2.size() != cols.size())
+ return true;
+ if (cols.size() != 1)
+ return true;
+
+ Column col;
+ Column col2;
+ for (int i = 0; i < cols.size(); i++) {
+ col = cols.get(i);
+ col2 = cols2.get(i);
+ if (!StringUtils.equals(col.getName(), col2.getName()))
+ return true;
+ if (!StringUtils.equals(col.getTypeName(), col2.getTypeName()))
+ return true;
+ if (col.getSize() != col2.getSize())
+ return true;
+ if (col.getDecimalDigits() != col2.getDecimalDigits())
+ return true;
+ if (col.getFlag(Column.FLAG_UNINSERTABLE)
+ != col2.getFlag(Column.FLAG_UNINSERTABLE))
+ return true;
+ if (col.getFlag(Column.FLAG_UNUPDATABLE)
+ != col2.getFlag(Column.FLAG_UNUPDATABLE))
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ protected void serializeAttributeOverrideMappingContent(FieldMetaData fmd,
+ FieldMetaData orig, AnnotationBuilder ab) {
+ FieldMapping fm = (FieldMapping) fmd;
+ serializeColumns(fm.getValueInfo(), ColType.COL, fm.getMappingInfo()
+ .getTableName(), ab, fmd);
+ }
+
+ @Override
+ protected PersistenceStrategy getStrategy(FieldMetaData fmd) {
+ PersistenceStrategy strat = super.getStrategy(fmd);
+ FieldMapping field = (FieldMapping) fmd;
+ switch (strat) {
+ case MANY_MANY:
+ // we can differentiate a one-many by the fact that there is no
+ // secondary table join, or the fk is unique
+ if (field.getMappedBy() == null
+ && (field.getMappingInfo().getJoinDirection()
+ == MappingInfo.JOIN_NONE
+ || field.getElementMapping().getValueInfo().getUnique()
+ != null))
+ return PersistenceStrategy.ONE_MANY;
+ break;
+ case MANY_ONE:
+ // inverse join cols or unique fk?
+ if (field.getValueInfo().getJoinDirection()
+ == MappingInfo.JOIN_INVERSE
+ || field.getValueInfo().getUnique() != null)
+ return PersistenceStrategy.ONE_ONE;
+
+ // scan for primary-key-join-column
+ List<Column> cols = field.getValueInfo().getColumns();
+ boolean pkJoin = cols != null && cols.size() > 0;
+ for (int i = 0; pkJoin && i < cols.size(); i++)
+ pkJoin = cols.get(i).getFlag(Column.FLAG_PK_JOIN);
+ if (pkJoin)
+ return PersistenceStrategy.ONE_ONE;
+ break;
+ }
+ return strat;
+ }
+
+ @Override
+ protected void serializeFieldMappingContent(FieldMetaData fmd,
+ PersistenceStrategy strategy, AnnotationBuilder ab) {
+ if (fmd.getMappedBy() != null)
+ return;
+
+ // while I'd like to do auto detection based on join directions, etc.
+ // the distinguished column / table / etc names forces our hand
+ // esp for OpenJPA custom mappings.
+ FieldMapping field = (FieldMapping) fmd;
+ switch (strategy) {
+ case ONE_ONE:
+ case MANY_ONE:
+ serializeColumns(field.getValueInfo(), ColType.JOIN,
+ field.getMappingInfo().getTableName(), null, fmd);
+ return;
+ case ONE_MANY:
+ if (field.getMappingInfo().getJoinDirection() ==
+ MappingInfo.JOIN_NONE) {
+ serializeColumns(field.getElementMapping().getValueInfo(),
+ ColType.JOIN, null, null, fmd);
+ return;
+ }
+ // else no break
+ case MANY_MANY:
+ if (field.getMappingInfo().hasSchemaComponents()
+ || field.getElementMapping().getValueInfo()
+ .hasSchemaComponents()) {
+ AnnotationBuilder abJoinTbl =
+ addAnnotation(JoinTable.class, fmd);
+ String table = field.getMappingInfo().getTableName();
+ if (table != null) {
+ int index = table.indexOf('.');
+ if (index < 0)
+ abJoinTbl.add("name", table);
+ else {
+ abJoinTbl.add("schema", table.substring(0, index));
+ abJoinTbl.add("name", table.substring(index + 1));
+ }
+ }
+ serializeColumns(field.getMappingInfo(),
+ ColType.JOIN, null, abJoinTbl, null);
+ serializeColumns(field.getElementMapping().getValueInfo(),
+ ColType.INVERSE, null, abJoinTbl, null);
+ }
+ return;
+ }
+
+ serializeColumns(field.getValueInfo(), ColType.COL,
+ field.getMappingInfo().getTableName(), null, fmd);
+ if (strategy == PersistenceStrategy.BASIC && isLob(field)) {
+ addAnnotation(Lob.class, fmd);
+ }
+ TemporalType temporal = getTemporal(field);
+ if (temporal != null) {
+ addAnnotation(Temporal.class, fmd).
+ add(null, temporal);
+ }
+
+ EnumType enumType = getEnumType(field);
+ if (enumType != null && enumType != EnumType.ORDINAL) {
+ addAnnotation(Enumerated.class, fmd).
+ add(null, enumType);
+ }
+ }
+
+ /**
+ * Determine if the field is a lob.
+ */
+ private boolean isLob(FieldMapping field) {
+ for (Column col : (List<Column>) field.getValueInfo().getColumns())
+ if (col.getType() == Types.BLOB || col.getType() == Types.CLOB)
+ return true;
+ return false;
+ }
+
+ /**
+ * Return field's temporal type.
+ */
+ private TemporalType getTemporal(FieldMapping field) {
+ if (field.getDeclaredTypeCode() != JavaTypes.DATE
+ && field.getDeclaredTypeCode() != JavaTypes.CALENDAR)
+ return null;
+
+ DBDictionary dict = ((JDBCConfiguration) getConfiguration())
+ .getDBDictionaryInstance();
+ int def = dict.getJDBCType(field.getTypeCode(), false);
+ for (Column col : (List<Column>) field.getValueInfo().getColumns()) {
+ if (col.getType() == def)
+ continue;
+ switch (col.getType()) {
+ case Types.DATE:
+ return TemporalType.DATE;
+ case Types.TIME:
+ return TemporalType.TIME;
+ case Types.TIMESTAMP:
+ return TemporalType.TIMESTAMP;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Return enum type for the field.
+ */
+ protected EnumType getEnumType(FieldMapping field) {
+ if (field.getDeclaredTypeCode() != JavaTypes.OBJECT)
+ return null;
+ if (!(field.getHandler() instanceof EnumValueHandler))
+ return null;
+ return ((EnumValueHandler) field.getHandler()).getStoreOrdinal()
+ ? EnumType.ORDINAL : EnumType.STRING;
+ }
+
+ /**
+ * Serialize the columns in the given mapping info.
+ */
+ private void serializeColumns(MappingInfo info, ColType type,
+ String secondary, AnnotationBuilder ab, Object meta) {
+ List<Column> cols = (List<Column>) info.getColumns();
+ if (cols == null)
+ return;
+ AnnotationBuilder abContainer = ab;
+ if (cols.size() > 1) {
+ Class grpType = type.getColumnGroupAnnotationType();
+ if (null != grpType) {
+ AnnotationBuilder abGrp = newAnnotationBuilder(grpType);
+ if (null == ab)
+ addAnnotation(abGrp, meta);
+ else
+ ab.add(null, abGrp);
+ abContainer = abGrp;
+ }
+ }
+ for (Column col : cols)
+ serializeColumn(col, type, secondary,
+ info.getUnique() != null, abContainer, meta);
+ }
+
+ /**
+ * Serialize a single column.
+ */
+ private void serializeColumn(Column col, ColType type, String secondary,
+ boolean unique, AnnotationBuilder ab, Object meta) {
+ FieldMetaData fmd = meta instanceof FieldMetaData ?
+ (FieldMetaData) meta : null;
+ AnnotationBuilder abCol = newAnnotationBuilder(
+ type.getColumnAnnotationType());
+ if (col.getName() != null && (null == fmd ||
+ !col.getName().equalsIgnoreCase(fmd.getName())))
+ abCol.add("name", col.getName());
+ if (col.getTypeName() != null)
+ abCol.add("columnDefinition", col.getTypeName());
+ if (col.getTarget() != null
+ && (type == ColType.JOIN || type == ColType.INVERSE
+ || type == ColType.PK_JOIN))
+ abCol.add("referencedColumnName", col.getTarget());
+ if (type == ColType.COL || type == ColType.JOIN
+ || type == ColType.PK_JOIN) {
+ if (unique)
+ abCol.add("unique", true);
+ if (col.isNotNull())
+ abCol.add("nullable", false);
+ if (col.getFlag(Column.FLAG_UNINSERTABLE))
+ abCol.add("insertable", false);
+ if (col.getFlag(Column.FLAG_UNUPDATABLE))
+ abCol.add("updatable", false);
+ if (secondary != null)
+ abCol.add("table", secondary);
+
+ if (type == ColType.COL) {
+ if (col.getSize() > 0 && col.getSize() != 255)
+ abCol.add("length", col.getSize());
+ if (col.getDecimalDigits() != 0)
+ abCol.add("scale", col.getDecimalDigits());
+ }
+ }
+
+ if (type != ColType.COL || abCol.hasComponents()) {
+ if (null != ab) {
+ String key = null;
+ if (ab.getType() == JoinTable.class) {
+ switch(type) {
+ case JOIN:
+ key = "joinColumns";
+ break;
+ case INVERSE:
+ key = "inverseJoinColumns";
+ break;
+ }
+ }
+ ab.add(key, abCol);
+ } else {
+ addAnnotation(abCol, meta);
+ }
+ }
+ }
+
+ private void serializeUniqueConstraint(Unique unique,
+ AnnotationBuilder ab) {
+ StringBuilder sb = new StringBuilder();
+ Column[] columns = unique.getColumns();
+ for (Column column:columns) {
+ if (sb.length() > 0)
+ sb.append(", ");
+ sb.append(column.getName());
+ }
+ if (columns.length > 1)
+ sb.insert(0, "{").append("}");
+ ab.add("columnNames", sb.toString());
+ }
+
+ @Override
+ protected SerializationComparator newSerializationComparator() {
+ return new AnnotationPersistenceMappingSerializer.
+ MappingSerializationComparator();
+ }
+
+ @Override
+ protected void addSystemMappingElements(Collection toSerialize) {
+ if (isQueryMode())
+ toSerialize.addAll(getQueryResultMappings(null));
+ }
+
+ @Override
+ protected int type(Object o) {
+ int type = super.type(o);
+ if (type == -1 && o instanceof QueryResultMapping)
+ return TYPE_RESULTMAP;
+ return type;
+ }
+
+ /**
+ * Return the result set mappings for the given scope.
+ */
+ private List<QueryResultMapping> getQueryResultMappings(ClassMetaData cm) {
+ if (_results == null || _results.isEmpty())
+ return (List<QueryResultMapping>) Collections.EMPTY_LIST;
+
+ List<QueryResultMapping> result = null;
+ for (int i = 0; i < _results.size(); i++) {
+ QueryResultMapping element = _results.get(i);
+ if ((cm == null && element.getSourceScope() != null) || (cm != null
+ && element.getSourceScope() != cm.getDescribedType()))
+ continue;
+
+ if (result == null)
+ result = new ArrayList<QueryResultMapping>(_results.size() - i);
+ result.add(element);
+ }
+ return (result == null)
+ ? (List<QueryResultMapping>) Collections.EMPTY_LIST : result;
+ }
+
+ @Override
+ protected void serializeSystemMappingElement(Object obj) {
+ if (obj instanceof QueryResultMapping)
+ serializeQueryResultMapping((QueryResultMapping) obj, null);
+ }
+
+ @Override
+ protected void serializeQueryMappings(ClassMetaData meta) {
+ for (QueryResultMapping res : getQueryResultMappings(meta))
+ serializeQueryResultMapping(res, meta);
+ }
+
+ /**
+ * Serialize given result set mapping.
+ */
+ private void serializeQueryResultMapping(QueryResultMapping meta,
+ ClassMetaData clsmeta) {
+ AnnotationBuilder ab = addAnnotation(SqlResultSetMapping.class, meta);
+ if (null != clsmeta)
+ addAnnotation(ab, clsmeta);
+ ab.add("name", meta.getName());
+ for (QueryResultMapping.PCResult pc : meta.getPCResults()) {
+ AnnotationBuilder abEntRes =
+ newAnnotationBuilder(EntityResult.class);
+ ab.add("entities", abEntRes);
+ abEntRes.add("entityClass", pc.getCandidateType());
+ Object discrim = pc.getMapping(pc.DISCRIMINATOR);
+ if (discrim != null)
+ abEntRes.add("discriminatorColumn", discrim.toString());
+
+ for (String path : pc.getMappingPaths()) {
+ AnnotationBuilder abFldRes =
+ newAnnotationBuilder(FieldResult.class);
+ abEntRes.add("fields", abFldRes);
+ abFldRes.add("name", path);
+ abFldRes.add("column", pc.getMapping(path).toString());
+ }
+ }
+ for (Object col : meta.getColumnResults()) {
+ AnnotationBuilder abColRes =
+ newAnnotationBuilder(ColumnResult.class);
+ abColRes.add("name", col.toString());
+ }
+ }
+
+ @Override
+ protected void serializeSequence(SequenceMetaData meta) {
+ if (SequenceMapping.IMPL_VALUE_TABLE.equals(meta.getSequencePlugin())) {
+ super.serializeSequence(meta);
+ return;
+ }
+
+ AnnotationBuilder abTblGen = addAnnotation(TableGenerator.class, meta);
+ SequenceMapping seq = (SequenceMapping) meta;
+ abTblGen.add("name", seq.getName());
+ String table = seq.getTable();
+ if (table != null) {
+ int dotIdx = table.indexOf('.');
+ if (dotIdx == -1)
+ abTblGen.add("table", table);
+ else {
+ abTblGen.add("table", table.substring(dotIdx + 1));
+ abTblGen.add("schema", table.substring(0, dotIdx));
+ }
+ }
+ if (!StringUtils.isEmpty(seq.getPrimaryKeyColumn()))
+ abTblGen.add("pkColumnName", seq.getPrimaryKeyColumn());
+ if (!StringUtils.isEmpty(seq.getSequenceColumn()))
+ abTblGen.add("valueColumnName", seq.getSequenceColumn());
+ if (!StringUtils.isEmpty(seq.getPrimaryKeyValue()))
+ abTblGen.add("pkColumnValue", seq.getPrimaryKeyValue());
+ if (seq.getAllocate() != 50 && seq.getAllocate() != -1)
+ abTblGen.add("allocationSize", seq.getAllocate() + "");
+ if (seq.getInitialValue() != 0 && seq.getInitialValue() != -1)
+ abTblGen.add("initialValue", seq.getInitialValue() + "");
+ }
+
+ /**
+ * Column types serialized under different names.
+ */
+ private static enum ColType {
+
+ COL,
+ JOIN,
+ INVERSE,
+ PK_JOIN,
+ DISC;
+
+ private Class<? extends Annotation> getColumnAnnotationType() {
+ switch(this) {
+ case COL:
+ return javax.persistence.Column.class;
+ case JOIN:
+ case INVERSE:
+ return JoinColumn.class;
+ case PK_JOIN:
+ return PrimaryKeyJoinColumn.class;
+ case DISC:
+ return DiscriminatorColumn.class;
+ }
+ return null;
+ }
+
+ private Class<? extends Annotation> getColumnGroupAnnotationType() {
+ switch(this) {
+ case JOIN:
+ case INVERSE:
+ return JoinColumns.class;
+ case PK_JOIN:
+ return PrimaryKeyJoinColumns.class;
+ }
+ return null;
+ }
+
+ }
+
+ /**
+ * Extends {@link SerializationComparator} for store-specific tags such
+ * as <sql-result-set-mapping>.
+ *
+ * @author Pinaki Poddar
+ */
+ protected class MappingSerializationComparator
+ extends SerializationComparator {
+
+ protected int compareUnknown(Object o1, Object o2) {
+ if (!(o1 instanceof QueryResultMapping))
+ return super.compareUnknown(o1, o2);
+
+ QueryResultMapping res1 = (QueryResultMapping) o1;
+ QueryResultMapping res2 = (QueryResultMapping) o2;
+
+ // system scope before class scope
+ Object scope1 = res1.getSourceScope();
+ Object scope2 = res2.getSourceScope();
+ if (scope1 == null && scope2 != null)
+ return -1;
+ if (scope1 != null && scope2 == null)
+ return 1;
+
+ // compare on listing index, or if none/same, use name
+ int listingIndex1 = res1.getListingIndex();
+ int listingIndex2 = res2.getListingIndex();
+ if (listingIndex1 != listingIndex2)
+ return listingIndex1 - listingIndex2;
+ return res1.getName ().compareTo (res2.getName ());
+ }
+ }
+}
Propchange: openjpa/trunk/openjpa-persistence-jdbc/src/main/java/org/apache/openjpa/persistence/jdbc/AnnotationPersistenceMappingSerializer.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: openjpa/trunk/openjpa-persistence-jdbc/src/main/java/org/apache/openjpa/persistence/jdbc/PersistenceMappingFactory.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/main/java/org/apache/openjpa/persistence/jdbc/PersistenceMappingFactory.java?view=diff&rev=552358&r1=552357&r2=552358
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/main/java/org/apache/openjpa/persistence/jdbc/PersistenceMappingFactory.java (original)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/main/java/org/apache/openjpa/persistence/jdbc/PersistenceMappingFactory.java Sun Jul 1 12:37:04 2007
@@ -21,10 +21,11 @@
import org.apache.openjpa.jdbc.conf.JDBCConfiguration;
import org.apache.openjpa.jdbc.meta.MappingRepository;
import org.apache.openjpa.meta.MetaDataFactory;
-import org.apache.openjpa.persistence.AnnotationPersistenceMetaDataParser;
import org.apache.openjpa.persistence.PersistenceMetaDataFactory;
import org.apache.openjpa.persistence.XMLPersistenceMetaDataParser;
import org.apache.openjpa.persistence.XMLPersistenceMetaDataSerializer;
+import org.apache.openjpa.persistence.AnnotationPersistenceMetaDataParser;
+import org.apache.openjpa.persistence.AnnotationPersistenceMetaDataSerializer;
/**
* {@link MetaDataFactory} for JPA mapping information.
@@ -46,6 +47,15 @@
parser.setMappingOverride(((MappingRepository) repos).
getStrategyInstaller().isAdapting());
return parser;
+ }
+
+ protected AnnotationPersistenceMetaDataSerializer newAnnotationSerializer()
+ {
+ AnnotationPersistenceMappingSerializer ser =
+ new AnnotationPersistenceMappingSerializer((JDBCConfiguration)
+ repos.getConfiguration());
+ ser.setSyncMappingInfo(true);
+ return ser;
}
@Override
Added: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/AnnotationBuilder.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/AnnotationBuilder.java?view=auto&rev=552358
==============================================================================
--- openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/AnnotationBuilder.java (added)
+++ openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/AnnotationBuilder.java Sun Jul 1 12:37:04 2007
@@ -0,0 +1,200 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+package org.apache.openjpa.persistence;
+
+import serp.util.Strings;
+
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.EnumSet;
+import java.lang.annotation.Annotation;
+
+import org.apache.commons.lang.StringUtils;
+
+/**
+ * Helper class to stringify annotation declarations.
+ *
+ * @author Gokhan Ergul
+ * @since 1.0.0
+ */
+public class AnnotationBuilder {
+
+ private Class<? extends Annotation> type;
+ private List<AnnotationEntry> components =
+ new ArrayList<AnnotationEntry>();
+
+ protected AnnotationBuilder(Class<? extends Annotation> type) {
+ this.type = type;
+ }
+
+ public Class<? extends Annotation> getType() {
+ return this.type;
+ }
+
+ public AnnotationBuilder add(String key, String val) {
+ return doAdd(key, val);
+ }
+
+ public AnnotationBuilder add(String key, boolean val) {
+ return doAdd(key, val);
+ }
+
+ public AnnotationBuilder add(String key, int val) {
+ return doAdd(key, val);
+ }
+
+ public AnnotationBuilder add(String key, Class val) {
+ return doAdd(key, val);
+ }
+
+ public AnnotationBuilder add(String key, EnumSet val) {
+ return doAdd(key, val);
+ }
+
+ public AnnotationBuilder add(String key, Enum val) {
+ return doAdd(key, val);
+ }
+
+ @SuppressWarnings("unchecked")
+ public AnnotationBuilder add(String key, AnnotationBuilder val) {
+ if (null == val)
+ return this;
+ AnnotationEntry ae = find(key);
+ if (null == ae) {
+ doAdd(key, val);
+ } else {
+ List<AnnotationBuilder> list;
+ if (ae.value instanceof List) {
+ list = (List<AnnotationBuilder>) ae.value;
+ } else if (ae.value instanceof AnnotationBuilder) {
+ list = new ArrayList<AnnotationBuilder> ();
+ list.add((AnnotationBuilder) ae.value);
+ ae.value = list;
+ } else {
+ throw new IllegalArgumentException(
+ "Unexpected type: " + ae.value);
+ }
+ list.add(val);
+ }
+ return this;
+ }
+
+ public boolean hasComponents() {
+ return components.size() > 0;
+ }
+
+ private AnnotationBuilder doAdd (String key, Object val) {
+ if (null != val)
+ components.add(new AnnotationEntry(key, val));
+ return this;
+ }
+
+ private AnnotationEntry find(String key) {
+ for(AnnotationEntry ae: components) {
+ // null key references considered equal
+ if (StringUtils.equals(ae.key, key))
+ return ae;
+ }
+ return null;
+ }
+
+ static String enumToString(Enum e) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(Strings.getClassName(e.getClass())).
+ append(".").append(e);
+ return sb.toString();
+ }
+
+ static String enumSetToString(EnumSet set) {
+ StringBuilder sb = new StringBuilder();
+ for (Iterator i = set.iterator(); i.hasNext();) {
+ Object e = i.next();
+ sb.append(Strings.getClassName(e.getClass())).
+ append(".").append(e);
+ if (i.hasNext())
+ sb.append(", ");
+ }
+ return sb.toString();
+ }
+
+ protected void toString(StringBuilder sb) {
+ sb.append("@").append(Strings.getClassName(type));
+ if (components.size() == 0)
+ return;
+ sb.append("(");
+ for (Iterator<AnnotationEntry> i = components.iterator(); i.hasNext();)
+ {
+ AnnotationEntry e = i.next();
+ e.toString(sb);
+ if (i.hasNext())
+ sb.append(", ");
+ }
+ sb.append(")");
+ }
+
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ toString(sb);
+ return sb.toString();
+ }
+
+}
+
+class AnnotationEntry {
+
+ String key;
+ Object value;
+
+ AnnotationEntry(String key, Object value) {
+ this.key = key;
+ this.value = value;
+ }
+
+ @SuppressWarnings("unchecked")
+ void toString(StringBuilder sb) {
+ if (null != key)
+ sb.append(key).append("=");
+
+ List.class.getTypeParameters();
+ if (value instanceof List) {
+ sb.append("{");
+ List<AnnotationBuilder> l = (List<AnnotationBuilder>) value;
+ for (Iterator<AnnotationBuilder> i = l.iterator(); i.hasNext();) {
+ AnnotationBuilder ab = i.next();
+ sb.append(ab.toString());
+ if (i.hasNext())
+ sb.append(", ");
+ }
+ sb.append("}");
+ } else if (value instanceof Class) {
+ String cls = ((Class) value).getName().replace('$', '.');
+ sb.append(cls).append(".class");
+ } else if (value instanceof String) {
+ sb.append('"').append(value).append('"');
+ } else if (value instanceof Enum) {
+ sb.append(AnnotationBuilder.enumToString((Enum) value));
+ } else if (value instanceof EnumSet) {
+ sb.append(AnnotationBuilder.enumSetToString((EnumSet) value));
+ } else {
+ sb.append(value);
+ }
+ }
+
+}
Propchange: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/AnnotationBuilder.java
------------------------------------------------------------------------------
svn:eol-style = native