mirror of
https://github.com/apache/openjpa.git
synced 2025-02-21 17:45:51 +00:00
OPENJPA-239 Patch to support the generation of annotation mappings using the reverse mapping tool
git-svn-id: https://svn.apache.org/repos/asf/openjpa/trunk@552358 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
0b356dfc0d
commit
85b2e766ca
@ -122,6 +122,14 @@ public class ReverseMappingToolTask
|
||||
flags.blobAsObject = blobAsObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
@ -201,6 +209,22 @@ public class ReverseMappingToolTask
|
||||
flags.metaDataLevel = level.getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
@ -255,6 +279,18 @@ public class ReverseMappingToolTask
|
||||
return new String[]{
|
||||
"package",
|
||||
"class",
|
||||
"none"
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public static class AccessType
|
||||
extends EnumeratedAttribute {
|
||||
|
||||
public String[] getValues() {
|
||||
return new String[]{
|
||||
"field",
|
||||
"property"
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -136,9 +136,16 @@ public class ReverseMappingTool
|
||||
*/
|
||||
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 @@ public class ReverseMappingTool
|
||||
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 @@ public class ReverseMappingTool
|
||||
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 @@ public class ReverseMappingTool
|
||||
// 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.
|
||||
*/
|
||||
@ -326,6 +339,22 @@ public class ReverseMappingTool
|
||||
_blobAsObj = blobAsObj;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
@ -478,6 +507,39 @@ public class ReverseMappingTool
|
||||
_versStrat = versionStrat;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
@ -784,7 +846,11 @@ public class ReverseMappingTool
|
||||
_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 @@ public class ReverseMappingTool
|
||||
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 @@ public class ReverseMappingTool
|
||||
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 @@ public class ReverseMappingTool
|
||||
tool.setIdentityClassSuffix(getIdentityClassSuffix());
|
||||
tool.setInverseRelations(getInverseRelations());
|
||||
tool.setDetachable(getDetachable());
|
||||
tool.setGenerateAnnotations(getGenerateAnnotations());
|
||||
tool.setCustomizer(getCustomizer());
|
||||
tool.setCodeFormat(getCodeFormat());
|
||||
return tool;
|
||||
@ -1667,6 +1760,9 @@ public class ReverseMappingTool
|
||||
* 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 @@ public class ReverseMappingTool
|
||||
* 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 @@ public class ReverseMappingTool
|
||||
("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 @@ public class ReverseMappingTool
|
||||
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 @@ public class ReverseMappingTool
|
||||
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 @@ public class ReverseMappingTool
|
||||
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 class ReverseMappingTool
|
||||
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 class ReverseMappingTool
|
||||
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 @@ public class ReverseMappingTool
|
||||
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 @@ public class ReverseMappingTool
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -359,6 +359,7 @@ revtool-map: Calculating reverse mappings.
|
||||
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 @@ revtool-usage: Usage: java org.apache.openjpa.jdbc.meta.ReverseMappingTool\n\
|
||||
\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 @@ revtool-usage: Usage: java org.apache.openjpa.jdbc.meta.ReverseMappingTool\n\
|
||||
\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\
|
||||
|
@ -24,8 +24,10 @@ import java.io.Writer;
|
||||
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 @@ public class CodeGenerator {
|
||||
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 @@ public class CodeGenerator {
|
||||
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 @@ public class CodeGenerator {
|
||||
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 @@ public class CodeGenerator {
|
||||
|
||||
// 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 @@ public class CodeGenerator {
|
||||
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);
|
||||
@ -426,6 +460,21 @@ public class CodeGenerator {
|
||||
return code.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 @@ public class CodeGenerator {
|
||||
* <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 @@ public class CodeGenerator {
|
||||
* <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 @@ public class CodeGenerator {
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -192,7 +192,10 @@ public abstract class AbstractCFMetaDataFactory
|
||||
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 @@ public abstract class AbstractCFMetaDataFactory
|
||||
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);
|
||||
@ -543,6 +549,11 @@ public abstract class AbstractCFMetaDataFactory
|
||||
*/
|
||||
protected abstract Serializer newSerializer();
|
||||
|
||||
/**
|
||||
* Create a new annotation metadata serializer.
|
||||
*/
|
||||
protected abstract Serializer newAnnotationSerializer();
|
||||
|
||||
/**
|
||||
* Return the metadata that defines the given query, if any.
|
||||
*
|
||||
|
@ -32,4 +32,5 @@ public interface MetaDataModes {
|
||||
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;
|
||||
}
|
||||
|
@ -308,6 +308,22 @@ public final class CodeFormat implements Cloneable {
|
||||
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.
|
||||
|
@ -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 ());
|
||||
}
|
||||
}
|
||||
}
|
@ -21,10 +21,11 @@ package org.apache.openjpa.persistence.jdbc;
|
||||
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.
|
||||
@ -48,6 +49,15 @@ public class PersistenceMappingFactory
|
||||
return parser;
|
||||
}
|
||||
|
||||
protected AnnotationPersistenceMetaDataSerializer newAnnotationSerializer()
|
||||
{
|
||||
AnnotationPersistenceMappingSerializer ser =
|
||||
new AnnotationPersistenceMappingSerializer((JDBCConfiguration)
|
||||
repos.getConfiguration());
|
||||
ser.setSyncMappingInfo(true);
|
||||
return ser;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected XMLPersistenceMetaDataParser newXMLParser(boolean loading) {
|
||||
XMLPersistenceMappingParser parser = new XMLPersistenceMappingParser
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -125,6 +125,15 @@ public class PersistenceMetaDataFactory
|
||||
(repos.getConfiguration());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new annotation serializer.
|
||||
*/
|
||||
protected AnnotationPersistenceMetaDataSerializer
|
||||
newAnnotationSerializer() {
|
||||
return new AnnotationPersistenceMetaDataSerializer
|
||||
(repos.getConfiguration());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return XML metadata parser, creating it if it does not already exist.
|
||||
*/
|
||||
|
@ -539,6 +539,26 @@ directory. Defaults to the current directory.
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<literal>-metadata/-md <class | package | none></literal>: Specify the
|
||||
level the metadata should be generated at. Defaults to generating a single
|
||||
package-level metadata file. Set to <literal>none</literal> to disable orm.xml
|
||||
generation.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<literal>-annotations/-ann <true/t | false/f></literal>: Set to true to
|
||||
generate JPA annotations in generated java classes.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<literal>-accessType/-access <field | property></literal>: Change access
|
||||
type for generated annotations. Defaults to field access.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<literal>-useSchemaName/-sn <true/t | false/f></literal>: Set this flag
|
||||
to <literal>true</literal> to include the schema as well as table name in the
|
||||
name of each generated class. This can be useful when dealing with multiple
|
||||
@ -588,6 +608,13 @@ for every many-1/1-1 relation detected.
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<literal>-useGenericCollections/-gc <true/t | false/f></literal>: Set to
|
||||
true to use generic collections on OneToMany and ManyToMany relations (requires
|
||||
JDK 1.5 or higher).
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<literal>-useDatastoreIdentity/-ds <true/t | false/f></literal>: Set to
|
||||
<literal>true</literal> to use datastore identity for tables that have single
|
||||
numeric primary key columns. The tool typically uses application identity for
|
||||
@ -672,8 +699,9 @@ property in the specified reverse customizer, and set to the given value.
|
||||
<para>
|
||||
Running the tool will generate <filename>.java</filename> files for each
|
||||
generated class (and its application identity class, if applicable), along with
|
||||
an <filename>orm.xml</filename> file containing the corresponding persistence
|
||||
metadata.
|
||||
JPA annotations (if enabled by setting <literal>-annotations true</literal>),
|
||||
or an <filename>orm.xml</filename> file (if not disabled with <literal>
|
||||
-metadata none</literal>) containing the corresponding persistence metadata.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
@ -688,9 +716,9 @@ After you are satisfied with the generated classes and their mappings, you
|
||||
should first compile the classes with <literal>javac</literal>, <literal>
|
||||
jikes</literal>, or your favorite Java compiler. Make sure the classes are
|
||||
located in the directory corresponding to the <literal>-package</literal> flag
|
||||
you gave the reverse mapping tool. Next, move the generated <filename>
|
||||
orm.xml</filename> file to a <filename>META-INF</filename> directory within a
|
||||
directory in your classpath. Finally, enhance the classes
|
||||
you gave the reverse mapping tool. Next, if you have generated an <filename>
|
||||
orm.xml</filename>, move that file to a <filename>META-INF</filename> directory
|
||||
within a directory in your classpath. Finally, enhance the classes
|
||||
if necessary (see <xref linkend="ref_guide_pc_enhance"/> ).
|
||||
</para>
|
||||
</listitem>
|
||||
|
Loading…
x
Reference in New Issue
Block a user