0001: /*
0002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
0003: *
0004: * This file is part of Resin(R) Open Source
0005: *
0006: * Each copy or derived work must preserve the copyright notice and this
0007: * notice unmodified.
0008: *
0009: * Resin Open Source is free software; you can redistribute it and/or modify
0010: * it under the terms of the GNU General Public License as published by
0011: * the Free Software Foundation; either version 2 of the License, or
0012: * (at your option) any later version.
0013: *
0014: * Resin Open Source is distributed in the hope that it will be useful,
0015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
0016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
0017: * of NON-INFRINGEMENT. See the GNU General Public License for more
0018: * details.
0019: *
0020: * You should have received a copy of the GNU General Public License
0021: * along with Resin Open Source; if not, write to the
0022: *
0023: * Free Software Foundation, Inc.
0024: * 59 Temple Place, Suite 330
0025: * Boston, MA 02111-1307 USA
0026: *
0027: * @author Rodrigo Westrupp
0028: */
0029:
0030: package com.caucho.amber.cfg;
0031:
0032: import com.caucho.amber.entity.Listener;
0033:
0034: import com.caucho.amber.field.*;
0035: import com.caucho.amber.idgen.IdGenerator;
0036: import com.caucho.amber.manager.AmberPersistenceUnit;
0037: import com.caucho.amber.table.Column;
0038: import com.caucho.amber.table.ForeignColumn;
0039: import com.caucho.amber.table.LinkColumns;
0040: import com.caucho.amber.table.Table;
0041: import com.caucho.amber.type.*;
0042: import com.caucho.bytecode.*;
0043: import com.caucho.config.ConfigException;
0044: import com.caucho.jdbc.JdbcMetaData;
0045: import com.caucho.util.L10N;
0046:
0047: import javax.persistence.*;
0048: import javax.persistence.EmbeddedId;
0049: import java.sql.SQLException;
0050: import java.util.ArrayList;
0051: import java.util.HashMap;
0052: import java.util.logging.Level;
0053: import java.util.logging.Logger;
0054:
0055: /**
0056: * Base concrete introspector for orm.xml and annotations.
0057: */
0058: public class BaseConfigIntrospector extends AbstractConfigIntrospector {
0059: private static final Logger log = Logger
0060: .getLogger(BaseConfigIntrospector.class.getName());
0061: private static final L10N L = new L10N(BaseConfigIntrospector.class);
0062:
0063: AmberPersistenceUnit _persistenceUnit;
0064:
0065: ArrayList<Completion> _linkCompletions = new ArrayList<Completion>();
0066: ArrayList<Completion> _depCompletions = new ArrayList<Completion>();
0067:
0068: HashMap<RelatedType, ArrayList<OneToOneCompletion>> _oneToOneCompletions = new HashMap<RelatedType, ArrayList<OneToOneCompletion>>();
0069:
0070: HashMap<String, EmbeddableConfig> _embeddableConfigMap = new HashMap<String, EmbeddableConfig>();
0071:
0072: ArrayList<EntityMappingsConfig> _entityMappingsList;
0073:
0074: // HashMap<String, EntityConfig> _entityConfigMap
0075: // = new HashMap<String, EntityConfig>();
0076: //
0077: // HashMap<String, MappedSuperclassConfig> _mappedSuperclassConfigMap
0078: // = new HashMap<String, MappedSuperclassConfig>();
0079:
0080: /**
0081: * Creates the introspector.
0082: */
0083: public BaseConfigIntrospector() {
0084: }
0085:
0086: /**
0087: * Creates the introspector.
0088: */
0089: public BaseConfigIntrospector(AmberPersistenceUnit persistenceUnit) {
0090: _persistenceUnit = persistenceUnit;
0091: }
0092:
0093: /**
0094: * Sets the entity mappings list.
0095: */
0096: public void setEntityMappingsList(
0097: ArrayList<EntityMappingsConfig> entityMappingsList) {
0098: _entityMappingsList = entityMappingsList;
0099: }
0100:
0101: /**
0102: * Returns the entity config for a class name.
0103: */
0104: public EntityConfig getEntityConfig(String className) {
0105: // jpa/0r41
0106: if (_entityMappingsList == null)
0107: return null;
0108:
0109: // jpa/0s2l: mapping-file.
0110:
0111: HashMap<String, EntityConfig> entityMap;
0112: EntityConfig entityConfig;
0113:
0114: for (EntityMappingsConfig entityMappings : _entityMappingsList) {
0115: entityMap = entityMappings.getEntityMap();
0116:
0117: if (entityMap != null) {
0118: entityConfig = entityMap.get(className);
0119:
0120: if (entityConfig != null)
0121: return entityConfig;
0122: }
0123: }
0124:
0125: return null;
0126: }
0127:
0128: /**
0129: * Returns the mapped superclass config for a class name.
0130: */
0131: public MappedSuperclassConfig getMappedSuperclassConfig(
0132: String className) {
0133: if (_entityMappingsList == null)
0134: return null;
0135:
0136: HashMap<String, MappedSuperclassConfig> super classMap;
0137: MappedSuperclassConfig super classConfig;
0138:
0139: for (EntityMappingsConfig entityMappings : _entityMappingsList) {
0140: super classMap = entityMappings.getMappedSuperclassMap();
0141:
0142: if (super classMap != null) {
0143: super classConfig = super classMap.get(className);
0144:
0145: if (super classConfig != null)
0146: return super classConfig;
0147: }
0148: }
0149:
0150: return null;
0151: }
0152:
0153: /**
0154: * Initializes the persistence unit meta data:
0155: * default listeners and so on.
0156: */
0157: public void initMetaData(
0158: ArrayList<EntityMappingsConfig> entityMappingsList,
0159: AmberPersistenceUnit persistenceUnit)
0160: throws ConfigException {
0161: PersistenceUnitMetaDataConfig metaData = null;
0162:
0163: for (EntityMappingsConfig entityMappings : entityMappingsList) {
0164: metaData = entityMappings.getPersistenceUnitMetaData();
0165:
0166: // It is undefined if this element occurs in multiple mapping
0167: // files within the same persistence unit.
0168: if (metaData != null)
0169: break;
0170: }
0171:
0172: if (metaData == null)
0173: return;
0174:
0175: PersistenceUnitDefaultsConfig defaults;
0176:
0177: defaults = metaData.getPersistenceUnitDefaults();
0178:
0179: if (defaults == null)
0180: return;
0181:
0182: EntityListenersConfig entityListeners;
0183: entityListeners = defaults.getEntityListeners();
0184:
0185: if (entityListeners == null)
0186: return;
0187:
0188: ArrayList<EntityListenerConfig> listeners;
0189: listeners = entityListeners.getEntityListeners();
0190:
0191: for (EntityListenerConfig listener : listeners)
0192: introspectDefaultListener(listener, persistenceUnit);
0193: }
0194:
0195: public void introspectDefaultListener(
0196: EntityListenerConfig listener,
0197: AmberPersistenceUnit persistenceUnit)
0198: throws ConfigException {
0199: JClassLoader loader = persistenceUnit.getJClassLoader();
0200:
0201: String className = listener.getClassName();
0202:
0203: JClass type = loader.forName(className);
0204:
0205: if (type == null)
0206: throw new ConfigException(
0207: L
0208: .l(
0209: "'{0}' is an unknown type for <entity-listener> in orm.xml",
0210: className));
0211:
0212: ListenerType listenerType = persistenceUnit
0213: .addDefaultListener(type);
0214:
0215: introspectListener(type, listenerType);
0216: }
0217:
0218: public void introspectEntityListeners(JClass type,
0219: RelatedType relatedType,
0220: AmberPersistenceUnit persistenceUnit)
0221: throws ConfigException {
0222: getInternalEntityListenersConfig(type, _annotationCfg);
0223: JAnnotation entityListenersAnn = _annotationCfg.getAnnotation();
0224: EntityListenersConfig entityListenersCfg = _annotationCfg
0225: .getEntityListenersConfig();
0226:
0227: Object listeners[] = null;
0228:
0229: // XML mapping takes higher priority than annotations.
0230: if (entityListenersCfg != null)
0231: listeners = entityListenersCfg.getEntityListeners()
0232: .toArray();
0233: else if (entityListenersAnn != null)
0234: listeners = (Object[]) entityListenersAnn.get("value");
0235: else
0236: return;
0237:
0238: String relatedTypeName = relatedType.getBeanClass().getName();
0239:
0240: for (int i = 0; i < listeners.length; i++) {
0241:
0242: JClass cl;
0243:
0244: // Introspects annotation or xml.
0245: if (listeners[i] instanceof JClass)
0246: cl = (JClass) listeners[i];
0247: else {
0248: JClassLoader loader = persistenceUnit.getJClassLoader();
0249:
0250: EntityListenerConfig listenerConfig = (EntityListenerConfig) listeners[i];
0251:
0252: String className = listenerConfig.getClassName();
0253:
0254: cl = loader.forName(className);
0255:
0256: if (cl == null)
0257: throw new ConfigException(
0258: L
0259: .l(
0260: "'{0}' is an unknown type for <entity-listener> in orm.xml",
0261: className));
0262: }
0263:
0264: if (persistenceUnit.getDefaultListener(cl.getName()) != null)
0265: continue;
0266:
0267: introspectEntityListener(cl, persistenceUnit, relatedType,
0268: relatedTypeName);
0269: }
0270: }
0271:
0272: public void introspectEntityListener(JClass type,
0273: AmberPersistenceUnit persistenceUnit,
0274: RelatedType sourceType, String sourceClassName)
0275: throws ConfigException {
0276: if (type == null) {
0277: throw new ConfigException(
0278: L
0279: .l(
0280: "'{0}' is an unknown type for @EntityListeners annotated at class '{1}'",
0281: type.getName(), sourceClassName));
0282: }
0283:
0284: JClass parentClass = type.getSuperClass();
0285:
0286: if (parentClass == null) {
0287: // java.lang.Object
0288: return;
0289: }
0290: /*
0291: else {
0292: // XXX: entity listener super-classes in a hierarchy might
0293: // not be annotated as entity listeners but they might have
0294: // @PreXxx or @PostXxx annotated methods. On the other hand,
0295: // needs to filter regular classes out.
0296:
0297: introspectEntityListener(parentClass, persistenceUnit,
0298: sourceType, sourceClassName);
0299: }
0300: */
0301:
0302: // jpa/0r42
0303: ListenerType listenerType = persistenceUnit
0304: .getEntityListener(type.getName());
0305:
0306: ListenerType newListenerType = persistenceUnit
0307: .addEntityListener(sourceClassName, type);
0308:
0309: if (listenerType == null) {
0310: listenerType = newListenerType;
0311: introspectListener(type, listenerType);
0312: }
0313:
0314: sourceType.addListener(listenerType);
0315: }
0316:
0317: public void introspectListener(JClass type,
0318: ListenerType listenerType) throws ConfigException {
0319: listenerType.setInstanceClassName(listenerType.getName()
0320: + "__ResinExt");
0321:
0322: for (JMethod method : type.getMethods()) {
0323: introspectCallbacks(listenerType, method);
0324: }
0325: }
0326:
0327: /**
0328: * Introspects the callbacks.
0329: */
0330: public void introspectCallbacks(JClass type, RelatedType entityType)
0331: throws ConfigException {
0332: getInternalExcludeDefaultListenersConfig(type, _annotationCfg);
0333:
0334: if (!_annotationCfg.isNull())
0335: entityType.setExcludeDefaultListeners(true);
0336:
0337: getInternalExcludeSuperclassListenersConfig(type,
0338: _annotationCfg);
0339:
0340: if (!_annotationCfg.isNull())
0341: entityType.setExcludeSuperclassListeners(true);
0342:
0343: for (JMethod method : type.getMethods()) {
0344: introspectCallbacks(entityType, method);
0345: }
0346: }
0347:
0348: /**
0349: * Introspects the callbacks.
0350: */
0351: public void introspectCallbacks(AbstractEnhancedType type,
0352: JMethod method) throws ConfigException {
0353: JClass[] param = method.getParameterTypes();
0354:
0355: String methodName = method.getName();
0356: JClass jClass = type.getBeanClass();
0357:
0358: boolean isListener = type instanceof ListenerType;
0359:
0360: int n = ListenerType.CALLBACK_CLASS.length;
0361:
0362: for (int i = 1; i < n; i++) {
0363: getInternalCallbackConfig(i, jClass, method, methodName,
0364: _annotationCfg);
0365:
0366: if (!_annotationCfg.isNull()) {
0367: validateCallback(ListenerType.CALLBACK_CLASS[i]
0368: .getName(), method, isListener);
0369:
0370: type.addCallback(i, method);
0371: }
0372: }
0373: }
0374:
0375: /**
0376: * Introspects named queries.
0377: */
0378: void introspectNamedQueries(JClass type, String typeName) {
0379: // jpa/0y0-
0380:
0381: getInternalNamedQueryConfig(type, _annotationCfg);
0382: JAnnotation namedQueryAnn = _annotationCfg.getAnnotation();
0383: NamedQueryConfig namedQueryConfig = _annotationCfg
0384: .getNamedQueryConfig();
0385:
0386: // getInternalNamedQueriesConfig(type);
0387: JAnnotation namedQueriesAnn = type
0388: .getAnnotation(NamedQueries.class);
0389: // NamedQueriesConfig namedQueriesConfig = _annotationCfg.getNamedQueriesConfig();
0390:
0391: if ((namedQueryAnn == null) && (namedQueriesAnn == null))
0392: return;
0393:
0394: Object namedQueryArray[];
0395:
0396: if ((namedQueryAnn != null) && (namedQueriesAnn != null)) {
0397: throw new ConfigException(
0398: L
0399: .l(
0400: "{0} may not have both @NamedQuery and @NamedQueries",
0401: typeName));
0402: } else if (namedQueriesAnn != null) {
0403: namedQueryArray = (Object[]) namedQueriesAnn.get("value");
0404: } else {
0405: namedQueryArray = new Object[] { namedQueryAnn };
0406: }
0407:
0408: for (int i = 0; i < namedQueryArray.length; i++) {
0409: namedQueryAnn = (JAnnotation) namedQueryArray[i];
0410: _persistenceUnit.addNamedQuery(namedQueryAnn
0411: .getString("name"), namedQueryAnn
0412: .getString("query"));
0413: }
0414: }
0415:
0416: /**
0417: * Introspects named native queries.
0418: */
0419: void introspectNamedNativeQueries(JClass type, String typeName) {
0420: // jpa/0y2-
0421:
0422: getInternalNamedNativeQueryConfig(type, _annotationCfg);
0423: JAnnotation namedNativeQueryAnn = _annotationCfg
0424: .getAnnotation();
0425: NamedNativeQueryConfig namedNativeQueryConfig = _annotationCfg
0426: .getNamedNativeQueryConfig();
0427:
0428: JAnnotation namedNativeQueriesAnn = type
0429: .getAnnotation(NamedNativeQueries.class);
0430:
0431: if ((namedNativeQueryAnn == null)
0432: && (namedNativeQueriesAnn == null))
0433: return;
0434:
0435: Object namedNativeQueryArray[];
0436:
0437: if ((namedNativeQueryAnn != null)
0438: && (namedNativeQueriesAnn != null)) {
0439: throw new ConfigException(
0440: L
0441: .l(
0442: "{0} may not have both @NamedNativeQuery and @NamedNativeQueries",
0443: typeName));
0444: } else if (namedNativeQueriesAnn != null) {
0445: namedNativeQueryArray = (Object[]) namedNativeQueriesAnn
0446: .get("value");
0447: } else {
0448: namedNativeQueryArray = new Object[] { namedNativeQueryAnn };
0449: }
0450:
0451: for (int i = 0; i < namedNativeQueryArray.length; i++) {
0452: namedNativeQueryAnn = (JAnnotation) namedNativeQueryArray[i];
0453:
0454: NamedNativeQueryConfig nativeQueryConfig = new NamedNativeQueryConfig();
0455:
0456: nativeQueryConfig.setQuery(namedNativeQueryAnn
0457: .getString("query"));
0458: nativeQueryConfig.setResultClass(namedNativeQueryAnn
0459: .getClass("resultClass").getName());
0460: nativeQueryConfig.setResultSetMapping(namedNativeQueryAnn
0461: .getString("resultSetMapping"));
0462:
0463: _persistenceUnit.addNamedNativeQuery(namedNativeQueryAnn
0464: .getString("name"), nativeQueryConfig);
0465: }
0466: }
0467:
0468: /**
0469: * Introspects sql result set mappings.
0470: */
0471: void introspectSqlResultSetMappings(JClass type,
0472: RelatedType relatedType, String typeName) {
0473: // jpa/0y1-
0474:
0475: getInternalSqlResultSetMappingConfig(type, _annotationCfg);
0476: JAnnotation sqlResultSetMappingAnn = _annotationCfg
0477: .getAnnotation();
0478: SqlResultSetMappingConfig sqlResultSetMappingConfig = _annotationCfg
0479: .getSqlResultSetMappingConfig();
0480:
0481: JAnnotation sqlResultSetMappingsAnn = type
0482: .getAnnotation(SqlResultSetMappings.class);
0483:
0484: if ((sqlResultSetMappingAnn == null)
0485: && (sqlResultSetMappingsAnn == null))
0486: return;
0487:
0488: Object sqlResultSetMappingArray[];
0489:
0490: if ((sqlResultSetMappingAnn != null)
0491: && (sqlResultSetMappingsAnn != null)) {
0492: throw new ConfigException(
0493: L
0494: .l(
0495: "{0} may not have both @SqlResultSetMapping and @SqlResultSetMappings",
0496: typeName));
0497: } else if (sqlResultSetMappingsAnn != null) {
0498: sqlResultSetMappingArray = (Object[]) sqlResultSetMappingsAnn
0499: .get("value");
0500: } else {
0501: sqlResultSetMappingArray = new Object[] { sqlResultSetMappingAnn };
0502: }
0503:
0504: if (sqlResultSetMappingConfig != null) {
0505: _persistenceUnit.addSqlResultSetMapping(
0506: sqlResultSetMappingConfig.getName(),
0507: sqlResultSetMappingConfig);
0508: return;
0509: }
0510:
0511: for (int i = 0; i < sqlResultSetMappingArray.length; i++) {
0512: sqlResultSetMappingAnn = (JAnnotation) sqlResultSetMappingArray[i];
0513:
0514: String name = sqlResultSetMappingAnn.getString("name");
0515: Object entities[] = (Object[]) sqlResultSetMappingAnn
0516: .get("entities");
0517: Object columns[] = (Object[]) sqlResultSetMappingAnn
0518: .get("columns");
0519:
0520: SqlResultSetMappingCompletion completion = new SqlResultSetMappingCompletion(
0521: relatedType, name, entities, columns);
0522:
0523: _depCompletions.add(completion);
0524: }
0525: }
0526:
0527: /**
0528: * Completion callback for sql result set mappings.
0529: */
0530: void addSqlResultSetMapping(String resultSetName,
0531: Object entities[], Object columns[]) throws ConfigException {
0532: // jpa/0y1-
0533:
0534: SqlResultSetMappingConfig sqlResultSetMapping = new SqlResultSetMappingConfig();
0535:
0536: // Adds @EntityResult.
0537: for (int i = 0; i < entities.length; i++) {
0538: JAnnotation entityResult = (JAnnotation) entities[i];
0539:
0540: String className = entityResult.getClass("entityClass")
0541: .getName();
0542:
0543: EntityType resultType = _persistenceUnit
0544: .getEntityType(className);
0545:
0546: if (resultType == null)
0547: throw new ConfigException(
0548: L
0549: .l(
0550: "entityClass '{0}' is not an @Entity bean for @SqlResultSetMapping '{1}'. The entityClass of an @EntityResult must be an @Entity bean.",
0551: className, resultSetName));
0552:
0553: EntityResultConfig entityResultConfig = new EntityResultConfig();
0554:
0555: entityResultConfig.setEntityClass(className);
0556:
0557: // @FieldResult annotations.
0558: Object fields[] = (Object[]) entityResult.get("fields");
0559:
0560: for (int j = 0; j < fields.length; j++) {
0561: JAnnotation fieldResult = (JAnnotation) fields[j];
0562:
0563: String fieldName = fieldResult.getString("name");
0564:
0565: AmberField field = resultType.getField(fieldName);
0566:
0567: if (field == null)
0568: throw new ConfigException(
0569: L
0570: .l(
0571: "@FieldResult with field name '{0}' is not a field for @EntityResult bean '{1}' in @SqlResultSetMapping '{2}'",
0572: fieldName, className,
0573: resultSetName));
0574:
0575: String columnName = fieldResult.getString("column");
0576:
0577: if (columnName == null || columnName.length() == 0)
0578: throw new ConfigException(
0579: L
0580: .l(
0581: "@FieldResult must have a column name defined and it must not be empty for '{0}' in @EntityResult '{1}' @SqlResultSetMapping '{2}'",
0582: fieldName, className,
0583: resultSetName));
0584:
0585: FieldResultConfig fieldResultConfig = new FieldResultConfig();
0586:
0587: fieldResultConfig.setName(fieldName);
0588: fieldResultConfig.setColumn(columnName);
0589:
0590: entityResultConfig.addFieldResult(fieldResultConfig);
0591: }
0592:
0593: sqlResultSetMapping.addEntityResult(entityResultConfig);
0594: }
0595:
0596: // Adds @ColumnResult.
0597: for (int i = 0; i < columns.length; i++) {
0598: JAnnotation columnResult = (JAnnotation) columns[i];
0599:
0600: String columnName = columnResult.getString("name");
0601:
0602: if (columnName == null || columnName.length() == 0)
0603: throw new ConfigException(
0604: L
0605: .l(
0606: "@ColumnResult must have a column name defined and it must not be empty in @SqlResultSetMapping '{0}'",
0607: resultSetName));
0608:
0609: ColumnResultConfig columnResultConfig = new ColumnResultConfig();
0610:
0611: columnResultConfig.setName(columnName);
0612:
0613: sqlResultSetMapping.addColumnResult(columnResultConfig);
0614: }
0615:
0616: // Adds a global sql result set mapping to the persistence unit.
0617: _persistenceUnit.addSqlResultSetMapping(resultSetName,
0618: sqlResultSetMapping);
0619: }
0620:
0621: /**
0622: * Completes all partial bean introspection.
0623: */
0624: public void configure() throws ConfigException {
0625: RuntimeException exn = null;
0626:
0627: while (_depCompletions.size() > 0
0628: || _linkCompletions.size() > 0) {
0629: while (_linkCompletions.size() > 0) {
0630: Completion completion = _linkCompletions.remove(0);
0631:
0632: try {
0633: completion.complete();
0634: } catch (Exception e) {
0635: if (e instanceof ConfigException) {
0636: log.warning(e.getMessage());
0637: log.log(Level.FINEST, e.toString(), e);
0638: } else
0639: log.log(Level.WARNING, e.toString(), e);
0640:
0641: completion.getRelatedType().setConfigException(e);
0642:
0643: if (exn == null)
0644: exn = ConfigException.create(e);
0645: }
0646: }
0647:
0648: if (_depCompletions.size() > 0) {
0649: Completion completion = _depCompletions.remove(0);
0650:
0651: try {
0652: completion.complete();
0653: } catch (Exception e) {
0654: if (e instanceof ConfigException) {
0655: log.warning(e.getMessage());
0656: log.log(Level.FINEST, e.toString(), e);
0657: } else
0658: log.log(Level.WARNING, e.toString(), e);
0659:
0660: completion.getRelatedType().setConfigException(e);
0661:
0662: if (exn == null)
0663: exn = ConfigException.create(e);
0664: }
0665: }
0666: }
0667:
0668: if (exn != null)
0669: throw exn;
0670: }
0671:
0672: /**
0673: * Introspects the Inheritance
0674: */
0675: void introspectInheritance(AmberPersistenceUnit persistenceUnit,
0676: RelatedType entityType, JClass type,
0677: JAnnotation inheritanceAnn,
0678: InheritanceConfig inheritanceConfig)
0679: throws ConfigException, SQLException {
0680: InheritanceType strategy;
0681:
0682: if (inheritanceAnn != null)
0683: strategy = (InheritanceType) inheritanceAnn.get("strategy");
0684: else
0685: strategy = inheritanceConfig.getStrategy();
0686:
0687: JAnnotation discValueAnn = type
0688: .getAnnotation(DiscriminatorValue.class);
0689:
0690: String discriminatorValue = null;
0691:
0692: if (discValueAnn != null)
0693: discriminatorValue = discValueAnn.getString("value");
0694:
0695: if (discriminatorValue == null || discriminatorValue.equals("")) {
0696: String name = entityType.getBeanClass().getName();
0697: int p = name.lastIndexOf('.');
0698: if (p > 0)
0699: name = name.substring(p + 1);
0700:
0701: discriminatorValue = name;
0702: }
0703:
0704: entityType.setDiscriminatorValue(discriminatorValue);
0705:
0706: if (entityType instanceof SubEntityType) {
0707: SubEntityType subType = (SubEntityType) entityType;
0708:
0709: subType.getParentType().addSubClass(subType);
0710:
0711: getInternalPrimaryKeyJoinColumnConfig(type, _annotationCfg);
0712: JAnnotation joinAnn = _annotationCfg.getAnnotation();
0713: PrimaryKeyJoinColumnConfig primaryKeyJoinColumnConfig = _annotationCfg
0714: .getPrimaryKeyJoinColumnConfig();
0715:
0716: // if (subType.isJoinedSubClass()) {
0717: if (strategy == InheritanceType.JOINED) {
0718: linkInheritanceTable(subType.getRootType().getTable(),
0719: subType.getTable(), joinAnn,
0720: primaryKeyJoinColumnConfig);
0721:
0722: subType
0723: .setId(new SubId(subType, subType.getRootType()));
0724: }
0725:
0726: return;
0727: }
0728:
0729: switch (strategy) {
0730: case JOINED:
0731: entityType.setJoinedSubClass(true);
0732: break;
0733: }
0734:
0735: getInternalDiscriminatorColumnConfig(type, _annotationCfg);
0736: JAnnotation discriminatorAnn = _annotationCfg.getAnnotation();
0737: DiscriminatorColumnConfig discriminatorConfig = _annotationCfg
0738: .getDiscriminatorColumnConfig();
0739:
0740: String columnName = null;
0741:
0742: if (discriminatorAnn != null)
0743: columnName = discriminatorAnn.getString("name");
0744:
0745: if (columnName == null || columnName.equals(""))
0746: columnName = "DTYPE";
0747:
0748: Type columnType = null;
0749: DiscriminatorType discType = DiscriminatorType.STRING;
0750:
0751: if (discriminatorAnn != null)
0752: discType = (DiscriminatorType) discriminatorAnn
0753: .get("discriminatorType");
0754:
0755: switch (discType) {
0756: case STRING:
0757: columnType = StringType.create();
0758: break;
0759: case CHAR:
0760: columnType = PrimitiveCharType.create();
0761: break;
0762: case INTEGER:
0763: columnType = PrimitiveIntType.create();
0764: break;
0765: default:
0766: throw new IllegalStateException();
0767: }
0768:
0769: Table table = entityType.getTable();
0770:
0771: // jpa/0gg0
0772: if (table == null)
0773: return;
0774:
0775: Column column = table.createColumn(columnName, columnType);
0776:
0777: if (discriminatorAnn != null) {
0778: column.setNotNull(!discriminatorAnn.getBoolean("nullable"));
0779:
0780: column.setLength(discriminatorAnn.getInt("length"));
0781:
0782: if (!"".equals(discriminatorAnn.get("columnDefinition")))
0783: column.setSQLType(discriminatorAnn
0784: .getString("columnDefinition"));
0785: } else {
0786: column.setNotNull(true);
0787: column.setLength(10);
0788: }
0789:
0790: entityType.setDiscriminator(column);
0791: }
0792:
0793: /**
0794: * Introspects the fields.
0795: */
0796: void introspectIdMethod(AmberPersistenceUnit persistenceUnit,
0797: RelatedType entityType, RelatedType parentType,
0798: JClass type, JClass idClass, MappedSuperclassConfig config)
0799: throws ConfigException, SQLException {
0800: ArrayList<IdField> keys = new ArrayList<IdField>();
0801:
0802: IdField idField = null;
0803:
0804: AttributesConfig attributesConfig = null;
0805:
0806: if (config != null)
0807: attributesConfig = config.getAttributes();
0808:
0809: for (JMethod method : type.getMethods()) {
0810: String methodName = method.getName();
0811: JClass[] paramTypes = method.getParameterTypes();
0812:
0813: if (method.getDeclaringClass().getName().equals(
0814: "java.lang.Object"))
0815: continue;
0816:
0817: if (!methodName.startsWith("get") || paramTypes.length != 0) {
0818: continue;
0819: }
0820:
0821: String fieldName = toFieldName(methodName.substring(3));
0822:
0823: if (containsFieldOrCompletion(parentType, fieldName))
0824: continue;
0825:
0826: getInternalIdConfig(type, method, fieldName, _annotationCfg);
0827: JAnnotation id = _annotationCfg.getAnnotation();
0828: IdConfig idConfig = _annotationCfg.getIdConfig();
0829:
0830: if (!_annotationCfg.isNull()) {
0831: idField = introspectId(persistenceUnit, entityType,
0832: method, fieldName, method.getReturnType(),
0833: idConfig);
0834:
0835: if (idField != null)
0836: keys.add(idField);
0837: } else {
0838: getInternalEmbeddedIdConfig(type, method, fieldName,
0839: _annotationCfg);
0840: JAnnotation embeddedId = _annotationCfg.getAnnotation();
0841: EmbeddedIdConfig embeddedIdConfig = _annotationCfg
0842: .getEmbeddedIdConfig();
0843:
0844: if (!_annotationCfg.isNull()) {
0845: idField = introspectEmbeddedId(persistenceUnit,
0846: entityType, method, fieldName, method
0847: .getReturnType());
0848: break;
0849: } else {
0850: continue;
0851: }
0852: }
0853: }
0854:
0855: if (keys.size() == 0) {
0856: if (idField != null) {
0857: // @EmbeddedId was used.
0858: com.caucho.amber.field.EmbeddedId id = new com.caucho.amber.field.EmbeddedId(
0859: entityType, (EmbeddedIdField) idField);
0860:
0861: entityType.setId(id);
0862: }
0863: } else if (keys.size() == 1) {
0864: entityType.setId(new com.caucho.amber.field.Id(entityType,
0865: keys));
0866: } else if (idClass == null) {
0867: throw new ConfigException(
0868: L
0869: .l(
0870: "{0} has multiple @Id methods, but no @IdClass. Compound primary keys require either an @IdClass or exactly one @EmbeddedId field or property.",
0871: entityType.getName()));
0872: } else {
0873: CompositeId id = new CompositeId(entityType, keys);
0874: id.setKeyClass(idClass);
0875:
0876: entityType.setId(id);
0877: }
0878: }
0879:
0880: /**
0881: * Introspects the fields.
0882: */
0883: void introspectIdField(AmberPersistenceUnit persistenceUnit,
0884: RelatedType entityType, RelatedType parentType,
0885: JClass type, JClass idClass, MappedSuperclassConfig config)
0886: throws ConfigException, SQLException {
0887: ArrayList<IdField> keys = new ArrayList<IdField>();
0888:
0889: AttributesConfig attributesConfig = null;
0890:
0891: if (config != null)
0892: attributesConfig = config.getAttributes();
0893:
0894: for (JField field : type.getFields()) {
0895: String fieldName = field.getName();
0896:
0897: if (containsFieldOrCompletion(parentType, fieldName))
0898: continue;
0899:
0900: getInternalIdConfig(type, field, fieldName, _annotationCfg);
0901: JAnnotation id = _annotationCfg.getAnnotation();
0902: IdConfig idConfig = _annotationCfg.getIdConfig();
0903:
0904: if (_annotationCfg.isNull()) {
0905: getInternalEmbeddedIdConfig(type, field, fieldName,
0906: _annotationCfg);
0907: JAnnotation embeddedId = _annotationCfg.getAnnotation();
0908: EmbeddedIdConfig embeddedIdConfig = _annotationCfg
0909: .getEmbeddedIdConfig();
0910:
0911: if (_annotationCfg.isNull())
0912: continue;
0913: }
0914:
0915: IdField idField = introspectId(persistenceUnit, entityType,
0916: field, fieldName, field.getType(), idConfig);
0917:
0918: if (idField != null)
0919: keys.add(idField);
0920: }
0921:
0922: if (keys.size() == 0) {
0923: } else if (keys.size() == 1)
0924: entityType.setId(new com.caucho.amber.field.Id(entityType,
0925: keys));
0926: else if (idClass == null) {
0927: throw new ConfigException(
0928: L
0929: .l(
0930: "{0} has multiple @Id fields, but no @IdClass. Compound primary keys require an @IdClass.",
0931: entityType.getName()));
0932: } else {
0933: CompositeId id = new CompositeId(entityType, keys);
0934: id.setKeyClass(idClass);
0935:
0936: entityType.setId(id);
0937: }
0938: }
0939:
0940: /**
0941: * Check if it's field
0942: */
0943: boolean isField(JClass type, AbstractEnhancedConfig typeConfig,
0944: boolean isEmbeddable) throws ConfigException {
0945: if (type == null)
0946: return false;
0947:
0948: if (typeConfig != null) {
0949: String access = typeConfig.getAccess();
0950:
0951: if (access != null)
0952: return access.equals("FIELD");
0953:
0954: JClass parentClass = type.getSuperClass();
0955:
0956: if (parentClass == null)
0957: return false;
0958: else {
0959: getInternalEntityConfig(parentClass, _annotationCfg);
0960: EntityConfig super EntityConfig = _annotationCfg
0961: .getEntityConfig();
0962:
0963: if (super EntityConfig == null)
0964: return false;
0965:
0966: return isField(parentClass, super EntityConfig, false);
0967: }
0968: }
0969:
0970: for (JField field : type.getDeclaredFields()) {
0971: JAnnotation id = field
0972: .getAnnotation(javax.persistence.Id.class);
0973:
0974: if (id != null)
0975: return true;
0976:
0977: id = field.getAnnotation(EmbeddedId.class);
0978:
0979: if (id != null)
0980: return true;
0981: }
0982:
0983: return isField(type.getSuperClass(), null, false);
0984: }
0985:
0986: private IdField introspectId(AmberPersistenceUnit persistenceUnit,
0987: RelatedType entityType, JAccessibleObject field,
0988: String fieldName, JClass fieldType, IdConfig idConfig)
0989: throws ConfigException, SQLException {
0990: JAnnotation id = field
0991: .getAnnotation(javax.persistence.Id.class);
0992: JAnnotation column = field
0993: .getAnnotation(javax.persistence.Column.class);
0994:
0995: ColumnConfig columnConfig = null;
0996: GeneratedValueConfig generatedValueConfig = null;
0997:
0998: if (idConfig != null) {
0999: columnConfig = idConfig.getColumn();
1000: generatedValueConfig = idConfig.getGeneratedValue();
1001: }
1002:
1003: JAnnotation gen = field.getAnnotation(GeneratedValue.class);
1004:
1005: Type amberType = persistenceUnit.createType(fieldType);
1006:
1007: KeyPropertyField idField;
1008:
1009: Column keyColumn = null;
1010:
1011: if (entityType.getTable() != null) {
1012: keyColumn = createColumn(entityType, field, fieldName,
1013: column, amberType, columnConfig);
1014:
1015: idField = new KeyPropertyField(entityType, fieldName,
1016: keyColumn);
1017: } else {
1018: idField = new KeyPropertyField(entityType, fieldName);
1019: return idField;
1020: }
1021:
1022: if (gen == null) {
1023: } else {
1024: JdbcMetaData metaData = null;
1025:
1026: try {
1027: metaData = persistenceUnit.getMetaData();
1028: } catch (ConfigException e) {
1029: throw e;
1030: } catch (Exception e) {
1031: throw new ConfigException(
1032: L
1033: .l("Unable to get meta data for database. Meta data is needed for generated values."),
1034: e);
1035: }
1036:
1037: if (GenerationType.IDENTITY.equals(gen.get("strategy"))) {
1038: if (!metaData.supportsIdentity())
1039: throw new ConfigException(L.l(
1040: "'{0}' does not support identity.",
1041: metaData.getDatabaseName()));
1042:
1043: keyColumn.setGeneratorType("identity");
1044: idField.setGenerator("identity");
1045: } else if (GenerationType.SEQUENCE.equals(gen
1046: .get("strategy"))) {
1047: if (!metaData.supportsSequences())
1048: throw new ConfigException(L.l(
1049: "'{0}' does not support sequence.",
1050: metaData.getDatabaseName()));
1051:
1052: addSequenceIdGenerator(persistenceUnit, idField, gen);
1053: } else if (GenerationType.TABLE.equals(gen.get("strategy"))) {
1054: addTableIdGenerator(persistenceUnit, idField, id);
1055: } else if (GenerationType.AUTO.equals(gen.get("strategy"))) {
1056: if (metaData.supportsIdentity()) {
1057: keyColumn.setGeneratorType("identity");
1058: idField.setGenerator("identity");
1059: } else if (metaData.supportsSequences()) {
1060: addSequenceIdGenerator(persistenceUnit, idField,
1061: gen);
1062: } else {
1063: addTableIdGenerator(persistenceUnit, idField, id);
1064: }
1065: }
1066: }
1067:
1068: return idField;
1069: }
1070:
1071: private IdField introspectEmbeddedId(
1072: AmberPersistenceUnit persistenceUnit,
1073: RelatedType ownerType, JAccessibleObject field,
1074: String fieldName, JClass fieldType) throws ConfigException,
1075: SQLException {
1076: IdField idField;
1077:
1078: EmbeddableType embeddableType = persistenceUnit
1079: .createEmbeddable(fieldType);
1080:
1081: idField = new EmbeddedIdField(ownerType, embeddableType,
1082: fieldName);
1083:
1084: return idField;
1085: }
1086:
1087: void addSequenceIdGenerator(AmberPersistenceUnit persistenceUnit,
1088: KeyPropertyField idField, JAnnotation genAnn)
1089: throws ConfigException {
1090: idField.setGenerator("sequence");
1091: idField.getColumn().setGeneratorType("sequence");
1092:
1093: String name = genAnn.getString("generator");
1094:
1095: if (name == null || "".equals(name))
1096: name = idField.getEntitySourceType().getTable().getName()
1097: + "_cseq";
1098:
1099: IdGenerator gen = persistenceUnit.createSequenceGenerator(name,
1100: 1);
1101:
1102: idField.getEntitySourceType().setGenerator(idField.getName(),
1103: gen);
1104: }
1105:
1106: void addTableIdGenerator(AmberPersistenceUnit persistenceUnit,
1107: KeyPropertyField idField, JAnnotation idAnn)
1108: throws ConfigException {
1109: idField.setGenerator("table");
1110: idField.getColumn().setGeneratorType("table");
1111:
1112: String name = idAnn.getString("generator");
1113: if (name == null || "".equals(name))
1114: name = "caucho";
1115:
1116: IdGenerator gen = persistenceUnit.getTableGenerator(name);
1117:
1118: if (gen == null) {
1119: String genName = "GEN_TABLE";
1120:
1121: GeneratorTableType genTable;
1122: genTable = persistenceUnit.createGeneratorTable(genName);
1123:
1124: gen = genTable.createGenerator(name);
1125:
1126: // jpa/0g60
1127: genTable.init();
1128:
1129: persistenceUnit.putTableGenerator(name, gen);
1130: }
1131:
1132: idField.getEntitySourceType().setGenerator(idField.getName(),
1133: gen);
1134: }
1135:
1136: /**
1137: * Links a secondary table.
1138: */
1139: void linkSecondaryTable(Table primaryTable, Table secondaryTable,
1140: JAnnotation[] joinColumnsAnn) throws ConfigException {
1141: ArrayList<ForeignColumn> linkColumns = new ArrayList<ForeignColumn>();
1142: for (Column column : primaryTable.getIdColumns()) {
1143: ForeignColumn linkColumn;
1144:
1145: JAnnotation joinAnn = getJoinColumn(joinColumnsAnn, column
1146: .getName());
1147: String name;
1148:
1149: if (joinAnn == null)
1150: name = column.getName();
1151: else
1152: name = joinAnn.getString("name");
1153:
1154: linkColumn = secondaryTable.createForeignColumn(name,
1155: column);
1156: linkColumn.setPrimaryKey(true);
1157:
1158: secondaryTable.addIdColumn(linkColumn);
1159:
1160: linkColumns.add(linkColumn);
1161: }
1162:
1163: LinkColumns link = new LinkColumns(secondaryTable,
1164: primaryTable, linkColumns);
1165:
1166: link.setSourceCascadeDelete(true);
1167:
1168: secondaryTable.setDependentIdLink(link);
1169: }
1170:
1171: /**
1172: * Links a secondary table.
1173: */
1174: void linkInheritanceTable(Table primaryTable, Table secondaryTable,
1175: JAnnotation joinAnn,
1176: PrimaryKeyJoinColumnConfig pkJoinColumnCfg)
1177: throws ConfigException {
1178: JAnnotation joinAnns[] = null;
1179:
1180: if (joinAnn != null)
1181: joinAnns = new JAnnotation[] { joinAnn };
1182:
1183: linkInheritanceTable(primaryTable, secondaryTable, joinAnns,
1184: pkJoinColumnCfg);
1185: }
1186:
1187: /**
1188: * Links a secondary table.
1189: */
1190: void linkInheritanceTable(Table primaryTable, Table secondaryTable,
1191: JAnnotation[] joinColumnsAnn,
1192: PrimaryKeyJoinColumnConfig pkJoinColumnCfg)
1193: throws ConfigException {
1194: ArrayList<ForeignColumn> linkColumns = new ArrayList<ForeignColumn>();
1195: for (Column column : primaryTable.getIdColumns()) {
1196: ForeignColumn linkColumn;
1197:
1198: String name;
1199:
1200: if (joinColumnsAnn == null) {
1201:
1202: if (pkJoinColumnCfg == null)
1203: name = column.getName();
1204: else
1205: name = pkJoinColumnCfg.getName();
1206: } else {
1207: JAnnotation join;
1208:
1209: join = getJoinColumn(joinColumnsAnn, column.getName());
1210:
1211: if (join == null)
1212: name = column.getName();
1213: else
1214: name = join.getString("name");
1215: }
1216:
1217: linkColumn = secondaryTable.createForeignColumn(name,
1218: column);
1219: linkColumn.setPrimaryKey(true);
1220:
1221: secondaryTable.addIdColumn(linkColumn);
1222:
1223: linkColumns.add(linkColumn);
1224: }
1225:
1226: LinkColumns link = new LinkColumns(secondaryTable,
1227: primaryTable, linkColumns);
1228:
1229: link.setSourceCascadeDelete(true);
1230:
1231: secondaryTable.setDependentIdLink(link);
1232:
1233: // jpa/0l48
1234: // link = new LinkColumns(primaryTable,
1235: // secondaryTable,
1236: // linkColumns);
1237: //
1238: // link.setSourceCascadeDelete(true);
1239: //
1240: // primaryTable.setDependentIdLink(link);
1241: }
1242:
1243: /**
1244: * Introspects the methods.
1245: */
1246: void introspectMethods(AmberPersistenceUnit persistenceUnit,
1247: AbstractStatefulType entityType,
1248: AbstractStatefulType parentType, JClass type,
1249: AbstractEnhancedConfig typeConfig) throws ConfigException {
1250: for (JMethod method : type.getMethods()) {
1251: String methodName = method.getName();
1252: JClass[] paramTypes = method.getParameterTypes();
1253:
1254: if (method.getDeclaringClass().getName().equals(
1255: "java.lang.Object"))
1256: continue;
1257:
1258: // jpa/0r38
1259: // Callbacks are introspected in the main introspect() block.
1260: // introspectCallbacks(entityType, method);
1261:
1262: String propName;
1263:
1264: if (paramTypes.length != 0) {
1265: validateNonGetter(method);
1266: continue;
1267: } else if (methodName.startsWith("get")) {
1268: propName = methodName.substring(3);
1269: } else if (methodName.startsWith("is")
1270: && (method.getReturnType().getName().equals(
1271: "boolean") || method.getReturnType()
1272: .getName().equals("java.lang.Boolean"))) {
1273: propName = methodName.substring(2);
1274: } else {
1275: validateNonGetter(method);
1276: continue;
1277: }
1278:
1279: getInternalVersionConfig(type, method, propName,
1280: _annotationCfg);
1281: JAnnotation versionAnn = _annotationCfg.getAnnotation();
1282: VersionConfig versionConfig = _annotationCfg
1283: .getVersionConfig();
1284:
1285: if (!_annotationCfg.isNull()) {
1286: validateNonGetter(method);
1287: } else {
1288:
1289: JMethod setter = type.getMethod("set" + propName,
1290: new JClass[] { method.getReturnType() });
1291: if (method.isPrivate() || (setter == null)
1292: || setter.isPrivate()) {
1293:
1294: JAnnotation ann = isAnnotatedMethod(method);
1295:
1296: if (ann == null) {
1297: if (setter != null)
1298: ann = isAnnotatedMethod(setter);
1299: } else if (ann.getType().equals(
1300: "javax.persistence.Transient"))
1301: continue;
1302:
1303: if (ann != null) {
1304: throw error(
1305: method,
1306: L
1307: .l(
1308: "'{0}' is not a valid annotation for {1}. Only public persistent property getters with matching setters may have property annotations.",
1309: ann.getType(), method
1310: .getFullName()));
1311: }
1312:
1313: continue;
1314: }
1315:
1316: // ejb/0g03 for private
1317: if (method.isStatic()) { // || ! method.isPublic()) {
1318: validateNonGetter(method);
1319: continue;
1320: }
1321: }
1322:
1323: String fieldName = toFieldName(propName);
1324:
1325: if (containsFieldOrCompletion(parentType, fieldName))
1326: continue;
1327:
1328: JClass fieldType = method.getReturnType();
1329:
1330: introspectField(persistenceUnit, entityType, method,
1331: fieldName, fieldType, typeConfig);
1332: }
1333: }
1334:
1335: /**
1336: * Introspects the fields.
1337: */
1338: void introspectFields(AmberPersistenceUnit persistenceUnit,
1339: AbstractStatefulType entityType,
1340: AbstractStatefulType parentType, JClass type,
1341: AbstractEnhancedConfig typeConfig, boolean isEmbeddable)
1342: throws ConfigException {
1343: if (!isEmbeddable && ((RelatedType) entityType).getId() == null)
1344: throw new IllegalStateException(L.l("{0} has no key",
1345: entityType));
1346:
1347: for (JField field : type.getFields()) {
1348: String fieldName = field.getName();
1349:
1350: if (containsFieldOrCompletion(parentType, fieldName)) {
1351: continue;
1352: }
1353:
1354: if (field.isStatic() || field.isTransient())
1355: continue;
1356:
1357: JClass fieldType = field.getType();
1358: introspectField(persistenceUnit, entityType, field,
1359: fieldName, fieldType, typeConfig);
1360: }
1361: }
1362:
1363: void introspectField(AmberPersistenceUnit persistenceUnit,
1364: AbstractStatefulType sourceType, JAccessibleObject field,
1365: String fieldName, JClass fieldType,
1366: AbstractEnhancedConfig typeConfig) throws ConfigException {
1367: EmbeddableConfig embeddableConfig = null;
1368: MappedSuperclassConfig mappedSuperOrEntityConfig = null;
1369:
1370: if (typeConfig instanceof EmbeddableConfig)
1371: embeddableConfig = (EmbeddableConfig) typeConfig;
1372: else if (typeConfig instanceof MappedSuperclassConfig)
1373: mappedSuperOrEntityConfig = (MappedSuperclassConfig) typeConfig;
1374:
1375: // jpa/0r37: interface fields must not be considered.
1376:
1377: JClass jClass = field.getDeclaringClass();
1378:
1379: if (jClass.isInterface())
1380: return;
1381:
1382: // jpa/0r37: fields declared in non-entity superclasses
1383: // must not be considered.
1384:
1385: AbstractStatefulType declaringType;
1386:
1387: declaringType = _persistenceUnit
1388: .getEntityType(jClass.getName());
1389:
1390: if (declaringType == null)
1391: declaringType = _persistenceUnit.getEmbeddable(jClass
1392: .getName());
1393:
1394: if (declaringType == null)
1395: declaringType = _persistenceUnit.getMappedSuperclass(jClass
1396: .getName());
1397:
1398: if (declaringType == null)
1399: return;
1400:
1401: AttributesConfig attributesConfig = null;
1402: IdConfig idConfig = null;
1403: BasicConfig basicConfig = null;
1404: OneToOneConfig oneToOneConfig = null;
1405: OneToManyConfig oneToManyConfig = null;
1406: ManyToOneConfig manyToOneConfig = null;
1407: ManyToManyConfig manyToManyConfig = null;
1408: VersionConfig versionConfig = null;
1409:
1410: if (mappedSuperOrEntityConfig != null) {
1411: attributesConfig = mappedSuperOrEntityConfig
1412: .getAttributes();
1413:
1414: if (attributesConfig != null) {
1415: idConfig = attributesConfig.getId(fieldName);
1416:
1417: basicConfig = attributesConfig.getBasic(fieldName);
1418:
1419: oneToOneConfig = attributesConfig
1420: .getOneToOne(fieldName);
1421:
1422: oneToManyConfig = attributesConfig
1423: .getOneToMany(fieldName);
1424:
1425: manyToOneConfig = attributesConfig
1426: .getManyToOne(fieldName);
1427:
1428: manyToManyConfig = attributesConfig
1429: .getManyToMany(fieldName);
1430:
1431: versionConfig = attributesConfig.getVersion(fieldName);
1432: }
1433: }
1434:
1435: if ((idConfig != null)
1436: || field
1437: .isAnnotationPresent(javax.persistence.Id.class)) {
1438: validateAnnotations(field, "@Id", _idAnnotations);
1439:
1440: if (!_idTypes.contains(fieldType.getName())) {
1441: throw error(field, L.l(
1442: "{0} is an invalid @Id type for {1}.",
1443: fieldType.getName(), field.getName()));
1444: }
1445: } else if ((basicConfig != null)
1446: || field
1447: .isAnnotationPresent(javax.persistence.Basic.class)) {
1448: validateAnnotations(field, "@Basic", _basicAnnotations);
1449:
1450: addBasic(sourceType, field, fieldName, fieldType,
1451: basicConfig);
1452: } else if ((versionConfig != null)
1453: || field
1454: .isAnnotationPresent(javax.persistence.Version.class)) {
1455: validateAnnotations(field, "@Version", _versionAnnotations);
1456:
1457: addVersion((RelatedType) sourceType, field, fieldName,
1458: fieldType, versionConfig);
1459: } else if ((manyToOneConfig != null)
1460: || field
1461: .isAnnotationPresent(javax.persistence.ManyToOne.class)) {
1462: validateAnnotations(field, "@ManyToOne",
1463: _manyToOneAnnotations);
1464:
1465: JAnnotation ann = field.getAnnotation(ManyToOne.class);
1466:
1467: JClass targetEntity = null;
1468:
1469: if (ann != null)
1470: targetEntity = ann.getClass("targetEntity");
1471: else {
1472:
1473: String s = manyToOneConfig.getTargetEntity();
1474:
1475: if ((s != null) && (s.length() > 0))
1476: targetEntity = _persistenceUnit.getJClassLoader()
1477: .forName(s);
1478: }
1479:
1480: if (targetEntity == null
1481: || targetEntity.getName().equals("void")) {
1482: targetEntity = fieldType;
1483: }
1484:
1485: getInternalEntityConfig(targetEntity, _annotationCfg);
1486: JAnnotation targetEntityAnn = _annotationCfg
1487: .getAnnotation();
1488: EntityConfig targetEntityConfig = _annotationCfg
1489: .getEntityConfig();
1490:
1491: if (_annotationCfg.isNull()) {
1492: throw error(
1493: field,
1494: L
1495: .l(
1496: "'{0}' is an illegal targetEntity for {1}. @ManyToOne relations must target a valid @Entity.",
1497: targetEntity.getName(), field
1498: .getName()));
1499: }
1500:
1501: if (!fieldType.isAssignableFrom(targetEntity)) {
1502: throw error(
1503: field,
1504: L
1505: .l(
1506: "'{0}' is an illegal targetEntity for {1}. @ManyToOne targetEntity must be assignable to the field type '{2}'.",
1507: targetEntity.getName(), field
1508: .getName(), fieldType
1509: .getName()));
1510: }
1511:
1512: RelatedType relatedType = (RelatedType) sourceType;
1513:
1514: relatedType.setHasDependent(true);
1515:
1516: _linkCompletions.add(new ManyToOneCompletion(relatedType,
1517: field, fieldName, fieldType));
1518: } else if ((oneToManyConfig != null)
1519: || field
1520: .isAnnotationPresent(javax.persistence.OneToMany.class)) {
1521: validateAnnotations(field, "@OneToMany",
1522: _oneToManyAnnotations);
1523:
1524: if (field
1525: .isAnnotationPresent(javax.persistence.MapKey.class)) {
1526: if (!fieldType.getName().equals("java.util.Map")) {
1527: throw error(
1528: field,
1529: L
1530: .l(
1531: "'{0}' is an illegal @OneToMany/@MapKey type for {1}. @MapKey must be a java.util.Map",
1532: fieldType.getName(), field
1533: .getName()));
1534: }
1535: } else if (!_oneToManyTypes.contains(fieldType.getName())) {
1536: throw error(
1537: field,
1538: L
1539: .l(
1540: "'{0}' is an illegal @OneToMany type for {1}. @OneToMany must be a java.util.Collection, java.util.List or java.util.Map",
1541: fieldType.getName(), field
1542: .getName()));
1543: }
1544:
1545: RelatedType relatedType = (RelatedType) sourceType;
1546:
1547: _depCompletions.add(new OneToManyCompletion(relatedType,
1548: field, fieldName, fieldType, oneToManyConfig));
1549: } else if ((oneToOneConfig != null)
1550: || field
1551: .isAnnotationPresent(javax.persistence.OneToOne.class)) {
1552: validateAnnotations(field, "@OneToOne",
1553: _oneToOneAnnotations);
1554:
1555: RelatedType relatedType = (RelatedType) sourceType;
1556:
1557: OneToOneCompletion oneToOne = new OneToOneCompletion(
1558: relatedType, field, fieldName, fieldType);
1559:
1560: // jpa/0o03 and jpa/0o06 (check also jpa/0o07 with no mappedBy at all)
1561: // @OneToOne with mappedBy should be completed first
1562: String mappedBy;
1563:
1564: if (oneToOneConfig != null)
1565: mappedBy = oneToOneConfig.getMappedBy();
1566: else {
1567: JAnnotation oneToOneAnn = field
1568: .getAnnotation(OneToOne.class);
1569: mappedBy = oneToOneAnn.getString("mappedBy");
1570: }
1571:
1572: boolean isOwner = (mappedBy == null || mappedBy.equals(""));
1573:
1574: if (isOwner)
1575: _depCompletions.add(oneToOne);
1576: else {
1577: _depCompletions.add(0, oneToOne);
1578: relatedType.setHasDependent(true);
1579: }
1580:
1581: ArrayList<OneToOneCompletion> oneToOneList = _oneToOneCompletions
1582: .get(relatedType);
1583:
1584: if (oneToOneList == null) {
1585: oneToOneList = new ArrayList<OneToOneCompletion>();
1586: _oneToOneCompletions.put(relatedType, oneToOneList);
1587: }
1588:
1589: oneToOneList.add(oneToOne);
1590: } else if ((manyToManyConfig != null)
1591: || field
1592: .isAnnotationPresent(javax.persistence.ManyToMany.class)) {
1593:
1594: if (field
1595: .isAnnotationPresent(javax.persistence.MapKey.class)) {
1596: if (!fieldType.getName().equals("java.util.Map")) {
1597: throw error(
1598: field,
1599: L
1600: .l(
1601: "'{0}' is an illegal @ManyToMany/@MapKey type for {1}. @MapKey must be a java.util.Map",
1602: fieldType.getName(), field
1603: .getName()));
1604: }
1605: }
1606:
1607: RelatedType relatedType = (RelatedType) sourceType;
1608:
1609: Completion completion = new ManyToManyCompletion(
1610: relatedType, field, fieldName, fieldType);
1611:
1612: JAnnotation ann = field.getAnnotation(ManyToMany.class);
1613:
1614: String mappedBy;
1615:
1616: if (ann != null)
1617: mappedBy = ann.getString("mappedBy");
1618: else
1619: mappedBy = manyToManyConfig.getMappedBy();
1620:
1621: if ("".equals(mappedBy))
1622: _linkCompletions.add(completion);
1623: else
1624: _depCompletions.add(completion);
1625: } else if (field
1626: .isAnnotationPresent(javax.persistence.Embedded.class)) {
1627: validateAnnotations(field, "@Embedded",
1628: _embeddedAnnotations);
1629:
1630: RelatedType relatedType = (RelatedType) sourceType;
1631:
1632: relatedType.setHasDependent(true);
1633:
1634: _depCompletions.add(new EmbeddedCompletion(relatedType,
1635: field, fieldName, fieldType, false));
1636: } else if (field
1637: .isAnnotationPresent(javax.persistence.EmbeddedId.class)) {
1638: validateAnnotations(field, "@EmbeddedId",
1639: _embeddedIdAnnotations);
1640:
1641: _depCompletions.add(new EmbeddedCompletion(
1642: (RelatedType) sourceType, field, fieldName,
1643: fieldType, true));
1644: } else if (field
1645: .isAnnotationPresent(javax.persistence.Transient.class)) {
1646: } else {
1647: addBasic(sourceType, field, fieldName, fieldType,
1648: basicConfig);
1649: }
1650: }
1651:
1652: void addBasic(AbstractStatefulType sourceType,
1653: JAccessibleObject field, String fieldName,
1654: JClass fieldType, BasicConfig basicConfig)
1655: throws ConfigException {
1656: AmberPersistenceUnit persistenceUnit = sourceType
1657: .getPersistenceUnit();
1658:
1659: JAnnotation basicAnn = field.getAnnotation(Basic.class);
1660: JAnnotation columnAnn = field
1661: .getAnnotation(javax.persistence.Column.class);
1662: JAnnotation enumeratedAnn = field
1663: .getAnnotation(Enumerated.class);
1664:
1665: ColumnConfig columnConfig = null;
1666:
1667: if (basicConfig != null)
1668: columnConfig = basicConfig.getColumn();
1669:
1670: if (_basicTypes.contains(fieldType.getName())) {
1671: } else if (fieldType.isAssignableTo(java.io.Serializable.class)) {
1672: } else
1673: throw error(field, L.l(
1674: "{0} is an invalid @Basic type for {1}.", fieldType
1675: .getName(), field.getName()));
1676:
1677: Type amberType;
1678:
1679: if (enumeratedAnn == null)
1680: amberType = persistenceUnit.createType(fieldType);
1681: else {
1682: com.caucho.amber.type.EnumType enumType;
1683:
1684: enumType = persistenceUnit.createEnum(fieldType.getName(),
1685: fieldType);
1686:
1687: enumType
1688: .setOrdinal(enumeratedAnn.get("value") == javax.persistence.EnumType.ORDINAL);
1689:
1690: amberType = enumType;
1691: }
1692:
1693: Column fieldColumn = null;
1694:
1695: fieldColumn = createColumn(sourceType, field, fieldName,
1696: columnAnn, amberType, columnConfig);
1697:
1698: PropertyField property = new PropertyField(sourceType,
1699: fieldName);
1700: property.setColumn(fieldColumn);
1701:
1702: // jpa/0w24
1703: property.setType(amberType);
1704:
1705: if (basicAnn != null)
1706: property.setLazy(basicAnn.get("fetch") == FetchType.LAZY);
1707: else if (basicConfig != null)
1708: property.setLazy(basicConfig.getFetch() == FetchType.LAZY);
1709: else
1710: property.setLazy(false);
1711:
1712: /*
1713: field.setInsertable(insertable);
1714: field.setUpdateable(updateable);
1715: */
1716:
1717: sourceType.addField(property);
1718: }
1719:
1720: void addVersion(RelatedType sourceType, JAccessibleObject field,
1721: String fieldName, JClass fieldType,
1722: VersionConfig versionConfig) throws ConfigException {
1723: AmberPersistenceUnit persistenceUnit = sourceType
1724: .getPersistenceUnit();
1725:
1726: JAnnotation columnAnn = field
1727: .getAnnotation(javax.persistence.Column.class);
1728:
1729: ColumnConfig columnConfig = null;
1730:
1731: if (versionConfig != null)
1732: columnConfig = versionConfig.getColumn();
1733:
1734: if (!_versionTypes.contains(fieldType.getName())) {
1735: throw error(field, L.l(
1736: "{0} is an invalid @Version type for {1}.",
1737: fieldType.getName(), field.getName()));
1738: }
1739:
1740: Type amberType = persistenceUnit.createType(fieldType);
1741:
1742: Column fieldColumn = createColumn(sourceType, field, fieldName,
1743: columnAnn, amberType, columnConfig);
1744:
1745: VersionField version = new VersionField(sourceType, fieldName);
1746: version.setColumn(fieldColumn);
1747:
1748: sourceType.setVersionField(version);
1749: }
1750:
1751: private Column createColumn(AbstractStatefulType beanType,
1752: JAccessibleObject field, String fieldName,
1753: JAnnotation columnAnn, Type amberType,
1754: ColumnConfig columnConfig) throws ConfigException {
1755: RelatedType entityType = null;
1756:
1757: if (beanType instanceof RelatedType)
1758: entityType = (RelatedType) beanType;
1759:
1760: String name;
1761:
1762: if (columnAnn != null && !columnAnn.get("name").equals(""))
1763: name = (String) columnAnn.get("name");
1764: else if (columnConfig != null
1765: && !columnConfig.getName().equals(""))
1766: name = columnConfig.getName();
1767: else
1768: name = toSqlName(fieldName);
1769:
1770: Column column = null;
1771:
1772: if (entityType == null) { // embeddable
1773: column = new Column(null, name, amberType);
1774: } else if (columnAnn != null
1775: && !columnAnn.get("table").equals("")) {
1776: String tableName = columnAnn.getString("table");
1777: Table table;
1778:
1779: table = entityType.getSecondaryTable(tableName);
1780:
1781: if (table == null)
1782: throw error(
1783: field,
1784: L
1785: .l(
1786: "{0} @Column(table='{1}') is an unknown secondary table.",
1787: fieldName, tableName));
1788:
1789: column = table.createColumn(name, amberType);
1790: } else if (entityType.getTable() != null)
1791: column = entityType.getTable()
1792: .createColumn(name, amberType);
1793: else { // jpa/0ge2: MappedSuperclassType
1794: column = new Column(null, name, amberType);
1795: }
1796:
1797: if (column != null && columnAnn != null) {
1798: // primaryKey = column.primaryKey();
1799: column.setUnique(columnAnn.getBoolean("unique"));
1800: column.setNotNull(!columnAnn.getBoolean("nullable"));
1801: //insertable = column.insertable();
1802: //updateable = column.updatable();
1803: if (!"".equals(columnAnn.getString("columnDefinition")))
1804: column.setSQLType(columnAnn
1805: .getString("columnDefinition"));
1806: column.setLength(columnAnn.getInt("length"));
1807: int precision = columnAnn.getInt("precision");
1808: if (precision < 0) {
1809: throw error(field, L.l(
1810: "{0} @Column precision cannot be less than 0.",
1811: fieldName));
1812: }
1813:
1814: int scale = columnAnn.getInt("scale");
1815: if (scale < 0) {
1816: throw error(field, L.l(
1817: "{0} @Column scale cannot be less than 0.",
1818: fieldName));
1819: }
1820:
1821: // this test implicitly works for case where
1822: // precision is not set explicitly (ie: set to 0 by default)
1823: // and scale is set
1824: if (scale > precision) {
1825: throw error(
1826: field,
1827: L
1828: .l(
1829: "{0} @Column scale cannot be greater than precision. Must set precision to a non-zero value before setting scale.",
1830: fieldName));
1831: }
1832:
1833: if (precision > 0) {
1834: column.setPrecision(precision);
1835: column.setScale(scale);
1836: }
1837: }
1838:
1839: return column;
1840: }
1841:
1842: void addManyToOne(RelatedType sourceType, JAccessibleObject field,
1843: String fieldName, JClass fieldType) throws ConfigException {
1844: AmberPersistenceUnit persistenceUnit = sourceType
1845: .getPersistenceUnit();
1846:
1847: getInternalManyToOneConfig(sourceType.getBeanClass(), field,
1848: fieldName, _annotationCfg);
1849: JAnnotation manyToOneAnn = _annotationCfg.getAnnotation();
1850: Object manyToOneConfig = _annotationCfg.getManyToOneConfig();
1851: HashMap<String, JoinColumnConfig> joinColumnMap = null;
1852: CascadeType cascadeTypes[] = null;
1853:
1854: JClass parentClass = sourceType.getBeanClass();
1855:
1856: do {
1857: getInternalEntityConfig(parentClass, _annotationCfg);
1858: JAnnotation parentEntity = _annotationCfg.getAnnotation();
1859: EntityConfig super EntityConfig = _annotationCfg
1860: .getEntityConfig();
1861:
1862: if (super EntityConfig != null) {
1863: AttributesConfig attributesConfig = super EntityConfig
1864: .getAttributes();
1865:
1866: if (attributesConfig != null) {
1867: if (manyToOneConfig == null)
1868: manyToOneConfig = attributesConfig
1869: .getManyToOne(fieldName);
1870: }
1871: }
1872:
1873: parentClass = parentClass.getSuperClass();
1874: } while ((parentClass != null) && (manyToOneConfig == null));
1875:
1876: FetchType fetchType = FetchType.EAGER;
1877: JClass targetClass = null;
1878:
1879: boolean isManyToOne = true;
1880:
1881: if ((manyToOneAnn == null) && (manyToOneConfig == null)) {
1882: // jpa/0j67
1883: isManyToOne = false;
1884:
1885: // jpa/0o03
1886: getInternalOneToOneConfig(sourceType.getBeanClass(), field,
1887: fieldName, _annotationCfg);
1888: manyToOneAnn = _annotationCfg.getAnnotation();
1889: manyToOneConfig = _annotationCfg.getOneToOneConfig();
1890:
1891: if (manyToOneConfig != null) {
1892: fetchType = ((OneToOneConfig) manyToOneConfig)
1893: .getFetch();
1894: joinColumnMap = ((OneToOneConfig) manyToOneConfig)
1895: .getJoinColumnMap();
1896:
1897: String s = ((OneToOneConfig) manyToOneConfig)
1898: .getTargetEntity();
1899: if (s != null)
1900: targetClass = _persistenceUnit.getJClassLoader()
1901: .forName(s);
1902: }
1903: } else {
1904: if (manyToOneConfig != null) {
1905: fetchType = ((ManyToOneConfig) manyToOneConfig)
1906: .getFetch();
1907: joinColumnMap = ((ManyToOneConfig) manyToOneConfig)
1908: .getJoinColumnMap();
1909: CascadeConfig cascade = ((ManyToOneConfig) manyToOneConfig)
1910: .getCascade();
1911:
1912: if (cascade != null) {
1913: cascadeTypes = cascade.getCascadeTypes();
1914: }
1915:
1916: String s = ((ManyToOneConfig) manyToOneConfig)
1917: .getTargetEntity();
1918: if (s != null)
1919: targetClass = _persistenceUnit.getJClassLoader()
1920: .forName(s);
1921: }
1922: }
1923:
1924: if (manyToOneAnn != null) {
1925: fetchType = (FetchType) manyToOneAnn.get("fetch");
1926:
1927: targetClass = manyToOneAnn.getClass("targetEntity");
1928:
1929: // XXX: runtime does not cast this
1930: // cascadeType = (CascadeType []) manyToOneAnn.get("cascade");
1931: Object cascade[] = (Object[]) manyToOneAnn.get("cascade");
1932:
1933: cascadeTypes = new CascadeType[cascade.length];
1934:
1935: for (int i = 0; i < cascade.length; i++)
1936: cascadeTypes[i] = (CascadeType) cascade[i];
1937: }
1938:
1939: if (fetchType == FetchType.EAGER) {
1940: if (sourceType.getBeanClass().getName().equals(
1941: fieldType.getName())) {
1942: throw error(
1943: field,
1944: L
1945: .l(
1946: "'{0}': '{1}' is an illegal recursive type for @OneToOne/@ManyToOne with EAGER fetching. You should specify FetchType.LAZY for this relationship.",
1947: field.getName(), fieldType
1948: .getName()));
1949: }
1950: }
1951:
1952: JAnnotation joinColumns = field
1953: .getAnnotation(JoinColumns.class);
1954:
1955: Object[] joinColumnsAnn = null;
1956:
1957: if (joinColumns != null)
1958: joinColumnsAnn = (Object[]) joinColumns.get("value");
1959:
1960: JAnnotation joinColumnAnn = field
1961: .getAnnotation(JoinColumn.class);
1962:
1963: if (joinColumnsAnn != null && joinColumnAnn != null) {
1964: throw error(
1965: field,
1966: L
1967: .l(
1968: "{0} may not have both @JoinColumn and @JoinColumns",
1969: field.getName()));
1970: }
1971:
1972: if (joinColumnAnn != null)
1973: joinColumnsAnn = new Object[] { joinColumnAnn };
1974:
1975: String targetName = "";
1976: if (targetClass != null)
1977: targetName = targetClass.getName();
1978:
1979: if (targetName.equals("") || targetName.equals("void"))
1980: targetName = fieldType.getName();
1981:
1982: EntityManyToOneField manyToOneField;
1983: manyToOneField = new EntityManyToOneField(sourceType,
1984: fieldName, cascadeTypes, isManyToOne);
1985:
1986: EntityType targetType = persistenceUnit.createEntity(
1987: targetName, fieldType);
1988:
1989: manyToOneField.setType(targetType);
1990:
1991: manyToOneField.setLazy(fetchType == FetchType.LAZY);
1992:
1993: manyToOneField.setJoinColumns(joinColumnsAnn);
1994: manyToOneField.setJoinColumnMap(joinColumnMap);
1995:
1996: sourceType.addField(manyToOneField);
1997:
1998: // jpa/0ge3
1999: if (sourceType instanceof MappedSuperclassType)
2000: return;
2001:
2002: validateJoinColumns(field, joinColumnsAnn, joinColumnMap,
2003: targetType);
2004:
2005: manyToOneField.init();
2006: }
2007:
2008: public static JAnnotation getJoinColumn(JAnnotation joinColumns,
2009: String keyName) {
2010: if (joinColumns == null)
2011: return null;
2012:
2013: return getJoinColumn((Object[]) joinColumns.get("value"),
2014: keyName);
2015: }
2016:
2017: void validateJoinColumns(JAccessibleObject field,
2018: Object[] columnsAnn,
2019: HashMap<String, JoinColumnConfig> joinColumnMap,
2020: RelatedType targetType) throws ConfigException {
2021: if ((joinColumnMap == null) && (columnsAnn == null))
2022: return;
2023:
2024: com.caucho.amber.field.Id id = targetType.getId();
2025:
2026: RelatedType parentType = targetType;
2027:
2028: int idCols;
2029:
2030: // XXX: jpa/0l48
2031: while ((idCols = id.getColumns().size()) == 0) {
2032: parentType = parentType.getParentType();
2033:
2034: if (parentType == null)
2035: break;
2036:
2037: id = parentType.getId();
2038: }
2039:
2040: int size;
2041: Object joinColumnCfg[] = null;
2042:
2043: if (columnsAnn != null)
2044: size = columnsAnn.length;
2045: else {
2046: size = joinColumnMap.size();
2047: joinColumnCfg = joinColumnMap.values().toArray();
2048: }
2049:
2050: if (idCols != size) {
2051: throw error(
2052: field,
2053: L
2054: .l(
2055: "Number of @JoinColumns for '{1}' ({0}) does not match the number of primary key columns for '{3}' ({2}).",
2056: "" + size, field.getName(), idCols,
2057: targetType.getName()));
2058: }
2059:
2060: for (int i = 0; i < size; i++) {
2061: String ref;
2062:
2063: if (joinColumnCfg != null) {
2064: ref = ((JoinColumnConfig) joinColumnCfg[i])
2065: .getReferencedColumnName();
2066: } else {
2067: JAnnotation ann = (JAnnotation) columnsAnn[i];
2068:
2069: ref = ann.getString("referencedColumnName");
2070: }
2071:
2072: if (((ref == null) || ref.equals("")) && size > 1)
2073: throw error(
2074: field,
2075: L
2076: .l("referencedColumnName is required when more than one @JoinColumn is specified."));
2077:
2078: Column column = findColumn(id.getColumns(), ref);
2079:
2080: if (column == null)
2081: throw error(
2082: field,
2083: L
2084: .l(
2085: "referencedColumnName '{0}' does not match any key column in '{1}'.",
2086: ref, targetType.getName()));
2087: }
2088: }
2089:
2090: private Column findColumn(ArrayList<Column> columns, String ref) {
2091: if (((ref == null) || ref.equals("")) && columns.size() == 1)
2092: return columns.get(0);
2093:
2094: for (Column column : columns) {
2095: if (column.getName().equals(ref))
2096: return column;
2097: }
2098:
2099: return null;
2100: }
2101:
2102: public static JAnnotation getJoinColumn(Object[] columnsAnn,
2103: String keyName) {
2104: if (columnsAnn == null || columnsAnn.length == 0)
2105: return null;
2106:
2107: for (int i = 0; i < columnsAnn.length; i++) {
2108: JAnnotation ann = (JAnnotation) columnsAnn[i];
2109:
2110: String ref = ann.getString("referencedColumnName");
2111:
2112: if (ref.equals("") || ref.equals(keyName))
2113: return ann;
2114: }
2115:
2116: return null;
2117: }
2118:
2119: void addManyToMany(RelatedType sourceType, JAccessibleObject field,
2120: String fieldName, JClass fieldType) throws ConfigException {
2121: getInternalManyToManyConfig(sourceType.getBeanClass(), field,
2122: fieldName, _annotationCfg);
2123: JAnnotation manyToManyAnn = _annotationCfg.getAnnotation();
2124: ManyToManyConfig manyToManyConfig = _annotationCfg
2125: .getManyToManyConfig();
2126:
2127: JType retType;
2128:
2129: if (field instanceof JField)
2130: retType = ((JField) field).getGenericType();
2131: else
2132: retType = ((JMethod) field).getGenericReturnType();
2133:
2134: JType[] typeArgs = retType.getActualTypeArguments();
2135:
2136: String targetName = "";
2137:
2138: if (manyToManyAnn != null) {
2139: JClass targetEntity = manyToManyAnn
2140: .getClass("targetEntity");
2141:
2142: if (targetEntity != null)
2143: targetName = targetEntity.getName();
2144: } else
2145: targetName = manyToManyConfig.getTargetEntity();
2146:
2147: if (!targetName.equals("") && !targetName.equals("void")) {
2148: } else if (typeArgs.length > 0)
2149: targetName = typeArgs[0].getName();
2150: else
2151: throw error(
2152: field,
2153: L
2154: .l(
2155: "Can't determine targetEntity for {0}. @OneToMany properties must target @Entity beans.",
2156: field.getName()));
2157:
2158: EntityType targetType = _persistenceUnit
2159: .getEntityType(targetName);
2160:
2161: if (targetType == null)
2162: throw error(
2163: field,
2164: L
2165: .l(
2166: "targetEntity '{0}' is not an @Entity bean for {1}. The targetEntity of a @ManyToMany collection must be an @Entity bean.",
2167: targetName, field.getName()));
2168:
2169: // XXX: introspect cascade types
2170: CascadeType[] cascadeTypes = null;
2171:
2172: String mappedBy;
2173:
2174: if (manyToManyAnn != null) {
2175: mappedBy = manyToManyAnn.getString("mappedBy");
2176:
2177: // XXX: runtime does not cast this
2178: // cascadeType = (CascadeType []) manyToManyAnn.get("cascade");
2179: Object cascade[] = (Object[]) manyToManyAnn.get("cascade");
2180:
2181: cascadeTypes = new CascadeType[cascade.length];
2182:
2183: for (int i = 0; i < cascade.length; i++)
2184: cascadeTypes[i] = (CascadeType) cascade[i];
2185: } else {
2186: mappedBy = manyToManyConfig.getMappedBy();
2187:
2188: CascadeConfig cascade = ((ManyToManyConfig) manyToManyConfig)
2189: .getCascade();
2190:
2191: if (cascade != null) {
2192: cascadeTypes = cascade.getCascadeTypes();
2193: }
2194: }
2195:
2196: if (!((mappedBy == null) || "".equals(mappedBy))) {
2197: EntityManyToManyField sourceField = (EntityManyToManyField) targetType
2198: .getField(mappedBy);
2199:
2200: EntityManyToManyField manyToManyField;
2201:
2202: if (sourceField == null)
2203: throw error(
2204: field,
2205: L
2206: .l(
2207: "Unable to find the associated field in '{0}' for a @ManyToMany relationship from '{1}'",
2208: targetName, field.getName()));
2209:
2210: manyToManyField = new EntityManyToManyField(sourceType,
2211: fieldName, sourceField, cascadeTypes);
2212: manyToManyField.setType(targetType);
2213: sourceType.addField(manyToManyField);
2214:
2215: // jpa/0i5-
2216: // Update column names for bidirectional many-to-many
2217:
2218: if (!sourceField.hasJoinColumns()) {
2219: LinkColumns sourceLink = sourceField.getSourceLink();
2220: ArrayList<ForeignColumn> columns = sourceLink
2221: .getColumns();
2222: for (ForeignColumn column : columns) {
2223: String columnName = column.getName();
2224: columnName = columnName.substring(columnName
2225: .indexOf('_'));
2226: columnName = toSqlName(manyToManyField.getName())
2227: + columnName;
2228: column.setName(columnName);
2229: }
2230: }
2231:
2232: if (!sourceField.hasInverseJoinColumns()) {
2233: LinkColumns targetLink = sourceField.getTargetLink();
2234: ArrayList<ForeignColumn> columns = targetLink
2235: .getColumns();
2236: for (ForeignColumn column : columns) {
2237: String columnName = column.getName();
2238: columnName = columnName.substring(columnName
2239: .indexOf('_'));
2240: columnName = toSqlName(sourceField.getName())
2241: + columnName;
2242: column.setName(columnName);
2243: }
2244: }
2245:
2246: return;
2247: }
2248:
2249: EntityManyToManyField manyToManyField;
2250:
2251: manyToManyField = new EntityManyToManyField(sourceType,
2252: fieldName, cascadeTypes);
2253: manyToManyField.setType(targetType);
2254:
2255: String sqlTable = sourceType.getTable().getName() + "_"
2256: + targetType.getTable().getName();
2257:
2258: JAnnotation joinTableAnn = field
2259: .getAnnotation(javax.persistence.JoinTable.class);
2260:
2261: JoinTableConfig joinTableConfig = null;
2262:
2263: if (manyToManyConfig != null)
2264: joinTableConfig = manyToManyConfig.getJoinTable();
2265:
2266: Table mapTable = null;
2267:
2268: ArrayList<ForeignColumn> sourceColumns = null;
2269: ArrayList<ForeignColumn> targetColumns = null;
2270:
2271: if ((joinTableAnn != null) || (joinTableConfig != null)) {
2272:
2273: Object joinColumns[] = null;
2274: Object inverseJoinColumns[] = null;
2275:
2276: HashMap<String, JoinColumnConfig> joinColumnsConfig = null;
2277: HashMap<String, JoinColumnConfig> inverseJoinColumnsConfig = null;
2278:
2279: String joinTableName;
2280:
2281: if (joinTableAnn != null) {
2282: joinTableName = joinTableAnn.getString("name");
2283: joinColumns = (Object[]) joinTableAnn
2284: .get("joinColumns");
2285: inverseJoinColumns = (Object[]) joinTableAnn
2286: .get("inverseJoinColumns");
2287:
2288: if ((joinColumns != null) && (joinColumns.length > 0))
2289: manyToManyField.setJoinColumns(true);
2290:
2291: if ((inverseJoinColumns != null)
2292: && (inverseJoinColumns.length > 0))
2293: manyToManyField.setInverseJoinColumns(true);
2294: } else {
2295: joinTableName = joinTableConfig.getName();
2296: joinColumnsConfig = joinTableConfig.getJoinColumnMap();
2297: inverseJoinColumnsConfig = joinTableConfig
2298: .getInverseJoinColumnMap();
2299:
2300: if ((joinColumnsConfig != null)
2301: && (joinColumnsConfig.size() > 0))
2302: manyToManyField.setJoinColumns(true);
2303:
2304: if ((inverseJoinColumnsConfig != null)
2305: && (inverseJoinColumnsConfig.size() > 0))
2306: manyToManyField.setInverseJoinColumns(true);
2307: }
2308:
2309: if (!joinTableName.equals(""))
2310: sqlTable = joinTableName;
2311:
2312: mapTable = _persistenceUnit.createTable(sqlTable);
2313:
2314: sourceColumns = AbstractConfigIntrospector
2315: .calculateColumns(field, mapTable, sourceType
2316: .getTable().getName()
2317: + "_", sourceType, joinColumns,
2318: joinColumnsConfig);
2319:
2320: targetColumns = AbstractConfigIntrospector
2321: .calculateColumns(field, mapTable, targetType
2322: .getTable().getName()
2323: + "_", targetType, inverseJoinColumns,
2324: inverseJoinColumnsConfig);
2325: } else {
2326: mapTable = _persistenceUnit.createTable(sqlTable);
2327:
2328: sourceColumns = AbstractConfigIntrospector
2329: .calculateColumns(mapTable, sourceType.getTable()
2330: .getName()
2331: + "_", sourceType);
2332:
2333: targetColumns = AbstractConfigIntrospector
2334: .calculateColumns(mapTable, targetType.getTable()
2335: .getName()
2336: + "_", targetType);
2337: }
2338:
2339: manyToManyField.setAssociationTable(mapTable);
2340: manyToManyField.setTable(sqlTable);
2341:
2342: manyToManyField.setSourceLink(new LinkColumns(mapTable,
2343: sourceType.getTable(), sourceColumns));
2344:
2345: manyToManyField.setTargetLink(new LinkColumns(mapTable,
2346: targetType.getTable(), targetColumns));
2347:
2348: getInternalMapKeyConfig(sourceType.getBeanClass(), field,
2349: fieldName, _annotationCfg);
2350: JAnnotation mapKeyAnn = _annotationCfg.getAnnotation();
2351: MapKeyConfig mapKeyConfig = _annotationCfg.getMapKeyConfig();
2352:
2353: if (!_annotationCfg.isNull()) {
2354:
2355: String key;
2356:
2357: if (mapKeyAnn != null)
2358: key = mapKeyAnn.getString("name");
2359: else
2360: key = mapKeyConfig.getName();
2361:
2362: String getter = "get"
2363: + Character.toUpperCase(key.charAt(0))
2364: + key.substring(1);
2365:
2366: JMethod method = targetType.getGetter(getter);
2367:
2368: if (method == null) {
2369: throw error(
2370: field,
2371: L
2372: .l(
2373: "targetEntity '{0}' has no getter for field named '{1}'. Either the @MapKey name or the @ManyToMany targetEntity is incorrect.",
2374: targetName, key));
2375: }
2376:
2377: manyToManyField.setMapKey(key);
2378: }
2379:
2380: sourceType.addField(manyToManyField);
2381: }
2382:
2383: EntityManyToOneField getSourceField(RelatedType targetType,
2384: String mappedBy, RelatedType sourceType) {
2385: do {
2386: ArrayList<AmberField> fields = targetType.getFields();
2387:
2388: for (AmberField field : fields) {
2389: // jpa/0o07: there is no mappedBy at all on any sides.
2390: if ("".equals(mappedBy) || mappedBy == null) {
2391: if (field.getJavaType().isAssignableFrom(
2392: sourceType.getBeanClass()))
2393: return (EntityManyToOneField) field;
2394: } else if (field.getName().equals(mappedBy))
2395: return (EntityManyToOneField) field;
2396: }
2397:
2398: // jpa/0ge4
2399: targetType = targetType.getParentType();
2400: } while (targetType != null);
2401:
2402: return null;
2403: }
2404:
2405: OneToOneCompletion getSourceCompletion(RelatedType targetType,
2406: String mappedBy) {
2407: do {
2408: ArrayList<OneToOneCompletion> sourceCompletions = _oneToOneCompletions
2409: .get(targetType);
2410:
2411: if (sourceCompletions == null) {
2412: } // jpa/0o07
2413: else if (sourceCompletions.size() == 1)
2414: return sourceCompletions.get(0);
2415: else {
2416: for (OneToOneCompletion oneToOne : sourceCompletions) {
2417: if (oneToOne.getFieldName().equals(mappedBy)) {
2418: return oneToOne;
2419: }
2420: }
2421: }
2422:
2423: // jpa/0ge4
2424: targetType = targetType.getParentType();
2425: } while (targetType != null);
2426:
2427: return null;
2428: }
2429:
2430: /**
2431: * completes for dependent
2432: */
2433: class Completion {
2434: protected RelatedType _relatedType;
2435:
2436: protected Completion(RelatedType relatedType, String fieldName) {
2437: _relatedType = relatedType;
2438: _relatedType.addCompletionField(fieldName);
2439: }
2440:
2441: protected Completion(RelatedType relatedType) {
2442: _relatedType = relatedType;
2443: }
2444:
2445: RelatedType getRelatedType() {
2446: return _relatedType;
2447: }
2448:
2449: void complete() throws ConfigException {
2450: }
2451: }
2452:
2453: /**
2454: * completes for dependent
2455: */
2456: class OneToManyCompletion extends Completion {
2457: private JAccessibleObject _field;
2458: private String _fieldName;
2459: private JClass _fieldType;
2460: private OneToManyConfig _oneToManyConfig;
2461:
2462: OneToManyCompletion(RelatedType type, JAccessibleObject field,
2463: String fieldName, JClass fieldType,
2464: OneToManyConfig oneToManyConfig) {
2465: super (type, fieldName);
2466:
2467: _field = field;
2468: _fieldName = fieldName;
2469: _fieldType = fieldType;
2470: _oneToManyConfig = oneToManyConfig;
2471: }
2472:
2473: void complete() throws ConfigException {
2474: getInternalOneToManyConfig(_relatedType.getBeanClass(),
2475: _field, _fieldName, _annotationCfg);
2476: JAnnotation oneToManyAnn = _annotationCfg.getAnnotation();
2477: OneToManyConfig oneToManyConfig = _annotationCfg
2478: .getOneToManyConfig();
2479:
2480: AmberPersistenceUnit persistenceUnit = _relatedType
2481: .getPersistenceUnit();
2482:
2483: JType retType;
2484:
2485: if (_field instanceof JField)
2486: retType = ((JField) _field).getGenericType();
2487: else
2488: retType = ((JMethod) _field).getGenericReturnType();
2489:
2490: JType[] typeArgs = retType.getActualTypeArguments();
2491:
2492: JClass targetEntity = null;
2493:
2494: if (oneToManyAnn != null)
2495: targetEntity = oneToManyAnn.getClass("targetEntity");
2496: else {
2497: String s = oneToManyConfig.getTargetEntity();
2498:
2499: if (s != null)
2500: targetEntity = _persistenceUnit.getJClassLoader()
2501: .forName(s);
2502: }
2503:
2504: String targetName = "";
2505:
2506: if (targetEntity != null)
2507: targetName = targetEntity.getName();
2508:
2509: if (!targetName.equals("") && !targetName.equals("void")) {
2510: } else if (typeArgs.length > 0)
2511: targetName = typeArgs[typeArgs.length - 1].getName();
2512: else
2513: throw error(
2514: _field,
2515: L
2516: .l(
2517: "Can't determine targetEntity for {0}. @OneToMany properties must target @Entity beans.",
2518: _field.getName()));
2519:
2520: EntityType targetType = persistenceUnit
2521: .getEntityType(targetName);
2522: if (targetType == null) {
2523:
2524: EntityConfig entityConfig = getEntityConfig(targetName);
2525:
2526: if (entityConfig == null)
2527: throw error(
2528: _field,
2529: L
2530: .l(
2531: "targetEntity '{0}' is not an @Entity bean for {1}. The targetEntity of a @OneToMany collection must be an @Entity bean.",
2532: targetName, _field
2533: .getName()));
2534: }
2535:
2536: CascadeType[] cascadeTypes = null;
2537:
2538: String mappedBy;
2539:
2540: if (oneToManyAnn != null) {
2541: mappedBy = oneToManyAnn.getString("mappedBy");
2542:
2543: // XXX: runtime does not cast this
2544: // cascadeType = (CascadeType []) oneToManyAnn.get("cascade");
2545: Object cascade[] = (Object[]) oneToManyAnn
2546: .get("cascade");
2547:
2548: cascadeTypes = new CascadeType[cascade.length];
2549:
2550: for (int i = 0; i < cascade.length; i++)
2551: cascadeTypes[i] = (CascadeType) cascade[i];
2552: } else {
2553: mappedBy = oneToManyConfig.getMappedBy();
2554:
2555: CascadeConfig cascade = ((OneToManyConfig) oneToManyConfig)
2556: .getCascade();
2557:
2558: if (cascade != null) {
2559: cascadeTypes = cascade.getCascadeTypes();
2560: }
2561: }
2562:
2563: if (mappedBy != null && !mappedBy.equals("")) {
2564: oneToManyBidirectional(targetType, targetName,
2565: mappedBy, cascadeTypes);
2566: } else {
2567: oneToManyUnidirectional(targetType, targetName,
2568: cascadeTypes);
2569: }
2570: }
2571:
2572: private void oneToManyBidirectional(RelatedType targetType,
2573: String targetName, String mappedBy,
2574: CascadeType[] cascadeTypes) throws ConfigException {
2575: JAnnotation joinTableAnn = _field
2576: .getAnnotation(javax.persistence.JoinTable.class);
2577:
2578: JoinTableConfig joinTableConfig = null;
2579:
2580: if (_oneToManyConfig != null)
2581: joinTableConfig = _oneToManyConfig.getJoinTable();
2582:
2583: if ((joinTableAnn != null) || (joinTableConfig != null)) {
2584: throw error(
2585: _field,
2586: L
2587: .l(
2588: "Bidirectional @ManyToOne property {0} may not have a @JoinTable annotation.",
2589: _field.getName()));
2590: }
2591:
2592: EntityManyToOneField sourceField = getSourceField(
2593: targetType, mappedBy, null);
2594:
2595: if (sourceField == null)
2596: throw error(
2597: _field,
2598: L
2599: .l(
2600: "'{0}' does not have matching field for @ManyToOne(mappedBy={1}).",
2601: targetType.getName(), mappedBy));
2602:
2603: JAnnotation orderByAnn = _field
2604: .getAnnotation(javax.persistence.OrderBy.class);
2605:
2606: String orderBy = null;
2607: ArrayList<String> orderByFields = null;
2608: ArrayList<Boolean> orderByAscending = null;
2609:
2610: if (orderByAnn != null) {
2611: orderBy = (String) orderByAnn.get("value");
2612:
2613: if (orderBy == null)
2614: orderBy = "";
2615:
2616: if ("".equals(orderBy)) {
2617: if (targetType instanceof RelatedType) {
2618: RelatedType targetRelatedType = (RelatedType) targetType;
2619: orderBy = targetRelatedType.getId()
2620: .generateJavaSelect(null);
2621: }
2622: }
2623:
2624: orderByFields = new ArrayList<String>();
2625: orderByAscending = new ArrayList<Boolean>();
2626:
2627: int len = orderBy.length();
2628:
2629: int i = 0;
2630:
2631: while (i < len) {
2632:
2633: int index = orderBy.indexOf(",", i);
2634:
2635: if (index < 0)
2636: index = len;
2637:
2638: String orderByField = orderBy.substring(i, index);
2639:
2640: i += index;
2641:
2642: // ASC or DESC
2643: index = orderByField.toUpperCase()
2644: .lastIndexOf("SC");
2645:
2646: Boolean asc = Boolean.TRUE;
2647:
2648: if (index > 1) {
2649: if (orderByField.charAt(index - 1) != 'E') {
2650: // field ASC or default
2651: if (orderByField.charAt(index - 1) == 'A'
2652: && Character
2653: .isSpaceChar(orderByField
2654: .charAt(index - 2))) {
2655: index -= 2;
2656: }
2657: } else if (index > 2
2658: && orderByField.charAt(index - 2) == 'D'
2659: && Character.isSpaceChar(orderByField
2660: .charAt(index - 3))) {
2661:
2662: asc = Boolean.FALSE;
2663: index -= 3;
2664: }
2665: }
2666:
2667: if (index > 0)
2668: orderByField = orderByField.substring(0, index)
2669: .trim();
2670:
2671: AmberField amberField = targetType
2672: .getField(orderByField);
2673:
2674: if (amberField == null)
2675: throw error(
2676: _field,
2677: L
2678: .l(
2679: "'{0}' has no field named '{1}' in @OrderBy",
2680: targetType.getName(),
2681: orderByField));
2682:
2683: /*
2684: if (amberField instanceof PropertyField) {
2685: PropertyField property = (PropertyField) amberField;
2686: orderByField = property.getColumn().getName();
2687: }
2688: */
2689:
2690: orderByFields.add(orderByField);
2691: orderByAscending.add(asc);
2692: }
2693: }
2694:
2695: EntityOneToManyField oneToMany;
2696:
2697: oneToMany = new EntityOneToManyField(_relatedType,
2698: _fieldName, cascadeTypes);
2699: oneToMany.setSourceField(sourceField);
2700: oneToMany.setOrderBy(orderByFields, orderByAscending);
2701:
2702: getInternalMapKeyConfig(_relatedType.getBeanClass(),
2703: _field, _fieldName, _annotationCfg);
2704: JAnnotation mapKeyAnn = _annotationCfg.getAnnotation();
2705: MapKeyConfig mapKeyConfig = _annotationCfg
2706: .getMapKeyConfig();
2707:
2708: if (!_annotationCfg.isNull()) {
2709:
2710: String key = mapKeyAnn.getString("name");
2711:
2712: String getter = "get"
2713: + Character.toUpperCase(key.charAt(0))
2714: + key.substring(1);
2715:
2716: JMethod method = targetType.getGetter(getter);
2717:
2718: if (method == null) {
2719: throw error(
2720: _field,
2721: L
2722: .l(
2723: "targetEntity '{0}' has no getter for field named '{1}'. Either the @MapKey name or the @OneToMany targetEntity is incorrect.",
2724: targetName, key));
2725: }
2726:
2727: oneToMany.setMapKey(key);
2728: }
2729:
2730: _relatedType.addField(oneToMany);
2731: }
2732:
2733: private void oneToManyUnidirectional(RelatedType targetType,
2734: String targetName, CascadeType[] cascadeTypes)
2735: throws ConfigException {
2736: EntityManyToManyField manyToManyField;
2737:
2738: manyToManyField = new EntityManyToManyField(_relatedType,
2739: _fieldName, cascadeTypes);
2740: manyToManyField.setType(targetType);
2741:
2742: String sqlTable = _relatedType.getTable().getName() + "_"
2743: + targetType.getTable().getName();
2744:
2745: JAnnotation joinTableAnn = _field
2746: .getAnnotation(javax.persistence.JoinTable.class);
2747:
2748: JoinTableConfig joinTableConfig = null;
2749:
2750: if (_oneToManyConfig != null)
2751: joinTableConfig = _oneToManyConfig.getJoinTable();
2752:
2753: Table mapTable = null;
2754:
2755: ArrayList<ForeignColumn> sourceColumns = null;
2756: ArrayList<ForeignColumn> targetColumns = null;
2757:
2758: if ((joinTableAnn != null) || (joinTableConfig != null)) {
2759:
2760: Object joinColumns[] = null;
2761: Object inverseJoinColumns[] = null;
2762:
2763: HashMap<String, JoinColumnConfig> joinColumnsConfig = null;
2764: HashMap<String, JoinColumnConfig> inverseJoinColumnsConfig = null;
2765:
2766: if (joinTableAnn != null) {
2767: if (!joinTableAnn.getString("name").equals(""))
2768: sqlTable = joinTableAnn.getString("name");
2769:
2770: joinColumns = (Object[]) joinTableAnn
2771: .get("joinColumns");
2772: inverseJoinColumns = (Object[]) joinTableAnn
2773: .get("inverseJoinColumns");
2774: } else {
2775: if (!joinTableConfig.getName().equals(""))
2776: sqlTable = joinTableConfig.getName();
2777:
2778: joinColumnsConfig = joinTableConfig
2779: .getJoinColumnMap();
2780: inverseJoinColumnsConfig = joinTableConfig
2781: .getInverseJoinColumnMap();
2782: }
2783:
2784: mapTable = _persistenceUnit.createTable(sqlTable);
2785:
2786: sourceColumns = AbstractConfigIntrospector
2787: .calculateColumns(
2788: _field,
2789: mapTable,
2790: _relatedType.getTable().getName() + "_",
2791: _relatedType, joinColumns,
2792: joinColumnsConfig);
2793:
2794: targetColumns = AbstractConfigIntrospector
2795: .calculateColumns(_field, mapTable, targetType
2796: .getTable().getName()
2797: + "_", targetType, inverseJoinColumns,
2798: inverseJoinColumnsConfig);
2799: } else {
2800: mapTable = _persistenceUnit.createTable(sqlTable);
2801:
2802: sourceColumns = AbstractConfigIntrospector
2803: .calculateColumns(mapTable, _relatedType
2804: .getTable().getName()
2805: + "_", _relatedType);
2806:
2807: targetColumns = AbstractConfigIntrospector
2808: .calculateColumns(mapTable,
2809: // jpa/0j40
2810: toSqlName(_fieldName) + "_", targetType);
2811: }
2812:
2813: manyToManyField.setAssociationTable(mapTable);
2814: manyToManyField.setTable(sqlTable);
2815:
2816: manyToManyField.setSourceLink(new LinkColumns(mapTable,
2817: _relatedType.getTable(), sourceColumns));
2818:
2819: manyToManyField.setTargetLink(new LinkColumns(mapTable,
2820: targetType.getTable(), targetColumns));
2821:
2822: getInternalMapKeyConfig(_relatedType.getBeanClass(),
2823: _field, _field.getName(), _annotationCfg);
2824: JAnnotation mapKeyAnn = _annotationCfg.getAnnotation();
2825: MapKeyConfig mapKeyConfig = _annotationCfg
2826: .getMapKeyConfig();
2827:
2828: if (!_annotationCfg.isNull()) {
2829:
2830: String key;
2831:
2832: if (mapKeyAnn != null)
2833: key = mapKeyAnn.getString("name");
2834: else
2835: key = mapKeyConfig.getName();
2836:
2837: String getter = "get"
2838: + Character.toUpperCase(key.charAt(0))
2839: + key.substring(1);
2840:
2841: JMethod method = targetType.getGetter(getter);
2842:
2843: if (method == null) {
2844: throw error(
2845: _field,
2846: L
2847: .l(
2848: "targetEntity '{0}' has no getter for field named '{1}'. Either the @MapKey name or the @ManyToMany targetEntity is incorrect.",
2849: targetName, key));
2850: }
2851:
2852: manyToManyField.setMapKey(key);
2853: }
2854:
2855: _relatedType.addField(manyToManyField);
2856: }
2857: }
2858:
2859: /**
2860: * completes for dependent
2861: */
2862: class OneToOneCompletion extends Completion {
2863: private JAccessibleObject _field;
2864: private String _fieldName;
2865: private JClass _fieldType;
2866:
2867: OneToOneCompletion(RelatedType type, JAccessibleObject field,
2868: String fieldName, JClass fieldType) {
2869: super (type, fieldName);
2870:
2871: _field = field;
2872: _fieldName = fieldName;
2873: _fieldType = fieldType;
2874: }
2875:
2876: String getFieldName() {
2877: return _fieldName;
2878: }
2879:
2880: void complete() throws ConfigException {
2881: getInternalOneToOneConfig(_relatedType.getBeanClass(),
2882: _field, _fieldName, _annotationCfg);
2883: JAnnotation oneToOneAnn = _annotationCfg.getAnnotation();
2884: OneToOneConfig oneToOneConfig = _annotationCfg
2885: .getOneToOneConfig();
2886:
2887: boolean isLazy;
2888:
2889: if (oneToOneAnn != null)
2890: isLazy = oneToOneAnn.get("fetch") == FetchType.LAZY;
2891: else
2892: isLazy = oneToOneConfig.getFetch() == FetchType.LAZY;
2893:
2894: if (!isLazy) {
2895: if (_relatedType.getBeanClass().getName().equals(
2896: _fieldType.getName())) {
2897: throw error(
2898: _field,
2899: L
2900: .l(
2901: "'{0}': '{1}' is an illegal recursive type for @OneToOne with EAGER fetching. You should specify FetchType.LAZY for this relationship.",
2902: _field.getName(),
2903: _fieldType.getName()));
2904: }
2905: }
2906:
2907: AmberPersistenceUnit persistenceUnit = _relatedType
2908: .getPersistenceUnit();
2909:
2910: JClass targetEntity = null;
2911: String targetName = "";
2912:
2913: if (oneToOneAnn != null) {
2914: targetEntity = oneToOneAnn.getClass("targetEntity");
2915:
2916: if (targetEntity != null)
2917: targetEntity.getName();
2918: } else {
2919: targetName = oneToOneConfig.getTargetEntity();
2920:
2921: if (!((targetName == null) || "".equals(targetName)))
2922: targetEntity = _persistenceUnit.getJClassLoader()
2923: .forName(targetName);
2924: }
2925:
2926: if (targetEntity == null
2927: || targetEntity.getName().equals("void"))
2928: targetEntity = _fieldType;
2929:
2930: getInternalEntityConfig(targetEntity, _annotationCfg);
2931: JAnnotation targetEntityAnn = _annotationCfg
2932: .getAnnotation();
2933: EntityConfig targetEntityConfig = _annotationCfg
2934: .getEntityConfig();
2935:
2936: if (_annotationCfg.isNull()) {
2937: throw error(
2938: _field,
2939: L
2940: .l(
2941: "'{0}' is an illegal targetEntity for {1}. @OneToOne relations must target a valid @Entity.",
2942: targetEntity.getName(), _field
2943: .getName()));
2944: }
2945:
2946: if (!_fieldType.isAssignableFrom(targetEntity)) {
2947: throw error(
2948: _field,
2949: L
2950: .l(
2951: "'{0}' is an illegal targetEntity for {1}. @OneToOne targetEntity must be assignable to the field type '{2}'.",
2952: targetEntity.getName(), _field
2953: .getName(), _fieldType
2954: .getName()));
2955: }
2956:
2957: String mappedBy;
2958:
2959: if (oneToOneAnn != null)
2960: mappedBy = oneToOneAnn.getString("mappedBy");
2961: else
2962: mappedBy = oneToOneConfig.getMappedBy();
2963:
2964: RelatedType targetType = null;
2965:
2966: if (targetName != null && !targetName.equals("")) {
2967: targetType = persistenceUnit.getEntityType(targetName);
2968:
2969: if (targetType == null)
2970: throw new ConfigException(
2971: L
2972: .l(
2973: "{0}: '{1}' is an unknown entity for '{2}'.",
2974: _field.getDeclaringClass()
2975: .getName(),
2976: targetName, _field
2977: .getName()));
2978: } else {
2979: targetType = persistenceUnit.getEntityType(_field
2980: .getReturnType().getName());
2981:
2982: if (targetType == null)
2983: throw new ConfigException(
2984: L
2985: .l(
2986: "{0} can't determine target name for '{1}'",
2987: _field.getDeclaringClass()
2988: .getName(), _field
2989: .getName()));
2990: }
2991:
2992: // jpa/0o00, jpa/0o03, jpa/0o06, jpa/0o07, jpa/10ca, jpa/0s2d
2993:
2994: // jpa/0o06
2995: boolean isManyToOne = (mappedBy == null)
2996: || "".equals(mappedBy);
2997:
2998: // jpa/0o07
2999: if (isManyToOne) {
3000: getInternalJoinColumnConfig(
3001: _relatedType.getBeanClass(), _field,
3002: _fieldName, _annotationCfg);
3003: JAnnotation joinColumnAnn = _annotationCfg
3004: .getAnnotation();
3005: JoinColumnConfig joinColumnConfig = _annotationCfg
3006: .getJoinColumnConfig();
3007:
3008: if (!_annotationCfg.isNull()) {
3009: // jpa/0o07: DstBean.getParent()
3010: // OK: isManyToOne = true;
3011: } else {
3012: // jpa/10ca
3013: OneToOneCompletion otherSide = getSourceCompletion(
3014: targetType, mappedBy);
3015:
3016: if (otherSide != null) {
3017: getInternalJoinColumnConfig(targetType
3018: .getBeanClass(), otherSide._field,
3019: otherSide._fieldName, _annotationCfg);
3020:
3021: // jpa/0o07, jpa/0s2d
3022: if (!_annotationCfg.isNull())
3023: isManyToOne = false;
3024: }
3025: }
3026: }
3027:
3028: // XXX: jpa/0ge4
3029: if (targetType.getParentType() != null) {
3030: if (targetType.getParentType() instanceof MappedSuperclassType) {
3031: isManyToOne = false;
3032:
3033: OneToOneCompletion otherSide = getSourceCompletion(
3034: targetType.getParentType(), mappedBy);
3035:
3036: if (otherSide != null) {
3037: // jpa/0ge4
3038: if (_depCompletions.remove(otherSide)) {
3039: otherSide.complete();
3040: }
3041: }
3042: }
3043: }
3044:
3045: if (isManyToOne) {
3046:
3047: addManyToOne(_relatedType, _field, _fieldName, _field
3048: .getReturnType());
3049:
3050: // XXX: set unique
3051: } else {
3052:
3053: if (!(mappedBy == null || "".equals(mappedBy))) {
3054:
3055: // jpa/0o06
3056:
3057: OneToOneCompletion otherSide = getSourceCompletion(
3058: targetType, mappedBy);
3059:
3060: if (otherSide != null) {
3061: // jpa/0o00
3062: if (_depCompletions.remove(otherSide)) {
3063: otherSide.complete();
3064: }
3065: }
3066: }
3067:
3068: // Owner
3069: EntityManyToOneField sourceField = getSourceField(
3070: targetType, mappedBy, _relatedType);
3071:
3072: if (sourceField == null) {
3073: throw new ConfigException(
3074: L
3075: .l(
3076: "{0}: OneToOne target '{1}' does not have a matching ManyToOne relation.",
3077: _field.getDeclaringClass()
3078: .getName(),
3079: targetType.getName()));
3080: }
3081:
3082: DependentEntityOneToOneField oneToOne;
3083:
3084: CascadeType cascadeTypes[] = null;
3085:
3086: if (oneToOneAnn != null) {
3087: // jpa/0o33
3088:
3089: // XXX: runtime does not cast this
3090: // cascadeType = (CascadeType []) manyToOneAnn.get("cascade");
3091: Object cascade[] = (Object[]) oneToOneAnn
3092: .get("cascade");
3093:
3094: cascadeTypes = new CascadeType[cascade.length];
3095:
3096: for (int i = 0; i < cascade.length; i++)
3097: cascadeTypes[i] = (CascadeType) cascade[i];
3098: }
3099:
3100: oneToOne = new DependentEntityOneToOneField(
3101: _relatedType, _fieldName, cascadeTypes);
3102: oneToOne.setTargetField(sourceField);
3103: sourceField.setTargetField(oneToOne);
3104: oneToOne.setLazy(isLazy);
3105:
3106: _relatedType.addField(oneToOne);
3107: }
3108: }
3109: }
3110:
3111: /**
3112: * completes for dependent
3113: */
3114: class ManyToManyCompletion extends Completion {
3115: private JAccessibleObject _field;
3116: private String _fieldName;
3117: private JClass _fieldType;
3118:
3119: ManyToManyCompletion(RelatedType type, JAccessibleObject field,
3120: String fieldName, JClass fieldType) {
3121: super (type, fieldName);
3122:
3123: _field = field;
3124: _fieldName = fieldName;
3125: _fieldType = fieldType;
3126: }
3127:
3128: void complete() throws ConfigException {
3129: addManyToMany(_relatedType, _field, _fieldName, _fieldType);
3130: }
3131: }
3132:
3133: /**
3134: * completes for link
3135: */
3136: class ManyToOneCompletion extends Completion {
3137: private JAccessibleObject _field;
3138: private String _fieldName;
3139: private JClass _fieldType;
3140:
3141: ManyToOneCompletion(RelatedType type, JAccessibleObject field,
3142: String fieldName, JClass fieldType) {
3143: super (type, fieldName);
3144:
3145: _field = field;
3146: _fieldName = fieldName;
3147: _fieldType = fieldType;
3148: }
3149:
3150: void complete() throws ConfigException {
3151: addManyToOne(_relatedType, _field, _fieldName, _fieldType);
3152: }
3153: }
3154:
3155: /**
3156: * completes for dependent
3157: */
3158: class EmbeddedCompletion extends Completion {
3159: private JAccessibleObject _field;
3160: private String _fieldName;
3161: private JClass _fieldType;
3162: // The same completion is used for both:
3163: // @Embedded or @EmbeddedId
3164: private boolean _embeddedId;
3165:
3166: EmbeddedCompletion(RelatedType type, JAccessibleObject field,
3167: String fieldName, JClass fieldType, boolean embeddedId) {
3168: super (type, fieldName);
3169:
3170: _field = field;
3171: _fieldName = fieldName;
3172: _fieldType = fieldType;
3173: _embeddedId = embeddedId;
3174: }
3175:
3176: void complete() throws ConfigException {
3177: getInternalAttributeOverrideConfig(_relatedType
3178: .getBeanClass(), _annotationCfg);
3179: JAnnotation attributeOverrideAnn = _annotationCfg
3180: .getAnnotation();
3181: AttributeOverrideConfig attributeOverrideConfig = _annotationCfg
3182: .getAttributeOverrideConfig();
3183:
3184: boolean hasAttributeOverride = !_annotationCfg.isNull();
3185:
3186: JAnnotation attributeOverridesAnn = _field
3187: .getAnnotation(AttributeOverrides.class);
3188:
3189: boolean hasAttributeOverrides = (attributeOverridesAnn != null);
3190:
3191: if (hasAttributeOverride && hasAttributeOverrides) {
3192: throw error(
3193: _field,
3194: L
3195: .l(
3196: "{0} may not have both @AttributeOverride and @AttributeOverrides",
3197: _field.getName()));
3198: }
3199:
3200: Object attOverridesAnn[] = null;
3201:
3202: if (attributeOverrideAnn != null) {
3203: attOverridesAnn = new Object[] { attributeOverrideAnn };
3204: } else if (attributeOverridesAnn != null) {
3205: attOverridesAnn = (Object[]) attributeOverridesAnn
3206: .get("value");
3207: }
3208:
3209: AmberPersistenceUnit persistenceUnit = _relatedType
3210: .getPersistenceUnit();
3211:
3212: EmbeddableType type = persistenceUnit
3213: .createEmbeddable(_fieldType);
3214:
3215: EntityEmbeddedField embeddedField;
3216:
3217: if (_embeddedId) {
3218: embeddedField = _relatedType.getId()
3219: .getEmbeddedIdField();
3220: } else {
3221: embeddedField = new EntityEmbeddedField(_relatedType,
3222: type, _fieldName);
3223: }
3224:
3225: // embeddedField.setEmbeddedId(_embeddedId);
3226:
3227: embeddedField.setLazy(false);
3228:
3229: _relatedType.addField(embeddedField);
3230:
3231: // XXX: todo ...
3232: // validateAttributeOverrides(_field, attributeOverridesAnn, type);
3233:
3234: Table sourceTable = _relatedType.getTable();
3235:
3236: HashMap<String, Column> embeddedColumns = new HashMap<String, Column>();
3237: HashMap<String, String> fieldNameByColumn = new HashMap<String, String>();
3238:
3239: for (EmbeddedSubField subField : embeddedField
3240: .getSubFields()) {
3241: String embeddedFieldName = subField.getName();
3242:
3243: String columnName = toSqlName(embeddedFieldName);
3244: boolean notNull = false;
3245: boolean unique = false;
3246:
3247: if (attOverridesAnn != null) {
3248: for (int j = 0; j < attOverridesAnn.length; j++) {
3249:
3250: if (embeddedFieldName
3251: .equals(((JAnnotation) attOverridesAnn[j])
3252: .getString("name"))) {
3253:
3254: JAnnotation columnAnn = ((JAnnotation) attOverridesAnn[j])
3255: .getAnnotation("column");
3256:
3257: if (columnAnn != null) {
3258: columnName = columnAnn
3259: .getString("name");
3260: notNull = !columnAnn
3261: .getBoolean("nullable");
3262: unique = columnAnn.getBoolean("unique");
3263:
3264: subField.getColumn()
3265: .setName(columnName);
3266: subField.getColumn()
3267: .setNotNull(notNull);
3268: subField.getColumn().setUnique(unique);
3269: }
3270: }
3271: }
3272: }
3273:
3274: /*
3275: Type amberType = _persistenceUnit.createType(fields.get(i).getJavaType().getName());
3276:
3277: Column column = sourceTable.createColumn(columnName, amberType);
3278:
3279: column.setNotNull(notNull);
3280: column.setUnique(unique);
3281:
3282: embeddedColumns.put(columnName, column);
3283: fieldNameByColumn.put(columnName, embeddedFieldName);
3284: */
3285: }
3286:
3287: /*
3288: embeddedField.setEmbeddedColumns(embeddedColumns);
3289: embeddedField.setFieldNameByColumn(fieldNameByColumn);
3290: */
3291:
3292: embeddedField.init();
3293: }
3294: }
3295:
3296: /**
3297: * completes for dependent
3298: */
3299: class SqlResultSetMappingCompletion extends Completion {
3300: private String _name;
3301: private Object _entities[];
3302: private Object _columns[];
3303:
3304: SqlResultSetMappingCompletion(RelatedType type, String name,
3305: Object entities[], Object columns[]) {
3306: super (type);
3307:
3308: _name = name;
3309: _entities = entities;
3310: _columns = columns;
3311: }
3312:
3313: void complete() throws ConfigException {
3314: addSqlResultSetMapping(_name, _entities, _columns);
3315: }
3316: }
3317:
3318: /**
3319: * completes for link
3320: */
3321: class AttributeOverrideCompletion extends Completion {
3322: private JClass _type;
3323:
3324: AttributeOverrideCompletion(RelatedType relatedType, JClass type) {
3325: super (relatedType);
3326:
3327: _type = type;
3328: }
3329:
3330: void complete() throws ConfigException {
3331: getInternalAttributeOverrideConfig(_type, _annotationCfg);
3332: JAnnotation attributeOverrideAnn = _annotationCfg
3333: .getAnnotation();
3334:
3335: boolean hasAttributeOverride = (attributeOverrideAnn != null);
3336:
3337: JAnnotation attributeOverridesAnn = _type
3338: .getAnnotation(AttributeOverrides.class);
3339:
3340: ArrayList<AttributeOverrideConfig> attributeOverrideList = null;
3341:
3342: EntityConfig entityConfig = getEntityConfig(_type.getName());
3343:
3344: if (entityConfig != null)
3345: attributeOverrideList = entityConfig
3346: .getAttributeOverrideList();
3347:
3348: boolean hasAttributeOverrides = false;
3349:
3350: if ((attributeOverrideList != null)
3351: && (attributeOverrideList.size() > 0)) {
3352: hasAttributeOverrides = true;
3353: } else if (attributeOverridesAnn != null)
3354: hasAttributeOverrides = true;
3355:
3356: if (hasAttributeOverride && hasAttributeOverrides)
3357: throw new ConfigException(
3358: L
3359: .l(
3360: "{0} may not have both @AttributeOverride and @AttributeOverrides",
3361: _type));
3362:
3363: if (attributeOverrideList == null)
3364: attributeOverrideList = new ArrayList<AttributeOverrideConfig>();
3365:
3366: if (hasAttributeOverride) {
3367: // Convert annotation to configuration.
3368:
3369: AttributeOverrideConfig attOverrideConfig = convertAttributeOverrideAnnotationToConfig(attributeOverrideAnn);
3370:
3371: attributeOverrideList.add(attOverrideConfig);
3372: } else if (hasAttributeOverrides) {
3373: if (attributeOverrideList.size() > 0) {
3374: // OK: attributeOverrideList came from orm.xml
3375: } else {
3376: // Convert annotations to configurations.
3377:
3378: Object attOverridesAnn[] = (Object[]) attributeOverridesAnn
3379: .get("value");
3380:
3381: AttributeOverrideConfig attOverrideConfig;
3382:
3383: for (int i = 0; i < attOverridesAnn.length; i++) {
3384: attOverrideConfig = convertAttributeOverrideAnnotationToConfig((JAnnotation) attOverridesAnn[i]);
3385:
3386: attributeOverrideList.add(attOverrideConfig);
3387: }
3388: }
3389: }
3390:
3391: // jpa/0ge8, jpa/0ge9, jpa/0gea
3392: // Fields which have not been overridden are added to the
3393: // entity subclass. This makes the columns to be properly
3394: // created at each entity table -- not the mapped superclass
3395: // table, even because the parent might not have a valid table.
3396:
3397: RelatedType parent = _relatedType.getParentType();
3398:
3399: ArrayList<AmberField> fields = parent.getFields();
3400:
3401: for (AmberField field : fields) {
3402: String fieldName = field.getName();
3403:
3404: AttributeOverrideConfig attOverrideConfig = null;
3405:
3406: int i = 0;
3407:
3408: for (; i < attributeOverrideList.size(); i++) {
3409: attOverrideConfig = attributeOverrideList.get(i);
3410:
3411: if (fieldName.equals(attOverrideConfig.getName())) {
3412: break;
3413: }
3414: }
3415:
3416: if (i < attributeOverrideList.size())
3417: continue;
3418:
3419: if (field instanceof PropertyField) {
3420: Column column = ((PropertyField) field).getColumn();
3421:
3422: // jpa/0ge8, jpa/0gea
3423: // Creates the missing attribute override config.
3424: attOverrideConfig = createAttributeOverrideConfig(
3425: fieldName, column.getName(), !column
3426: .isNotNull(), column.isUnique());
3427:
3428: attributeOverrideList.add(attOverrideConfig);
3429: }
3430: }
3431:
3432: // jpa/0ge8, jpa/0ge9
3433: // Similar code to create any missing configuration for keys.
3434:
3435: com.caucho.amber.field.Id parentId = parent.getId();
3436:
3437: // jpa/0ge6
3438: if (parentId != null) {
3439: ArrayList<IdField> keys = parentId.getKeys();
3440:
3441: for (IdField field : keys) {
3442: String fieldName = field.getName();
3443:
3444: AttributeOverrideConfig attOverrideConfig = null;
3445:
3446: int i = 0;
3447:
3448: for (; i < attributeOverrideList.size(); i++) {
3449: attOverrideConfig = attributeOverrideList
3450: .get(i);
3451:
3452: if (fieldName.equals(attOverrideConfig
3453: .getName())) {
3454: break;
3455: }
3456: }
3457:
3458: if (i < attributeOverrideList.size())
3459: continue;
3460:
3461: if (field instanceof KeyPropertyField) {
3462: try {
3463: if (_relatedType.isFieldAccess())
3464: introspectIdField(_persistenceUnit,
3465: _relatedType, null, parent
3466: .getBeanClass(), null,
3467: null);
3468: else
3469: introspectIdMethod(_persistenceUnit,
3470: _relatedType, null, parent
3471: .getBeanClass(), null,
3472: null);
3473: } catch (SQLException e) {
3474: throw ConfigException.create(e);
3475: }
3476:
3477: field = _relatedType.getId().getKeys().get(0);
3478:
3479: Column column = ((KeyPropertyField) field)
3480: .getColumn();
3481:
3482: // jpa/0ge8, jpa/0ge9, jpa/0gea
3483: // Creates the missing attribute override config.
3484: attOverrideConfig = createAttributeOverrideConfig(
3485: fieldName, column.getName(), !column
3486: .isNotNull(), column.isUnique());
3487:
3488: attributeOverrideList.add(attOverrideConfig);
3489: }
3490: }
3491: }
3492:
3493: // Overrides fields from MappedSuperclass.
3494:
3495: Table sourceTable = _relatedType.getTable();
3496:
3497: for (int i = 0; i < attributeOverrideList.size(); i++) {
3498:
3499: AttributeOverrideConfig attOverrideConfig = attributeOverrideList
3500: .get(i);
3501:
3502: String entityFieldName;
3503: String columnName;
3504: boolean notNull = false;
3505: boolean unique = false;
3506:
3507: Type amberType = null;
3508:
3509: for (int j = 0; j < fields.size(); j++) {
3510:
3511: AmberField field = fields.get(j);
3512:
3513: if (!(field instanceof PropertyField)) {
3514: // jpa/0ge3: relationship fields are fully mapped in the
3515: // mapped superclass, i.e., are not included in @AttributeOverrides
3516: // and can be added to the entity right away.
3517:
3518: // Adds only once.
3519: if (i == 0) {
3520: _relatedType
3521: .addMappedSuperclassField(field);
3522: }
3523:
3524: continue;
3525: }
3526:
3527: entityFieldName = field.getName();
3528:
3529: columnName = toSqlName(entityFieldName);
3530:
3531: if (entityFieldName.equals(attOverrideConfig
3532: .getName())) {
3533:
3534: ColumnConfig columnConfig = attOverrideConfig
3535: .getColumn();
3536:
3537: if (columnConfig != null) {
3538: columnName = columnConfig.getName();
3539: notNull = !columnConfig.getNullable();
3540: unique = columnConfig.getUnique();
3541: amberType = _persistenceUnit
3542: .createType(field.getJavaType()
3543: .getName());
3544:
3545: Column column = sourceTable.createColumn(
3546: columnName, amberType);
3547:
3548: column.setNotNull(notNull);
3549: column.setUnique(unique);
3550:
3551: PropertyField overriddenField = new PropertyField(
3552: field.getSourceType(), field
3553: .getName());
3554:
3555: overriddenField
3556: .setType(((PropertyField) field)
3557: .getType());
3558: overriddenField.setLazy(field.isLazy());
3559: overriddenField.setColumn(column);
3560:
3561: _relatedType
3562: .addMappedSuperclassField(overriddenField);
3563: }
3564: }
3565: }
3566:
3567: if (_relatedType.getId() != null) {
3568: ArrayList<IdField> keys = _relatedType.getId()
3569: .getKeys();
3570:
3571: for (int j = 0; j < keys.size(); j++) {
3572:
3573: IdField field = keys.get(j);
3574:
3575: entityFieldName = field.getName();
3576:
3577: columnName = toSqlName(entityFieldName);
3578:
3579: if (entityFieldName.equals(attOverrideConfig
3580: .getName())) {
3581:
3582: ColumnConfig columnConfig = attOverrideConfig
3583: .getColumn();
3584:
3585: if (columnConfig != null) {
3586: columnName = columnConfig.getName();
3587: notNull = !columnConfig.getNullable();
3588: unique = columnConfig.getUnique();
3589: amberType = _persistenceUnit
3590: .createType(field.getJavaType()
3591: .getName());
3592:
3593: Column column = sourceTable
3594: .createColumn(columnName,
3595: amberType);
3596:
3597: column.setNotNull(notNull);
3598: column.setUnique(unique);
3599:
3600: if (field instanceof KeyPropertyField) {
3601: KeyPropertyField overriddenField = new KeyPropertyField(
3602: (RelatedType) field
3603: .getSourceType(),
3604: field.getName());
3605:
3606: overriddenField.setGenerator(field
3607: .getGenerator());
3608: overriddenField.setColumn(column);
3609:
3610: // XXX: needs to handle compound pk with @AttributeOverride ???
3611: if (keys.size() == 1) {
3612: keys.remove(0);
3613: keys.add(overriddenField);
3614: _relatedType
3615: .setId(new com.caucho.amber.field.Id(
3616: _relatedType,
3617: keys));
3618: }
3619: }
3620: }
3621: }
3622: }
3623: }
3624: }
3625: }
3626: }
3627:
3628: void getInternalEmbeddableConfig(JClass type,
3629: AnnotationConfig annotationCfg) {
3630: annotationCfg.reset(type, Embeddable.class);
3631:
3632: EmbeddableConfig embeddableConfig = null;
3633:
3634: if (_embeddableConfigMap != null)
3635: embeddableConfig = _embeddableConfigMap.get(type.getName());
3636:
3637: annotationCfg.setConfig(embeddableConfig);
3638: }
3639:
3640: void getInternalEntityConfig(JClass type,
3641: AnnotationConfig annotationCfg) {
3642: annotationCfg.reset(type, Entity.class);
3643:
3644: EntityConfig entityConfig = getEntityConfig(type.getName());
3645:
3646: annotationCfg.setConfig(entityConfig);
3647: }
3648:
3649: void getInternalMappedSuperclassConfig(JClass type,
3650: AnnotationConfig annotationCfg) {
3651: annotationCfg.reset(type, MappedSuperclass.class);
3652:
3653: MappedSuperclassConfig mappedSuperConfig = getMappedSuperclassConfig(type
3654: .getName());
3655:
3656: annotationCfg.setConfig(mappedSuperConfig);
3657: }
3658:
3659: void getInternalEntityListenersConfig(JClass type,
3660: AnnotationConfig annotationCfg) {
3661: annotationCfg.reset(type, EntityListeners.class);
3662:
3663: EntityConfig entityConfig = getEntityConfig(type.getName());
3664:
3665: if (entityConfig == null)
3666: return;
3667:
3668: annotationCfg.setConfig(entityConfig.getEntityListeners());
3669: }
3670:
3671: void getInternalExcludeDefaultListenersConfig(JClass type,
3672: AnnotationConfig annotationCfg) {
3673: annotationCfg.reset(type, ExcludeDefaultListeners.class);
3674:
3675: MappedSuperclassConfig entityConfig = getInternalMappedSuperclassOrEntityConfig(type
3676: .getName());
3677:
3678: if (entityConfig == null)
3679: return;
3680:
3681: if (entityConfig.getExcludeDefaultListeners())
3682: annotationCfg.setConfig(entityConfig
3683: .getExcludeDefaultListeners());
3684: }
3685:
3686: void getInternalExcludeSuperclassListenersConfig(JClass type,
3687: AnnotationConfig annotationCfg) {
3688: annotationCfg.reset(type, ExcludeSuperclassListeners.class);
3689:
3690: MappedSuperclassConfig entityConfig = getInternalMappedSuperclassOrEntityConfig(type
3691: .getName());
3692:
3693: if (entityConfig == null)
3694: return;
3695:
3696: if (entityConfig.getExcludeSuperclassListeners())
3697: annotationCfg.setConfig(entityConfig
3698: .getExcludeSuperclassListeners());
3699: }
3700:
3701: void getInternalInheritanceConfig(JClass type,
3702: AnnotationConfig annotationCfg) {
3703: annotationCfg.reset(type, Inheritance.class);
3704:
3705: EntityConfig entityConfig = getEntityConfig(type.getName());
3706:
3707: if (entityConfig != null) {
3708: annotationCfg.setConfig(entityConfig.getInheritance());
3709: }
3710: }
3711:
3712: void getInternalNamedQueryConfig(JClass type,
3713: AnnotationConfig annotationCfg) {
3714: annotationCfg.reset(type, NamedQuery.class);
3715:
3716: EntityConfig entityConfig = getEntityConfig(type.getName());
3717:
3718: if (entityConfig != null) {
3719: annotationCfg.setConfig(entityConfig.getNamedQuery());
3720: }
3721: }
3722:
3723: void getInternalNamedNativeQueryConfig(JClass type,
3724: AnnotationConfig annotationCfg) {
3725: annotationCfg.reset(type, NamedNativeQuery.class);
3726:
3727: EntityConfig entityConfig = getEntityConfig(type.getName());
3728:
3729: if (entityConfig != null) {
3730: annotationCfg.setConfig(entityConfig.getNamedNativeQuery());
3731: }
3732: }
3733:
3734: void getInternalSqlResultSetMappingConfig(JClass type,
3735: AnnotationConfig annotationCfg) {
3736: annotationCfg.reset(type, SqlResultSetMapping.class);
3737:
3738: EntityConfig entityConfig = getEntityConfig(type.getName());
3739:
3740: if (entityConfig != null) {
3741: annotationCfg.setConfig(entityConfig
3742: .getSqlResultSetMapping());
3743: }
3744: }
3745:
3746: void getInternalTableConfig(JClass type,
3747: AnnotationConfig annotationCfg) {
3748: annotationCfg.reset(type, javax.persistence.Table.class);
3749:
3750: EntityConfig entityConfig = getEntityConfig(type.getName());
3751:
3752: if (entityConfig != null) {
3753: annotationCfg.setConfig(entityConfig.getTable());
3754: }
3755: }
3756:
3757: void getInternalSecondaryTableConfig(JClass type,
3758: AnnotationConfig annotationCfg) {
3759: annotationCfg.reset(type, SecondaryTable.class);
3760:
3761: EntityConfig entityConfig = getEntityConfig(type.getName());
3762:
3763: if (entityConfig != null) {
3764: annotationCfg.setConfig(entityConfig.getSecondaryTable());
3765: }
3766: }
3767:
3768: void getInternalIdClassConfig(JClass type,
3769: AnnotationConfig annotationCfg) {
3770: annotationCfg.reset(type, IdClass.class);
3771:
3772: MappedSuperclassConfig entityConfig = getInternalMappedSuperclassOrEntityConfig(type
3773: .getName());
3774:
3775: if (entityConfig == null)
3776: return;
3777:
3778: annotationCfg.setConfig(entityConfig.getIdClass());
3779: }
3780:
3781: void getInternalPrimaryKeyJoinColumnConfig(JClass type,
3782: AnnotationConfig annotationCfg) {
3783: annotationCfg.reset(type, PrimaryKeyJoinColumn.class);
3784:
3785: EntityConfig entityConfig = getEntityConfig(type.getName());
3786:
3787: if (entityConfig != null) {
3788: annotationCfg.setConfig(entityConfig
3789: .getPrimaryKeyJoinColumn());
3790: }
3791: }
3792:
3793: void getInternalDiscriminatorColumnConfig(JClass type,
3794: AnnotationConfig annotationCfg) {
3795: annotationCfg.reset(type, DiscriminatorColumn.class);
3796:
3797: EntityConfig entityConfig = getEntityConfig(type.getName());
3798:
3799: if (entityConfig != null) {
3800: annotationCfg.setConfig(entityConfig
3801: .getDiscriminatorColumn());
3802: }
3803: }
3804:
3805: void getInternalOneToOneConfig(JClass type,
3806: JAccessibleObject field, String fieldName,
3807: AnnotationConfig annotationCfg) {
3808: annotationCfg.reset(field, OneToOne.class);
3809:
3810: MappedSuperclassConfig entityConfig = getInternalMappedSuperclassOrEntityConfig(type
3811: .getName());
3812:
3813: if (entityConfig == null)
3814: return;
3815:
3816: AttributesConfig attributes = entityConfig.getAttributes();
3817:
3818: if (attributes != null) {
3819: OneToOneConfig oneToOne = attributes.getOneToOne(fieldName);
3820:
3821: annotationCfg.setConfig(oneToOne);
3822: }
3823: }
3824:
3825: void getInternalOneToManyConfig(JClass type,
3826: JAccessibleObject field, String fieldName,
3827: AnnotationConfig annotationCfg) {
3828: annotationCfg.reset(field, OneToMany.class);
3829:
3830: MappedSuperclassConfig entityConfig = getInternalMappedSuperclassOrEntityConfig(type
3831: .getName());
3832:
3833: if (entityConfig == null)
3834: return;
3835:
3836: AttributesConfig attributes = entityConfig.getAttributes();
3837:
3838: if (attributes != null) {
3839: OneToManyConfig oneToMany = attributes
3840: .getOneToMany(fieldName);
3841:
3842: annotationCfg.setConfig(oneToMany);
3843: }
3844: }
3845:
3846: void getInternalManyToOneConfig(JClass type,
3847: JAccessibleObject field, String fieldName,
3848: AnnotationConfig annotationCfg) {
3849: annotationCfg.reset(field, ManyToOne.class);
3850:
3851: MappedSuperclassConfig entityConfig = getInternalMappedSuperclassOrEntityConfig(type
3852: .getName());
3853:
3854: if (entityConfig == null)
3855: return;
3856:
3857: AttributesConfig attributes = entityConfig.getAttributes();
3858:
3859: if (attributes != null) {
3860: ManyToOneConfig manyToOne = attributes
3861: .getManyToOne(fieldName);
3862:
3863: annotationCfg.setConfig(manyToOne);
3864: }
3865: }
3866:
3867: void getInternalManyToManyConfig(JClass type,
3868: JAccessibleObject field, String fieldName,
3869: AnnotationConfig annotationCfg) {
3870: annotationCfg.reset(field, ManyToMany.class);
3871:
3872: MappedSuperclassConfig entityConfig = getInternalMappedSuperclassOrEntityConfig(type
3873: .getName());
3874:
3875: if (entityConfig == null)
3876: return;
3877:
3878: AttributesConfig attributes = entityConfig.getAttributes();
3879:
3880: if (attributes != null) {
3881: ManyToManyConfig manyToMany = attributes
3882: .getManyToMany(fieldName);
3883:
3884: annotationCfg.setConfig(manyToMany);
3885: }
3886: }
3887:
3888: void getInternalIdConfig(JClass type, JAccessibleObject method,
3889: String fieldName, AnnotationConfig annotationCfg) {
3890: annotationCfg.reset(method, javax.persistence.Id.class);
3891:
3892: MappedSuperclassConfig mappedSuperclassOrEntityConfig = getInternalMappedSuperclassOrEntityConfig(type
3893: .getName());
3894:
3895: if (mappedSuperclassOrEntityConfig == null)
3896: return;
3897:
3898: AttributesConfig attributes = mappedSuperclassOrEntityConfig
3899: .getAttributes();
3900:
3901: if (attributes != null) {
3902: IdConfig id = attributes.getId(fieldName);
3903:
3904: annotationCfg.setConfig(id);
3905: }
3906: }
3907:
3908: void getInternalCallbackConfig(int callback, JClass type,
3909: JAccessibleObject method, String fieldName,
3910: AnnotationConfig annotationCfg) {
3911: annotationCfg.reset(method,
3912: ListenerType.CALLBACK_CLASS[callback]);
3913:
3914: MappedSuperclassConfig entityConfig = getInternalMappedSuperclassOrEntityConfig(type
3915: .getName());
3916:
3917: if (entityConfig == null)
3918: return;
3919:
3920: AbstractListenerConfig callbackConfig;
3921:
3922: switch (callback) {
3923: case Listener.PRE_PERSIST:
3924: callbackConfig = entityConfig.getPrePersist();
3925: break;
3926: case Listener.POST_PERSIST:
3927: callbackConfig = entityConfig.getPostPersist();
3928: break;
3929: case Listener.PRE_REMOVE:
3930: callbackConfig = entityConfig.getPreRemove();
3931: break;
3932: case Listener.POST_REMOVE:
3933: callbackConfig = entityConfig.getPostRemove();
3934: break;
3935: case Listener.PRE_UPDATE:
3936: callbackConfig = entityConfig.getPreUpdate();
3937: break;
3938: case Listener.POST_UPDATE:
3939: callbackConfig = entityConfig.getPostUpdate();
3940: break;
3941: case Listener.POST_LOAD:
3942: callbackConfig = entityConfig.getPostLoad();
3943: break;
3944: default:
3945: return;
3946: }
3947:
3948: if (callbackConfig == null)
3949: return;
3950:
3951: if (callbackConfig.getMethodName().equals(method.getName()))
3952: annotationCfg.setConfig(callbackConfig);
3953: }
3954:
3955: void getInternalEmbeddedIdConfig(JClass type,
3956: JAccessibleObject method, String fieldName,
3957: AnnotationConfig annotationCfg) {
3958: annotationCfg.reset(method, EmbeddedId.class);
3959: }
3960:
3961: void getInternalVersionConfig(JClass type,
3962: JAccessibleObject method, String fieldName,
3963: AnnotationConfig annotationCfg) {
3964: annotationCfg.reset(method, Version.class);
3965: }
3966:
3967: void getInternalJoinColumnConfig(JClass type,
3968: JAccessibleObject field, String fieldName,
3969: AnnotationConfig annotationCfg) {
3970: annotationCfg.reset(field, JoinColumn.class);
3971: }
3972:
3973: void getInternalJoinTableConfig(JClass type,
3974: JAccessibleObject field, String fieldName,
3975: AnnotationConfig annotationCfg) {
3976: annotationCfg.reset(field, JoinTable.class);
3977: }
3978:
3979: void getInternalMapKeyConfig(JClass type, JAccessibleObject field,
3980: String fieldName, AnnotationConfig annotationCfg) {
3981: annotationCfg.reset(field, MapKey.class);
3982: }
3983:
3984: void getInternalAttributeOverrideConfig(JClass type,
3985: AnnotationConfig annotationCfg) {
3986: annotationCfg.reset(type, AttributeOverride.class);
3987: }
3988:
3989: private MappedSuperclassConfig getInternalMappedSuperclassOrEntityConfig(
3990: String name) {
3991: MappedSuperclassConfig mappedSuperclassConfig = null;
3992:
3993: mappedSuperclassConfig = getEntityConfig(name);
3994:
3995: if (mappedSuperclassConfig != null)
3996: return mappedSuperclassConfig;
3997:
3998: mappedSuperclassConfig = getMappedSuperclassConfig(name);
3999:
4000: return mappedSuperclassConfig;
4001: }
4002:
4003: private static AttributeOverrideConfig convertAttributeOverrideAnnotationToConfig(
4004: JAnnotation attOverrideAnn) {
4005: JAnnotation columnAnn = attOverrideAnn.getAnnotation("column");
4006:
4007: return createAttributeOverrideConfig(attOverrideAnn
4008: .getString("name"), columnAnn.getString("name"),
4009: columnAnn.getBoolean("nullable"), columnAnn
4010: .getBoolean("unique"));
4011: }
4012:
4013: private static AttributeOverrideConfig createAttributeOverrideConfig(
4014: String name, String columnName, boolean isNullable,
4015: boolean isUnique) {
4016: AttributeOverrideConfig attOverrideConfig = new AttributeOverrideConfig();
4017:
4018: attOverrideConfig.setName(name);
4019:
4020: ColumnConfig columnConfig = new ColumnConfig();
4021:
4022: columnConfig.setName(columnName);
4023: columnConfig.setNullable(isNullable);
4024: columnConfig.setUnique(isUnique);
4025:
4026: attOverrideConfig.setColumn(columnConfig);
4027:
4028: return attOverrideConfig;
4029: }
4030: }
|