From bcb432ee3c7d3d9f9d54bd8cced5884e0c2a0386 Mon Sep 17 00:00:00 2001 From: David Avendasora Date: Sat, 8 Jun 2013 03:47:12 +0800 Subject: [PATCH] Add UUID CopyType, Fix Generics and expectations that destination objects of reference-copied relationships implement ERXCopyable - they don't need to. --- .../er/extensions/eof/ERXCopyable.java | 271 ++++++++++-------- 1 file changed, 150 insertions(+), 121 deletions(-) diff --git a/Frameworks/Core/ERExtensions/Sources/er/extensions/eof/ERXCopyable.java b/Frameworks/Core/ERExtensions/Sources/er/extensions/eof/ERXCopyable.java index 90ef0dfe78b..37af79e100d 100644 --- a/Frameworks/Core/ERExtensions/Sources/er/extensions/eof/ERXCopyable.java +++ b/Frameworks/Core/ERExtensions/Sources/er/extensions/eof/ERXCopyable.java @@ -1,5 +1,7 @@ package er.extensions.eof; +import java.util.UUID; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -12,6 +14,7 @@ import com.webobjects.eocontrol.EOEditingContext; import com.webobjects.eocontrol.EOEnterpriseObject; import com.webobjects.eocontrol.EOGlobalID; +import com.webobjects.eocontrol.EORelationshipManipulation; import com.webobjects.foundation.NSArray; import com.webobjects.foundation.NSDictionary; import com.webobjects.foundation.NSMutableArray; @@ -145,7 +148,7 @@ * @author Sacha Mallais * @author David Avendasora */ -public interface ERXCopyable extends ERXEnterpriseObject { +public interface ERXCopyable> extends ERXEnterpriseObject { /** *

