com.github.tonybaines.gestalt.Configurations.groovy Maven / Gradle / Ivy
package com.github.tonybaines.gestalt
import com.github.tonybaines.gestalt.serialisation.ConfigPropertiesSerialiser
import com.github.tonybaines.gestalt.serialisation.ConfigXmlSerialiser
import com.github.tonybaines.gestalt.sources.*
import com.github.tonybaines.gestalt.sources.features.CachingDecorator
import com.github.tonybaines.gestalt.sources.features.ExceptionOnNullValueDecorator
import com.github.tonybaines.gestalt.sources.features.ValidatingDecorator
import com.github.tonybaines.gestalt.transformers.DefaultPropertyNameTransformer
import com.github.tonybaines.gestalt.transformers.PropertyNameTransformer
import com.github.tonybaines.gestalt.validation.ReflectionValidator
import com.github.tonybaines.gestalt.validation.ValidationResult
import groovy.transform.TupleConstructor
import groovy.util.logging.Slf4j
import javax.validation.constraints.AssertFalse
import javax.validation.constraints.AssertTrue
import javax.validation.constraints.DecimalMax
import javax.validation.constraints.DecimalMin
import javax.validation.constraints.Digits
import javax.validation.constraints.Max
import javax.validation.constraints.Min
import javax.validation.constraints.NotNull
import javax.validation.constraints.Null
import javax.validation.constraints.Pattern
import javax.validation.constraints.Size
import java.beans.Introspector
import java.lang.annotation.Annotation
import java.lang.reflect.Method
import java.lang.reflect.ParameterizedType
import static com.github.tonybaines.gestalt.Configurations.Utils.propsFromString
@Slf4j
class Configurations {
static CompositeConfigurationBuilder definedBy(Class configInterface) {
new CompositeConfigurationBuilder(configInterface)
}
static ValidationResult validate(Object instance, Class configInterface) {
new ReflectionValidator(instance, configInterface).validate()
}
static class Utils {
static String fromBeanSpec(String methodName) {
Introspector.decapitalize(methodName.replaceFirst(/(get|is)/, '')) // TODO: replace at start only
}
static isAList(type) {
type instanceof ParameterizedType && type.rawType.isAssignableFrom(List)
}
static boolean returnsAValue(Method method) {
isAValueType(method.returnType)
}
static isAValueType(Class type) {
switch (type) {
case String: return true
case Integer: return true
case int: return true
case Double: return true
case double: return true
case Long: return true
case long: return true
case Boolean: return true
case boolean: return true
default: return false
}
}
static boolean declaresMethod(Class clazz, String name, Class... params) {
declaredMethodsOf(clazz).any {it.name == name && it.parameterTypes == params}
}
static Iterable declaredMethodsOf(configInterface) {
configInterface.declaredMethods.grep { !it.name.startsWith('\$') }
}
public static boolean hasAFromStringMethod(Class clazz) {
declaresMethod(clazz, 'fromString', String)
}
public static boolean isDefaultReturningValidationResults(Method method) {
method.isDefault() && method.returnType.equals(ValidationResult.class) || method.returnType.equals(ValidationResult.Item.class)
}
public static boolean optional(Method method) {
method.declaredAnnotations.any{it instanceof Optional}
}
public static Properties propsFromString(String propsString) {
Properties props = new Properties()
propsString.eachLine {
if (!it.startsWith('#')) {
def (k,v) = it.split(/ = /)
props.put(k, v)
}
}
props
}
static def annotationInfo(Method method) {
def info = []
method.declaredAnnotations.each { Annotation a ->
Class type = a.annotationType()
if (type.name.contains(Comment.class.name)) {
def comment = a.h.memberValues['value']
info << "${comment}"
}
if (type.name.contains(Default.class.name)) {
def defaultValue = a.h.memberValues['value']
info << "default: ${defaultValue}"
}
if (type.canonicalName.startsWith('javax.validation.constraints')) {
switch (type) {
case Size: info << "[Size: min=${a.min()}, max=${a.max()}]"; break
case AssertTrue: info << "[Always true]"; break
case AssertFalse: info << "[Always false]"; break
case DecimalMin: info << "[Decimal min=${a.value()}]"; break
case DecimalMax: info << "[Decimal max=${a.value()}]"; break
case Digits: info << "[Digits integer-digits=${a.integer()}, fraction-digits=${a.fraction()}]"; break
case Min: info << "[Min ${a.value()}]"; break
case Max: info << "[Max ${a.value()}]"; break
case NotNull: info << "[Not Null]"; break
case Null: info << "[Always Null]"; break
case Pattern: info << "[Pattern ${a.regexp()}]"; break
}
}
}
info
}
public static isNotAProperty(Object obj, String propertyName) {
!obj.hasProperty(propertyName)
}
}
static SerialisationBuilder serialise(T instance, Class configInterface) {
new SerialisationBuilder(instance, configInterface)
}
/**
* @deprecated use {@see com.github.tonybaines.gestalt.Configurations#serialise(java.lang.Object, java.lang.Object)}
*/
static String toXml(T instance, Class configInterface, PropertyNameTransformer propertyNameTransformer = new DefaultPropertyNameTransformer()) {
serialise(instance, configInterface).using(propertyNameTransformer).toXml()
}
/**
* @deprecated use {@see com.github.tonybaines.gestalt.Configurations#serialise(java.lang.Object, java.lang.Object)}
*/
static Properties toProperties(T instance, Class configInterface, PropertyNameTransformer propertyNameTransformer = new DefaultPropertyNameTransformer()) {
propsFromString(serialise(instance, configInterface).using(propertyNameTransformer).toProperties())
}
static class SerialisationBuilder {
private final T instance
private final Class configInterface
private PropertyNameTransformer propertyNameTransformer = new DefaultPropertyNameTransformer()
boolean generatingComments = false
SerialisationBuilder(T instance, Class configInterface) {
this.configInterface = configInterface
this.instance = instance
}
public SerialisationBuilder using(PropertyNameTransformer propertyNameTransformer) {
this.propertyNameTransformer = propertyNameTransformer
this
}
public SerialisationBuilder withComments() {
this.generatingComments = true
this
}
public String toXml() {
new ConfigXmlSerialiser(instance, propertyNameTransformer, generatingComments).toXmlString(configInterface)
}
public String toProperties() {
new ConfigPropertiesSerialiser(instance, propertyNameTransformer, generatingComments).toProperties(configInterface)
}
}
static enum Feature {
Validation, Defaults, ExceptionOnNullValue, Caching
}
static enum Behaviour {
isOptional
}
static class CompositeConfigurationBuilder {
private Class configInterface
private Map constants = [:]
private List
© 2015 - 2025 Weber Informatics LLC | Privacy Policy