package com.netflix.fabricator.component.bind;
import java.lang.reflect.Method;
import java.util.List;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.base.CaseFormat;
import com.google.common.collect.Lists;
import com.google.inject.Inject;
import com.netflix.fabricator.InjectionSpi;
import com.netflix.fabricator.PropertyBinder;
import com.netflix.fabricator.PropertyBinderFactory;
import com.netflix.fabricator.PropertyBinderResolver;
public class SimplePropertyBinderFactoryResolver implements PropertyBinderResolver {
private static final Logger LOG = LoggerFactory.getLogger(SimplePropertyBinderFactoryResolver.class);
private static final String WITH_METHOD_PREFIX = "with";
private static final String SET_METHOD_PREFIX = "set";
private static final List<PropertyBinderFactory> DEFAULT_PROPERTY_FACTORIES = Lists.newArrayList(
StringBinderFactory.get(),
LongBinderFactory.get(),
DoubleBinderFactory.get(),
BooleanBinderFactory.get(),
IntegerBinderFactory.get(),
EnumBinderFactory.get(),
ClassBinderFactory.get(),
DynamicStringBinderFactory.get(),
DynamicLongBinderFactory.get(),
DynamicDoubleBinderFactory.get(),
DynamicBooleanBinderFactory.get(),
DynamicIntegerBinderFactory.get(),
PropertiesBinderFactory.get()
);
private final List<PropertyBinderFactory> propertyBinders;
private final InjectionSpi injector;
public SimplePropertyBinderFactoryResolver(List<PropertyBinderFactory> propertyBinders, InjectionSpi injector) {
if (propertyBinders != null)
this.propertyBinders = Lists.newArrayList(propertyBinders);
else
this.propertyBinders = Lists.newArrayList();
this.propertyBinders.addAll(DEFAULT_PROPERTY_FACTORIES);
this.injector = injector;
}
public SimplePropertyBinderFactoryResolver() {
this(null, null);
}
@Override
public PropertyBinder get(Method method) {
// Skip methods that do real DI. These will have been injected at object creation
if (hasInjectAnnotation(method)) {
return null;
}
// Deduce property name from the method
final String propertyName = getPropertyName(method);
if (propertyName == null) {
return null;
}
// Only support methods with a single parameter.
// TODO: Might want to support methods that take TimeUnit
Class<?>[] types = method.getParameterTypes();
if (types.length != 1) {
return null;
}
// Primitive or String will be handled as configuration binding
final Class<?> argType = types[0];
for (PropertyBinderFactory factory : propertyBinders) {
PropertyBinder binder = factory.createBinder(method, propertyName);
if (binder != null) {
return binder;
}
}
return injector.createInjectableProperty(propertyName, argType, method);
}
private static boolean hasInjectAnnotation(Method method) {
return method.isAnnotationPresent(Inject.class) ||
method.isAnnotationPresent(javax.inject.Inject.class);
}
private static String getPropertyName(Method method) {
if (method.getName().startsWith(WITH_METHOD_PREFIX)) {
return CaseFormat.UPPER_CAMEL.to(
CaseFormat.LOWER_CAMEL,
StringUtils.substringAfter(method.getName(), WITH_METHOD_PREFIX));
}
if (method.getName().startsWith(SET_METHOD_PREFIX)) {
return CaseFormat.UPPER_CAMEL.to(
CaseFormat.LOWER_CAMEL,
StringUtils.substringAfter(method.getName(), SET_METHOD_PREFIX));
}
return null;
}
}