Cloning objects is very often useful. groovy offers excellent tools for doing this by its meta programming features.
MOP the properties 1
class User {
def String name
def Boolean id
// the list carry on ..
def User createNewInstance(){
User.metaClass.getProperties().findAll(){it.getSetter()!=null}.inject(new User()) { user,metaProp->
metaProp.setProperty(user,metaProp.getProperty(this))
user
}
}
}
Copying JSONObject to a bean
/**Grails simple copy
* Copies the properties of a JSONObject to a bean.
*
* @param source the JSONObject
* @param target the target bean
* @param ignoreProperties a list of property names to be ignored
* @return the fully qualified class name of the originally marshalled class
*/
def copyJSONObjectPropertiesToBean(JSONObject source, target, ignoreProperties) {
ignoreProperties.add "class"
target.metaClass.properties.each {
if (!ignoreProperties.contains(it.name) && source.containsKey(it.name)) {
it.setProperty(target, source[it.name])
}
}
source.class
}
/**
* Creates a new instance of class based on it's fully qualified class name and sets it's properties.
* The instantiation works only when instantiating a grails domain class
*
* @param clazzName the fully qualified class name
* @param properties an object with the properties to copy
* @return an instance of the specified class
*/
def newDomainClassInstance(properties) {
def clazzName = properties.remove("class")
if(!clazzName) {
throw new IllegalArgumentException("attribute 'class' is missing")
}
def clazz = grailsApplication.getDomainClass(clazzName).getClazz()
def instance = clazz.newInstance(properties)
return instance
}
/*
* Clones a domain object and recursively clones children, clearing ids and
* attaching children to their new parents. Ownership relationships (indicated
* by GORM belongsTo keyword) cause "copy as new" (a recursive deep clone),
* but associations without ownership are shallow copied by reference.
*/
public Object deepClone(domainInstanceToClone) {
//Our target instance for the instance we want to clone
// recursion
def newDomainInstance = domainInstanceToClone.getClass().newInstance()
//Returns a DefaultGrailsDomainClass (as interface GrailsDomainClass) for inspecting properties
def domainClass = ApplicationHolder.application.getDomainClass(newDomainInstance.getClass().name)
domainClass?.persistentProperties?.each {prop ->
if (prop.association) {
if (prop.owningSide) {
//we have to deep clone owned associations
if (prop.oneToOne) {
def newAssociationInstance = deepClone(domainInstanceToClone?."${prop.name}")
newDomainInstance."${prop.name}" = newAssociationInstance
}
else {
domainInstanceToClone."${prop.name}".each { associationInstance ->
def newAssociationInstance = deepClone(associationInstance)
newDomainInstance."addTo${StringUtils.capitalize(prop.name)}"(newAssociationInstance)
}
}
}
else {
if (!prop.bidirectional) {
//If the association isn't owned or the owner, then we can just do a shallow copy of the reference.
newDomainInstance."${prop.name}" = domainInstanceToClone."${prop.name}"
}
// @@JR
// Yes bidirectional and not owning. E.g. clone Report, belongsTo Organisation which hasMany
// manyToOne. Just add to the owning objects collection.
else {
if (prop.manyToOne) {
newDomainInstance."${prop.name}" = domainInstanceToClone."${prop.name}"
def owningInstance = domainInstanceToClone."${prop.name}"
// Need to find the collection.
String otherSide = StringUtils.capitalize(prop.otherSide.name)
owningInstance."addTo${otherSide}"(newDomainInstance)
}
}
}
}
else {
//If the property isn't an association then simply copy the value
newDomainInstance."${prop.name}" = domainInstanceToClone."${prop.name}"
}
}
return newDomainInstance
}
Keine Kommentare:
Kommentar veröffentlichen