in grails-datastore-core/src/main/groovy/org/grails/datastore/mapping/config/ConfigurationBuilder.groovy [139:400]
protected void buildRecurse(Object builder, List<Class> builderQueue, Object fallBackConfig, String startingPrefix) {
List<Class> hierarchy = toHierarchy(builder.getClass())
startBuild(builder, startingPrefix)
for(Class builderClass in hierarchy) {
def methods = builderClass.declaredMethods
for (method in methods) {
def methodName = method.name
if (!Modifier.isPublic(method.modifiers) || method.isSynthetic() || IGNORE_METHODS.contains(methodName)) {
continue
}
if (method.declaringClass != builderClass) {
continue
}
def parameterTypes = method.parameterTypes
String settingName
boolean hasBuilderPrefix = builderMethodPrefix != null
if (hasBuilderPrefix && methodName.startsWith(builderMethodPrefix)) {
settingName = methodName.substring(builderMethodPrefix.size()).uncapitalize()
}
else if (hasBuilderPrefix) {
continue
}
else if (!hasBuilderPrefix &&
((org.grails.datastore.mapping.reflect.ReflectionUtils.isGetter(methodName, parameterTypes) && method.returnType.getAnnotation(Builder) == null) ||
org.grails.datastore.mapping.reflect.ReflectionUtils.isSetter(methodName, parameterTypes))) {
// don't process getters or setters, unless the getter returns a builder
continue
}
else {
settingName = methodName
}
String propertyPath = startingPrefix ? "${startingPrefix}.${settingName}" : settingName
if (parameterTypes.length == 1) {
Class argType = parameterTypes[0]
def builderMethod = ReflectionUtils.findMethod(argType, 'builder')
if (builderMethod != null && Modifier.isStatic(builderMethod.modifiers)) {
if (propertyResolver.containsProperty(propertyPath)) {
Method existingGetter = ReflectionUtils.findMethod(builderClass, NameUtils.getGetterName(methodName))
def newBuilder
if (existingGetter != null) {
newBuilder = existingGetter.invoke(builder)
}
if (newBuilder == null) {
newBuilder = builderMethod.invoke(argType)
}
newChildBuilder(newBuilder, propertyPath)
Object fallBackChildConfig = getFallBackValue(fallBackConfig, settingName)
if (!builderQueue.contains(newBuilder.class)) {
builderQueue.add(newBuilder.class)
buildRecurse(newBuilder, builderQueue, fallBackChildConfig, propertyPath)
builderQueue.remove(newBuilder.class)
def buildMethod = ReflectionUtils.findMethod(newBuilder.getClass(), 'build')
if (buildMethod != null) {
try {
method.invoke(builder, buildMethod.invoke(newBuilder))
} catch (Throwable e) {
log.error("build method threw exception", e)
}
} else {
method.invoke(builder, newBuilder)
}
}
}
continue
}
def buildMethod = ReflectionUtils.findMethod(argType, 'build')
if (buildMethod != null) {
Method existingGetter = ReflectionUtils.findMethod(builderClass, NameUtils.getGetterName(methodName))
def newBuilder
if (existingGetter != null) {
newBuilder = existingGetter.invoke(builder)
if (newBuilder != null) {
Object fallBackChildConfig = getFallBackValue(fallBackConfig, settingName)
newBuilder = newChildBuilderForFallback(newBuilder, fallBackChildConfig)
if (!builderQueue.contains(newBuilder.class)) {
builderQueue.add(newBuilder.class)
buildRecurse(newBuilder, builderQueue, fallBackChildConfig, propertyPath)
builderQueue.remove(newBuilder.class)
newChildBuilder(newBuilder, propertyPath)
method.invoke(builder, newBuilder)
}
continue
}
}
}
Builder builderAnnotation = argType.getAnnotation(Builder)
if (builderAnnotation != null && builderAnnotation.builderStrategy() == SimpleStrategy) {
Method existingGetter = ReflectionUtils.findMethod(builderClass, NameUtils.getGetterName(methodName))
def newBuilder
if (existingGetter != null) {
newBuilder = existingGetter.invoke(builder)
}
if (newBuilder == null) {
newBuilder = argType.newInstance()
}
if (newBuilder instanceof Map) {
Map subMap = propertyResolver.getProperty(propertyPath, Map, Collections.emptyMap())
if (!subMap.isEmpty()) {
((Map) newBuilder).putAll(subMap)
}
}
newChildBuilder(newBuilder, propertyPath)
Object fallBackChildConfig = getFallBackValue(fallBackConfig, methodName)
if (!builderQueue.contains(newBuilder.class)) {
builderQueue.add(newBuilder.class)
buildRecurse(newBuilder, builderQueue, fallBackChildConfig, propertyPath)
builderQueue.remove(newBuilder.class)
method.invoke(builder, newBuilder)
}
continue
}
if (ConfigurationBuilder.isAssignableFrom(argType)) {
try {
Method existingGetter = ReflectionUtils.findMethod(builderClass, NameUtils.getGetterName(methodName))
ConfigurationBuilder newBuilder
if (existingGetter != null) {
newBuilder = (ConfigurationBuilder) existingGetter.invoke(builder)
}
if (newBuilder == null) {
if (fallBackConfig != null && builderClass.isInstance(fallBackConfig)) {
ConfigurationBuilder fallbackBuilder = (ConfigurationBuilder) existingGetter.invoke(fallBackConfig)
if (fallbackBuilder != null) {
newBuilder = (ConfigurationBuilder) argType.newInstance(this.propertyResolver, propertyPath, fallbackBuilder.build())
} else {
newBuilder = (ConfigurationBuilder) argType.newInstance(this.propertyResolver, propertyPath)
}
} else {
newBuilder = (ConfigurationBuilder) argType.newInstance(this.propertyResolver, propertyPath)
}
}
newChildBuilder(newBuilder, propertyPath)
method.invoke(builder, newBuilder)
} catch (Throwable e) {
throw new ConfigurationException("Cannot read configuration for path $propertyPath: $e.message", e)
}
continue
}
} else if (methodName.startsWith("get") && parameterTypes.length == 0) {
if (method.returnType.getAnnotation(Builder)) {
def childBuilder = method.invoke(builder)
if (childBuilder != null) {
Object fallBackChildConfig = null
if (fallBackConfig != null) {
Method fallbackGetter = ReflectionUtils.findMethod(fallBackConfig.getClass(), methodName)
if (fallbackGetter != null) {
fallBackChildConfig = fallbackGetter.invoke(fallBackConfig)
}
}
String getterPropertyPath = startingPrefix ? "${startingPrefix}.${NameUtils.getPropertyNameForGetterOrSetter(methodName)}" : NameUtils.getPropertyNameForGetterOrSetter(methodName)
if (!builderQueue.contains(childBuilder.class)) {
builderQueue.add(childBuilder.class)
buildRecurse(childBuilder, builderQueue, fallBackChildConfig, getterPropertyPath)
builderQueue.remove(childBuilder.class)
}
continue
}
}
} else if (parameterTypes.length == 0) {
def value = propertyResolver.getProperty(propertyPath, Boolean, false)
if (value) {
try {
method.invoke(builder)
} catch (Throwable e) {
throw new ConfigurationException("Error executing method for path $propertyPath: $e.message", e)
}
}
continue
}
List<Object> args = []
boolean appendArgName = parameterTypes.length > 1
int argIndex = 0
for (Class argType: parameterTypes) {
String propertyPathForArg = propertyPath
if (appendArgName) {
propertyPathForArg += ".arg${argIndex}"
}
argIndex++
def valueOfMethod = ReflectionUtils.findMethod(argType, 'valueOf')
if (valueOfMethod != null && Modifier.isStatic(valueOfMethod.modifiers)) {
try {
def value = propertyResolver.getProperty(propertyPathForArg, "")
if (value) {
def converted = valueOfMethod.invoke(argType, value)
args.add(converted)
}
} catch (Throwable e) {
throw new ConfigurationException("Cannot read configuration for path $propertyPathForArg: $e.message", e)
}
}
else {
Object fallBackValue = getFallBackValue(fallBackConfig, settingName)
def value
try {
value = propertyResolver.getProperty(propertyPathForArg, argType, fallBackValue)
} catch (ConversionFailedException e) {
if(argType.isEnum()) {
value = propertyResolver.getProperty(propertyPathForArg, String)
if (value != null) {
try {
value = Enum.valueOf((Class)argType, value.toUpperCase())
} catch (Throwable e2) {
// ignore e2 and throw original
throw new ConfigurationException("Invalid value for setting [$propertyPathForArg]: $e.message", e)
}
}
else {
throw new ConfigurationException("Invalid value for setting [$propertyPathForArg]: $e.message", e)
}
}
else {
throw new ConfigurationException("Invalid value for setting [$propertyPathForArg]: $e.message", e)
}
}
if (value != null) {
log.debug("Resolved value [{}] for setting [{}]", value, propertyPathForArg)
args.add(value)
}
}
}
if (args) {
ReflectionUtils.makeAccessible(method)
ReflectionUtils.invokeMethod(method, builder, args.toArray())
}
}
}
}