@@ -169,7 +172,7 @@ public enum CopyType { * dictionary. This setting does not copy the {@code original}'s * value. It sets the {@code copy}'s value to null. */ - NULLIFY("Nullify"), + NULLIFY("Nullify", new NSArray>(EOAttribute.class, EORelationship.class)), /** * For attributes and relationships. Stored as " @@ -182,7 +185,7 @@ public enum CopyType { * non-flattening, to-many relationship, the destination objects will be * moved from the {@code original} to the {@code copy}. */ - REFERENCE("Reference"), + REFERENCE("Reference", new NSArray>(EOAttribute.class, EORelationship.class)), /** * For relationships only. Stored as " @@ -191,7 +194,7 @@ public enum CopyType { * destination {@link ERXCopyable} objects will be made and all of the * original's attributes and relationships will be reference copied. */ - SHALLOW("Shallow"), + SHALLOW("Shallow", new NSArray>(EORelationship.class)), /** * For relationships only. Stored as " @@ -200,7 +203,7 @@ public enum CopyType { * {@link ERXCopyable} objects using their implementation of the * {@link #duplicate(NSMutableDictionary)} method. */ - DEEP("Deep"), + DEEP("Deep", new NSArray>(EORelationship.class)), /** * For attributes only. Stored as " @@ -210,18 +213,46 @@ public enum CopyType { * value to the current date and time using * {@code new NSTimestamp()} */ - CURRENT_TIMESTAMP("CurrentTimestamp"); + CURRENT_TIMESTAMP("CurrentTimestamp", new NSArray>(EOAttribute.class)), + + /** + * For attributes only. Stored as " + * {@code ERXCopyable.CopyType = UUID;}" in the {@link EOAttribute}'s + * UserInfo dictionary. This setting does not copy the + * {@code original}'s value. It sets the {@code copy}'s value to a newly + * generated {@link java.util.UUID} using + * {@link java.util.UUID#randomUUID()} + */ + UUID("UUID", new NSArray>(EOAttribute.class)); private final String _type; + private final NSArray> _validPropertyClasses; - CopyType(String type) { + CopyType(String type, NSArray> propertyTypes) { _type = type; + _validPropertyClasses = propertyTypes; } public String type() { return _type; } + /** + * @param property + * the attribute or relationship being copied + * @return an array of the valid {@link CopyType}s for the passed-in + * {@link EOProperty} + */ + public static NSArray copyTypesFor(EOProperty property) { + NSMutableArray validCopyTypes = new NSMutableArray(); + for (CopyType copyType : values()) { + if (copyType.validPropertyClasses().contains(property.getClass())) { + validCopyTypes.add(copyType); + } + } + return validCopyTypes.immutableClone(); + } + /** * @param typeAsString * a String to match (case-insensitive) to a {@link CopyType} @@ -234,7 +265,7 @@ public static CopyType get(String typeAsString) { CopyType copyType = null; if (typeAsString != null) { for (CopyType ct : CopyType.values()) { - if (typeAsString.equalsIgnoreCase(ct.type())) { + if (typeAsString.equalsIgnoreCase(ct.type()) || typeAsString.equalsIgnoreCase(ct.name())) { copyType = ct; break; } @@ -242,6 +273,10 @@ public static CopyType get(String typeAsString) { } return copyType; } + + public NSArray> validPropertyClasses() { + return _validPropertyClasses; + } } /** @@ -287,7 +322,6 @@ public static class DefaultImplementation { * * @param * the Type of the {@code source} - * * @param copiedObjects * the copied objects keyed on the EOGlobalID of the object * the copy was made from. @@ -295,14 +329,14 @@ public static class DefaultImplementation { * the {@code ERXCopyable} to copy * @return a copy of this object */ - @SuppressWarnings("unchecked") - public static T copy(NSMutableDictionary> copiedObjects, T source) { + public static > T copy(NSMutableDictionary> copiedObjects, T source) { EOGlobalID globalID = source.editingContext().globalIDForObject(source); ERXCopyable.copyLogger.debug("Copying object " + source.userPresentableDescription()); + @SuppressWarnings("unchecked") T copy = (T) copiedObjects.objectForKey(globalID); if (copy == null) { ERXCopyable.copyLogger.debug("Creating duplicate."); - copy = (T) source.duplicate(copiedObjects); + copy = source.duplicate(copiedObjects); copiedObjects.setObjectForKey(copy, globalID); } else { @@ -324,7 +358,7 @@ public static T copy(NSMutableDictionary T duplicate(NSMutableDictionary> copiedObjects, T source) { + public static > T duplicate(NSMutableDictionary> copiedObjects, T source) { T duplicate = Utility.deepCopy(copiedObjects, source); return duplicate; } @@ -413,7 +447,7 @@ public static EOEntity entity(T enterpriseObject * the newly instantiated copy of source that needs to have * its relationships cleaned */ - public static void cleanRelationships(T source, T destination) { + public static > void cleanRelationships(T source, T destination) { ERXCopyable.copyLogger.debug("Cleaning related objects in copy of " + source); EOEditingContext editingContext = source.editingContext(); EOEntity entity = Utility.entity(source); @@ -421,13 +455,11 @@ public static void cleanRelationships(T source, T destin // To-Many relationships for (String relationshipName : destination.toManyRelationshipKeys()) { @SuppressWarnings("unchecked") - NSArray relatedObjects = (NSArray) destination.valueForKey(relationshipName); - + NSArray relatedObjects = (NSArray) destination.valueForKey(relationshipName); if (relatedObjects.count() > 0) { entity.relationshipNamed(relationshipName); ERXCopyable.copyLogger.debug("Removing objects in to-many relationship " + relationshipName); - for (ERXCopyable relatedObject : relatedObjects) { - + for (ERXEnterpriseObject relatedObject : relatedObjects) { destination.removeObjectFromBothSidesOfRelationshipWithKey(relatedObject, relationshipName); if (relatedObject.isNewObject()) { editingContext.deleteObject(relatedObject); @@ -438,7 +470,7 @@ public static void cleanRelationships(T source, T destin // To-one relationships for (String relationshipName : destination.toOneRelationshipKeys()) { - ERXCopyable relatedObject = (ERXCopyable) destination.valueForKey(relationshipName); + ERXEnterpriseObject relatedObject = (ERXEnterpriseObject) destination.valueForKey(relationshipName); if (relatedObject != null) { ERXCopyable.copyLogger.debug("Removing object in to-one relationship " + relationshipName); destination.removeObjectFromBothSidesOfRelationshipWithKey(relatedObject, relationshipName); @@ -468,7 +500,7 @@ public static void cleanRelationships(T source, T destin * @param destination * object to copy attribute values to */ - public static void copyClassAttributes(T source, T destination) { + public static > void copyClassAttributes(T source, T destination) { EOEntity entity = Utility.entity(source); ERXCopyable.copyLogger.debug("Copying all attributes for " + source.userPresentableDescription()); NSArray attributes = Utility.classAttributes(entity); @@ -488,7 +520,7 @@ public static void copyClassAttributes(T source, T desti * the {@link EOAttribute} that should have its value copied * @since Feb 10, 2013 */ - public static void copyAttribute(T source, T destination, EOAttribute attribute) { + public static > void copyAttribute(T source, T destination, EOAttribute attribute) { String attributeName = attribute.name(); Object sourceValue = source.storedValueForKey(attributeName); NSArray exposedPKAndFKAttributes = Utility.exposedPKAndFKAttributes(source); @@ -523,7 +555,7 @@ public static void copyAttribute(T source, T destination * the subclass of {@code ERXCopyable} to copy * @return a copy of this object */ - public static T deepCopy(NSMutableDictionary> copiedObjects, T source) { + public static > T deepCopy(NSMutableDictionary> copiedObjects, T source) { ERXCopyable.copyLogger.debug("Making deep copy of " + source.userPresentableDescription()); @@ -559,7 +591,7 @@ public static T deepCopy(NSMutableDictionary void deepCopyClassRelationships(NSMutableDictionary> copiedObjects, T source, T destination) { + public static > void deepCopyClassRelationships(NSMutableDictionary> copiedObjects, T source, T destination) { ERXCopyable.copyLogger.debug("Deep copying relationships for " + source.userPresentableDescription()); EOEntity entity = Utility.entity(source); NSArray relationships = Utility.classRelationships(entity); @@ -617,7 +649,7 @@ public static synchronized NSArray classRelationships(EOEntity e * @param relationship * the {@link EORelationship} to copy */ - public static void deepCopyRelationship(NSMutableDictionary> copiedObjects, T source, T destination, EORelationship relationship) { + public static > void deepCopyRelationship(NSMutableDictionary> copiedObjects, T source, T destination, EORelationship relationship) { if (relationship.isToMany()) { Utility.deepCopyToManyRelationship(copiedObjects, source, destination, relationship); } @@ -629,6 +661,8 @@ public static void deepCopyRelationship(NSMutableDiction /** * @param * the Type of the {@code source} and {@code destination} + * @param + * the Type of the object for the {@code relationship} * @param copiedObjects * the copied objects keyed on the {@code EOGlobalID} of the * object the copy was made from @@ -641,16 +675,18 @@ public static void deepCopyRelationship(NSMutableDiction * @param relationship * the to-one {@link EORelationship} to copy */ - public static void deepCopyToOneRelationship(NSMutableDictionary> copiedObjects, T source, T destination, EORelationship relationship) { + public static , E extends ERXCopyable> void deepCopyToOneRelationship(NSMutableDictionary> copiedObjects, T source, T destination, EORelationship relationship) { String relationshipName = relationship.name(); EOEntity sourceEntity = relationship.entity(); String sourceEntityName = sourceEntity.name(); - ERXCopyable original = (ERXCopyable) source.valueForKey(relationshipName); + @SuppressWarnings("unchecked") + E original = (E) source.valueForKey(relationshipName); if (original != null) { ERXCopyable.copyLogger.debug("Copying to-one relationship " + sourceEntityName + "." + relationshipName); ERXCopyable.copyLogger.debug(" from " + source); ERXCopyable.copyLogger.debug("Copying " + original.userPresentableDescription()); - ERXCopyable copy = original.copy(copiedObjects); + + E copy = original.copy(copiedObjects); destination.addObjectToBothSidesOfRelationshipWithKey(copy, relationshipName); } } @@ -658,6 +694,8 @@ public static void deepCopyToOneRelationship(NSMutableDi /** * @param * the Type of the {@code source} and {@code destination} + * @param + * the Type of the objects for the {@code relationship} * @param copiedObjects * the copied objects keyed on the {@code EOGlobalID} of the * object the copy was made from @@ -670,7 +708,7 @@ public static void deepCopyToOneRelationship(NSMutableDi * @param relationship * the to-many {@link EORelationship} to copy */ - public static void deepCopyToManyRelationship(NSMutableDictionary> copiedObjects, T source, T destination, EORelationship relationship) { + public static , E extends ERXCopyable> void deepCopyToManyRelationship(NSMutableDictionary> copiedObjects, T source, T destination, EORelationship relationship) { String relationshipName = relationship.name(); String inverseRelationshipName = null; if (relationship.inverseRelationship() != null) { @@ -680,15 +718,15 @@ public static void deepCopyToManyRelationship(NSMutableD ERXCopyable.copyLogger.debug(" from " + source); @SuppressWarnings("unchecked") - NSArray originals = ((NSArray) source.valueForKey(relationshipName)).immutableClone(); + NSArray originals = ((NSArray) source.valueForKey(relationshipName)).immutableClone(); @SuppressWarnings("unchecked") - NSArray destinationInitialRelatedObjects = ((NSArray) destination.valueForKey(relationshipName)).immutableClone(); + NSArray destinationInitialRelatedObjects = ((NSArray) destination.valueForKey(relationshipName)).immutableClone(); ERXCopyable.copyLogger.debug("Copying " + originals.count() + " object(s) for relationship " + relationshipName); - try { - for (T original : originals) { - T copy = (T) original.copy(copiedObjects); - + for (E original : originals) { + try { + E copy = original.copy(copiedObjects); + /* * This is a tricky part. Making the copy in the previous line * may have already added objects to the relationship that we @@ -704,19 +742,19 @@ public static void deepCopyToManyRelationship(NSMutableD copy.addObjectToBothSidesOfRelationshipWithKey(destination, inverseRelationshipName); } } + } catch (ClassCastException e) { + String message = original.entityName() + + " does not impliment " + + ERXCopyable.class.getCanonicalName() + + ". If you are using the Standard mode, you must manually add the implements clause to the class delcaration in " + + original.getClass().getSimpleName() + + ".java. If you are using the \"Model\" mode you must have an 'ERXCopyable = Model' entry in " + + original.entityName() + + "'s UserInfo dictionary in the EOModel. (Originally thrown exception message: " + + e.getMessage() + ")"; + throw new RuntimeException(message, e); } } - catch (ClassCastException e) { - String message = source.entityName() - + " does not impliment " - + ERXCopyable.class.getCanonicalName() - + ". If you are using the Standard mode, you must manually add the implements clause to the class delcaration in " - + source.getClass().getSimpleName() - + ".java. If you are using the \"Model\" mode you must have an 'ERXCopyable = Model' entry in " - + source.entityName() - + "'s UserInfo dictionary in the EOModel."; - throw new ClassCastException(message); - } } /** @@ -733,7 +771,7 @@ public static void deepCopyToManyRelationship(NSMutableD * {@code source}'s {@link EOEntity} that are used in forming * {@link EORelationship}s. **/ - public static NSArray exposedPKandFKAttributeNames(T source) { + public static > NSArray exposedPKandFKAttributeNames(T source) { @SuppressWarnings("unchecked") NSArray attributeNames = (NSArray) exposedPKAndFKAttributes(source).valueForKey("name"); return attributeNames; @@ -746,14 +784,12 @@ public static NSArray exposedPKandFKAttributeNam * exposed primary- or foreign-keys and must be handled differently when * copying an object. * - * @param - * the Type of the {@code source} object * @param source * the subclass of {@code ERXCopyable} that will be copied * @return an array of attribute names from the {@code EOEntity} of * source that are used in forming relationships. **/ - public static synchronized NSArray exposedPKAndFKAttributes(T source) { + public static synchronized NSArray exposedPKAndFKAttributes(ERXEnterpriseObject source) { EOEntity entity = Utility.entity(source); String entityName = entity.name(); if (Utility._exposedPKAndFKAttributeDictionary == null) { @@ -812,23 +848,29 @@ public static synchronized NSArray classAttributes(EOEntity entity) * @return the {@code EOGlobalID} of the {@code enterpriseObject} * parameter */ - public static EOGlobalID globalIDForObject(ERXCopyable enterpriseObject) { + public static EOGlobalID globalIDForObject(ERXEnterpriseObject enterpriseObject) { EOGlobalID globalID = enterpriseObject.editingContext().globalIDForObject(enterpriseObject); return globalID; } /** - * This creates and returns a new instance of the same Entity as source. - * When an EO object is created it can already have some relationships - * and attributes set. These can come from to one relationships that are - * marked as 'owns destination' and also from the effects of - * awakeFromInsertion(). Preset attributes should be overwritten when - * all attributes are copied, but the relationships need some special - * handling. See the method - * {@link Utility#cleanRelationships(ERXCopyable, ERXCopyable)} for - * details on what is done. This method can be used when creating custom - * implementations of the - * {@link ERXCopyable#duplicate(NSMutableDictionary)} method. + * This creates and returns a new, completely empty instance of + * the same Entity as source. + *

+ * The reason that copying should use this method is because when an EO + * object is created it can already have some relationships and + * attributes set. These can come from to one relationships that are + * marked as 'owns destination' and also from awakeFromInsertion(). + * Preset/default attributes will be overwritten when all attributes are + * copied, but the relationships need some special handling. See the + * method {@link Utility#cleanRelationships(ERXCopyable, ERXCopyable)} + * for details on what is done. + *

+ * + *

+ * This method is for use in custom implementations of + * {@link ERXCopyable#duplicate(NSMutableDictionary)}. + *

* * @param * the Type of the {@code source} @@ -837,8 +879,7 @@ public static EOGlobalID globalIDForObject(ERXCopyable enterpriseObject) { * the subclass of {@code ERXCopyable} to copy * @return a new instance of the same Entity as source */ - public static T newInstance(T source) { - // ** require [valid_source] source != null; **/ + public static > T newInstance(T source) { ERXCopyable.copyLogger.debug("Making new instance of " + source.userPresentableDescription()); @SuppressWarnings("unchecked") T destination = (T) EOUtilities.createAndInsertInstance(source.editingContext(), source.entityName()); @@ -847,10 +888,9 @@ public static T newInstance(T source) { } /** - * Returns a copy of this object by reference. This is equivalent to - * return this; on an {@code ERXCopyable}. This method of - * copying is suitable for lookup list items and other objects which - * should never be duplicated. + * Returns a copy of this object by reference. This simply returns the + * receiver. This method of copying is suitable for lookup list / + * enumeration items and other objects which should never be duplicated. * * @param * the Type of the {@code source} @@ -876,7 +916,7 @@ public static T referenceCopy(T source) { * the subclass of {@code ERXCopyable} to copy * @return a copy of this object */ - public static T shallowCopy(T source) { + public static > T shallowCopy(T source) { ERXCopyable.copyLogger.debug("Making shallow copy of " + source); T copy = Utility.newInstance(source); Utility.copyClassAttributes(source, copy); @@ -885,10 +925,10 @@ public static T shallowCopy(T source) { } /** - * This copies related objects from the source {@code ERXCopyable} to - * the destination by reference. Only relationships which are class - * properties are copied. It can be used when creating custom - * implementations of the duplicate() method in ERXCopyable. + * This copies all objects for all class-property relationships from the + * {@code source} onto the {@code destination}. It can be used when + * creating custom implementations of + * {@link ERXCopyable#duplicate(NSMutableDictionary)}. * * @param * the Type of the {@code source} and {@code destination} @@ -899,7 +939,7 @@ public static T shallowCopy(T source) { * the subclass of {@code ERXCopyable} to copy attribute * values to */ - public static void referenceCopyClassRelationships(T source, T destination) { + public static > void referenceCopyClassRelationships(T source, T destination) { ERXCopyable.copyLogger.debug("Reference copying relationships for " + source); EOEntity entity = EOUtilities.entityForObject(source.editingContext(), source); for (EORelationship relationship : classRelationships(entity)) { @@ -922,7 +962,7 @@ public static void referenceCopyClassRelationshi * the {@link EORelationship} to copy from the {@code source} * to the {@code destination} */ - public static void referenceCopyRelationship(T source, T destination, EORelationship relationship) { + public static > void referenceCopyRelationship(T source, T destination, EORelationship relationship) { if (relationship.isToMany()) { Utility.referenceCopyToManyRelationship(source, destination, relationship); } @@ -948,7 +988,7 @@ public static void referenceCopyRelationship(T s * the subclass of {@code ERXCopyable} to copy to-one * relationships values to */ - public static void referenceCopyToOneClassRelationships(T source, T destination) { + public static > void referenceCopyToOneClassRelationships(T source, T destination) { ERXCopyable.copyLogger.debug("Reference copying all to-one relationships for " + source.userPresentableDescription()); EOEntity entity = Utility.entity(source); for (EORelationship relationship : classRelationships(entity)) { @@ -962,6 +1002,7 @@ public static void referenceCopyToOneClassRelationships( /** * @param * the Type of the {@code source} and {@code destination} + * @param * @param source * the subclass of {@code ERXCopyable} to copy the * relationship's value from @@ -972,12 +1013,13 @@ public static void referenceCopyToOneClassRelationships( * the {@link EORelationship} to copy from the {@code source} * to the {@code destination} */ - public static void referenceCopyToOneRelationship(T source, T destination, EORelationship relationship) { + public static , E extends ERXEnterpriseObject> void referenceCopyToOneRelationship(T source, T destination, EORelationship relationship) { String relationshipName = relationship.name(); - ERXEnterpriseObject sourceRelatedEO = (ERXEnterpriseObject) source.valueForKey(relationshipName); + @SuppressWarnings("unchecked") + E sourceRelatedEO = (E) source.valueForKey(relationshipName); if (sourceRelatedEO != null) { ERXCopyable.copyLogger.debug("Copying " + sourceRelatedEO.userPresentableDescription() + " object for relationship " + relationshipName); - ERXEnterpriseObject destinationRelatedEO = Utility.referenceCopy(sourceRelatedEO); + E destinationRelatedEO = Utility.referenceCopy(sourceRelatedEO); destination.addObjectToBothSidesOfRelationshipWithKey(destinationRelatedEO, relationshipName); } } @@ -998,7 +1040,7 @@ public static void referenceCopyToOneRelationshi * the subclass of {@code ERXCopyable} to copy to-many * {@code relationship}'s values to */ - public static void referenceCopyToManyClassRelationships(T source, T destination) { + public static > void referenceCopyToManyClassRelationships(T source, T destination) { ERXCopyable.copyLogger.debug("Reference copying all to-many relationships for " + source.userPresentableDescription()); EOEntity entity = Utility.entity(source); for (EORelationship relationship : classRelationships(entity)) { @@ -1012,6 +1054,7 @@ public static void referenceCopyToManyClassRelat /** * @param * the Type of the {@code source} and {@code destination} + * @param * @param source * the subclass of {@code ERXCopyable} to copy the * {@code relationship}'s value(s) from @@ -1023,14 +1066,14 @@ public static void referenceCopyToManyClassRelat * {@code source} to the {@code destination} * @since Feb 10, 2013 */ - public static void referenceCopyToManyRelationship(T source, T destination, EORelationship relationship) { + public static , E extends ERXEnterpriseObject> void referenceCopyToManyRelationship(T source, T destination, EORelationship relationship) { String relationshipName = relationship.name(); @SuppressWarnings("unchecked") - NSArray sourceRelatedEOs = (NSArray) source.valueForKey(relationshipName); + NSArray sourceRelatedEOs = (NSArray) source.valueForKey(relationshipName); ERXCopyable.copyLogger.debug("Copying " + sourceRelatedEOs.count() + " for relationship " + relationshipName); - for (ERXCopyable sourceRelatedEO : sourceRelatedEOs) { + for (E sourceRelatedEO : sourceRelatedEOs) { ERXCopyable.copyLogger.debug("Copying " + sourceRelatedEO.userPresentableDescription() + " for relationship " + relationshipName); - ERXCopyable destinationRelatedEO = Utility.referenceCopy(sourceRelatedEO); + E destinationRelatedEO = Utility.referenceCopy(sourceRelatedEO); destination.addObjectToBothSidesOfRelationshipWithKey(destinationRelatedEO, relationshipName); } } @@ -1048,7 +1091,7 @@ public static void referenceCopyToManyRelationsh * the {@link EORelationship} to copy from the {@code source} * to the {@code destination} */ - public static void shallowCopyRelationship(T source, T destination, EORelationship relationship) { + public static > void shallowCopyRelationship(T source, T destination, EORelationship relationship) { if (relationship.isToMany()) { Utility.shallowCopyToManyRelationship(source, destination, relationship); } @@ -1065,6 +1108,8 @@ public static void shallowCopyRelationship(T source, T d * * @param * the Type of the {@code source} and {@code destination} + * @param + * the Type of the objects for the {@code relationship} * @param source * the subclass of {@code ERXCopyable} to copy the * {@code relationship}'s value(s) from @@ -1076,14 +1121,14 @@ public static void shallowCopyRelationship(T source, T d * {@code source} to the {@code destination} * @since Feb 10, 2013 */ - public static void shallowCopyToManyRelationship(T source, T destination, EORelationship relationship) { + public static , E extends ERXCopyable> void shallowCopyToManyRelationship(T source, T destination, EORelationship relationship) { String relationshipName = relationship.name(); @SuppressWarnings("unchecked") - NSArray sourceRelatedEOs = (NSArray) source.valueForKey(relationshipName); + NSArray sourceRelatedEOs = (NSArray) source.valueForKey(relationshipName); ERXCopyable.copyLogger.debug("Copying " + sourceRelatedEOs.count() + " for relationship " + relationshipName); - for (ERXCopyable sourceRelatedEO : sourceRelatedEOs) { + for (E sourceRelatedEO : sourceRelatedEOs) { ERXCopyable.copyLogger.debug("Copying " + sourceRelatedEO.userPresentableDescription() + " for relationship " + relationshipName); - ERXCopyable destinationRelatedEO = Utility.shallowCopy(sourceRelatedEO); + E destinationRelatedEO = Utility.shallowCopy(sourceRelatedEO); destination.addObjectToBothSidesOfRelationshipWithKey(destinationRelatedEO, relationshipName); } } @@ -1094,6 +1139,8 @@ public static void shallowCopyToManyRelationship(T sourc * * @param * the Type of the {@code source} and {@code destination} + * @param + * the Type of the objects for the {@code relationship} * @param source * the subclass of {@code ERXCopyable} to copy the * relationship's value from @@ -1104,12 +1151,13 @@ public static void shallowCopyToManyRelationship(T sourc * the {@link EORelationship} to copy from the {@code source} * to the {@code destination} */ - public static void shallowCopyToOneRelationship(T source, T destination, EORelationship relationship) { + public static , E extends ERXCopyable> void shallowCopyToOneRelationship(T source, T destination, EORelationship relationship) { String relationshipName = relationship.name(); - ERXCopyable sourceRelatedEO = (ERXCopyable) source.valueForKey(relationshipName); + @SuppressWarnings("unchecked") + E sourceRelatedEO = (E) source.valueForKey(relationshipName); if (sourceRelatedEO != null) { ERXCopyable.copyLogger.debug("Copying " + sourceRelatedEO.userPresentableDescription() + " object for relationship " + relationshipName); - ERXCopyable destinationRelatedEO = Utility.shallowCopy(sourceRelatedEO); + E destinationRelatedEO = Utility.shallowCopy(sourceRelatedEO); destination.addObjectToBothSidesOfRelationshipWithKey(destinationRelatedEO, relationshipName); } } @@ -1147,7 +1195,7 @@ public static void shallowCopyToOneRelationship( * * @author David Avendasora */ - public static T modelCopy(NSMutableDictionary> copiedObjects, T source) { + public static > T modelCopy(NSMutableDictionary> copiedObjects, T source) { EOEntity entity = Utility.entity(source); EOModel model = entity.model(); NSDictionary entityUserInfo = entity.userInfo(); @@ -1199,7 +1247,7 @@ public static T modelCopy(NSMutableDictionary void modelCopyClassRelationships(NSMutableDictionary> copiedObjects, T source, T destination) { + public static > void modelCopyClassRelationships(NSMutableDictionary> copiedObjects, T source, T destination) { ERXCopyable.copyLogger.debug("Model-copying class relationships for " + source.userPresentableDescription()); for (EORelationship relationship : Utility.classRelationships(Utility.entity(source))) { Utility.modelCopyRelationship(copiedObjects, source, destination, relationship); @@ -1228,7 +1276,7 @@ public static void modelCopyClassRelationships(NSMutable * the {@link EORelationship} to copy values for from the * {@code source} to the {@code destination} */ - public static void modelCopyRelationship(NSMutableDictionary> copiedObjects, T source, T destination, EORelationship relationship) { + public static > void modelCopyRelationship(NSMutableDictionary> copiedObjects, T source, T destination, EORelationship relationship) { String relationshipName = relationship.name(); CopyType copyType = Utility.copyType(relationship); ERXCopyable.copyLogger.debug("CopyType \"" + copyType.type() + "\" specified for " + relationshipName); @@ -1261,7 +1309,7 @@ public static void modelCopyRelationship(NSMutableDictio * the subclass of {@code ERXCopyable} to copy the class * attribute values to */ - public static void modelCopyClassAttributes(T source, T destination) { + public static > void modelCopyClassAttributes(T source, T destination) { ERXCopyable.copyLogger.debug("Model-copying class attributes for " + source.userPresentableDescription()); NSArray attributesToCopy = Utility.classAttributes(Utility.entity(source)); for (EOAttribute attribute : attributesToCopy) { @@ -1283,7 +1331,7 @@ public static void modelCopyClassAttributes(T source, T * the {@link EOAttribute} that should have its value copied * from the {@code source} to the {@code destination} */ - public static void modelCopyAttribute(T source, T destination, EOAttribute attribute) { + public static > void modelCopyAttribute(T source, T destination, EOAttribute attribute) { String attributeName = attribute.name(); CopyType copyType = Utility.copyType(attribute); switch (copyType) { @@ -1293,12 +1341,12 @@ public static void modelCopyAttribute(T source, T destin case CURRENT_TIMESTAMP: destination.takeStoredValueForKey(new NSTimestamp(), attributeName); break; + case UUID: + destination.takeStoredValueForKey(UUID.randomUUID(), attributeName); + break; case NULLIFY: destination.takeStoredValueForKey(null, attributeName); break; - case DEEP: - handleMissingOrInvalidCopyType(attribute, copyType); - break; default: handleMissingOrInvalidCopyType(attribute, copyType); } @@ -1377,14 +1425,14 @@ public static void handleMissingERXCopyableKey(Class invalidClass) { public static void handleMissingOrInvalidCopyType(EOProperty property, CopyType copyType) { String propertyType = Utility.propertyType(property); @SuppressWarnings("unchecked") - NSArray copyTypes = (NSArray) Utility.copyTypes(property).valueForKey("type"); + NSArray copyTypes = (NSArray) CopyType.copyTypesFor(property).valueForKey("type"); String validCopyTypes = copyTypes.componentsJoinedByString(", "); String propertyName = property.name(); EOEntity entity = property.entity(); String entityName = entity.name(); EOModel model = entity.model(); String modelName = model.name(); - String exceptionMessage = "To use ERXCopyable's modelCopy methods the \"" + ERXCopyable.COPY_TYPE_KEY + "\" key must be set in the UserInfo dictionary of the \"" + entityName + "." + propertyName + "\" " + propertyType + " in " + modelName + " AND it must be set to one of these values: {" + validCopyTypes + "}. " + copyType + " is not a valid value."; + String exceptionMessage = "ERXCopyable's modelCopy requires the \"" + ERXCopyable.COPY_TYPE_KEY + "\" key must be set in the UserInfo dictionary of \"" + entityName + "." + propertyName + "\" " + propertyType + " in " + modelName + " AND it must be set to one of these values: {" + validCopyTypes + "}. \"" + copyType + "\" is not a valid value."; throw new IllegalStateException(exceptionMessage); } @@ -1407,32 +1455,13 @@ public static String propertyType(EOProperty property) { } /** - * @param property - * the attribute or relationship being copied - * @return an array of the valid {@link CopyType}s for the passed-in - * {@link EOProperty} - */ - public static NSArray copyTypes(EOProperty property) { - NSArray validCopyTypes; - if (property instanceof EOAttribute) { - validCopyTypes = new NSArray(CopyType.NULLIFY, CopyType.CURRENT_TIMESTAMP, CopyType.REFERENCE); - } - else { - validCopyTypes = new NSArray(CopyType.NULLIFY, CopyType.REFERENCE, CopyType.SHALLOW, CopyType.DEEP); - } - return validCopyTypes; - } - - /** - * @param - * the Type of the {@code source} object * @param source * the subclass of {@code ERXCopyable} that is being copied * @return an array of {@link EOAttribute}s that are the Primary- and * Foreign-Key attributes for the {@code source} subclass of * {@link ERXCopyable} */ - public static NSArray primaryAndForeignKeyAttributes(T source) { + public static NSArray primaryAndForeignKeyAttributes(ERXEnterpriseObject source) { EOEntity entity = Utility.entity(source); NSArray primaryKeyAttributes = entity.primaryKeyAttributes(); NSMutableSet keyAttributes = new NSMutableSet(primaryKeyAttributes);