Skip to content

Instantly share code, notes, and snippets.

@tonyerskine
Created December 9, 2019 18:09
Show Gist options
  • Save tonyerskine/025d586118ef242647ee1ec1c56a13ac to your computer and use it in GitHub Desktop.
Save tonyerskine/025d586118ef242647ee1ec1c56a13ac to your computer and use it in GitHub Desktop.
Groovy/Grails ToMap Trait: Convert POGO to Map
/**
* This Trait adds a ToMap(..) methods to a POGO, which convert the object to a Map<String, Object>
* ignoring extraneous fields such as synthetic, static, grails domain classes, and collections.
* It is designed to be used preprocess Grails domain object proir to converting to JSON. However,
* it does not require Grails to work.
*/
import groovy.transform.InheritConstructors
import org.codehaus.groovy.grails.commons.DomainClassArtefactHandler
import org.springframework.validation.Errors
import java.lang.reflect.Field
import java.lang.reflect.Modifier
trait ToMap {
static transients = ["defaultMappedFields", "excludedFields"]
private List<String> defaultMappedFields
private List<String> excludedFields = ["grailsApplication"]
List<String> getExcludedFields() { excludedFields }
void setExcludedFields(List<String> excludedFields) { this.excludedFields = excludedFields }
List<String> getDefaultMappedFields() {
defaultMappedFields ?: this.class.declaredFields.findAll { field ->
!field.synthetic &&
!DomainClassArtefactHandler.isDomainClass(field.type) &&
!Modifier.isStatic(field.modifiers) &&
![Set, List, Map, Errors].contains(field.type) &&
!excludedFields.contains(field.name)
}*.name
}
void setDefaultMappedFields(List<String> defaultFields) {
defaultFields.each {
Field field = this.class.getDeclaredField(it)
if (DomainClassArtefactHandler.isDomainClass(field.type)) {
throw new InvalidDefaultMappedFieldException("$it cannot be set as a default mapped field because it is a domain object. Only simple fields can be set as default fields to prevent circular references, etc.")
}
if ([Set, List, Map, Errors].contains(field.type)) {
throw new InvalidDefaultMappedFieldException("$it cannot be set as a default mapped field because it is a collection or map. Only simple fields can be set as default fields to prevent circular references, etc.")
}
if (excludedFields.contains(field.name)) {
throw new InvalidDefaultMappedFieldException("$it cannot be set as a default mapped field because it is explicitly excluded in excludedFields: $excludedFields")
}
}
this.defaultMappedFields = defaultFields
}
Map toMap() {
getDefaultMappedFields().collectEntries { fieldName ->
[(fieldName): this."$fieldName"]
}
}
Map toMap(List<String> include) {
Map map = toMap()
include.each {
map[it] = this[it].toMap()
}
return map
}
}
@InheritConstructors
class InvalidDefaultMappedFieldException extends RuntimeException {
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment