Instantly share code, notes, and snippets.

Embed
What would you like to do?
// Defining ModelMapper PropertyCondition
// Better place to put this Util class or Helper Class in your application
/**
* Creating a Mapper field skip condition
*
* @param skipFields list of string. For eg. ['courses', 'students']
* @return {@link org.modelmapper.Condition}
*/
static Condition createSkipCondition(skipFields) {
new Condition() {
boolean applies(MappingContext context) {
!(context.mapping.destinationProperties[0].name in skipFields)
}
}
}
//=============================================================================================================================
// Defining helper method of createTypeMap, place method where you're globally configuring ModelMapper.
// Typical spots are Bootstrap.groovy or dedicated ApplicationInitializeService.groovy
private createTypeMap(Class source, Class target, String typeMapName = null, def skipFields = null) {
if (skipFields && typeMapName) {
modelMapper.createTypeMap(source, target, typeMapName).propertyCondition = Helper.createSkipCondition(skipFields)
} else if (typeMapName) {
modelMapper.createTypeMap(source, target, typeMapName)
} else if (skipFields) {
modelMapper.createTypeMap(source, target).propertyCondition = Helper.createSkipCondition(skipFields)
} else {
modelMapper.createTypeMap(source, target)
}
}
//=============================================================================================================================
// Defining Mapping
// Global settings
modelMapper.configuration.setPropertyCondition(Conditions.isNotNull())
/**
* Domain To DTO/POGO/POJO Mapping
*
* Note: Mapping is required only if you want multiple combination of fields while mapping.
* For Example-
* ------------
* Scenario:: Student ==> StudentDto
* Combinations:
* 1. Default is skip reports and syllabus always
* 2. Skip only reports
* 3. Skip only syllabus
* 4. All data - Don't skip at all
*/
createTypeMap(Student, StudentDto, null, ['reports', 'syllabus'])
createTypeMap(Student, StudentDto, STUDENT_TO_DTO_REPORTS, ['syllabus'])
createTypeMap(Student, StudentDto, STUDENT_TO_DTO_SYLLABUS, ['reports'])
createTypeMap(Student, StudentDto, STUDENT_TO_DTO_REPORTS_SYLLABUS)
//=============================================================================================================================
// Defining Collection to DTO/POGO/POJO method
private mapDomainToDto(obj, clazz, typeMapName = null) {
if (typeMapName) {
modelMapper.map(obj, clazz, typeMapName)
} else {
modelMapper.map(obj, clazz)
}
}
private collectionToDto(def delegate, Class clazz, String name = null) {
def result = []
if (name) {
delegate.each {
result << mapDomainToDto(it, clazz, name)
}
} else {
delegate.each {
result << mapDomainToDto(it, clazz)
}
}
result
}
// Defining Closures
Closure toDtoClass = { Class clazz ->
collectionToDto(delegate, clazz)
}
Closure toDtoClassWithCondition = { Class clazz, String name ->
collectionToDto(delegate, clazz, name)
}
//=============================================================================================================================
// Initializing Meta methods
// Adding the toDTO(Class) & toDTO(Class, name) methods to collection, list, set, etc
[Collection, ArrayList, HashSet, TreeSet].each {
it.metaClass.toDto = toDtoClass
it.metaClass.toDto = toDtoClassWithCondition
}
grailsApplication.domainClasses.each { domainArtefact ->
// Adding 'as DTO'
final MetaClass mc = domainArtefact.metaClass
final asTypeRef = mc.getMetaMethod('asType', [Class ] as Object[])
mc.asType = { Class clazz ->
def result
if (delegate) {
if (clazz.name.endsWith('Dto')) { // I know its hacky way :(
result = mapDomainToDto(delegate, clazz)
} else {
result = asTypeRef.invoke(delegate, [clazz ] as Object[])
}
}
result
}
// Adding toDto(Class)
mc.toDto = { Class clazz ->
mapDomainToDto(delegate, clazz)
}
// Adding toDto(Class, name)
mc.toDto = { Class clazz, String name ->
mapDomainToDto(delegate, clazz, name)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment