Skip to content

Instantly share code, notes, and snippets.

@ffbit
Created May 22, 2013 19:01
Show Gist options
  • Select an option

  • Save ffbit/5630026 to your computer and use it in GitHub Desktop.

Select an option

Save ffbit/5630026 to your computer and use it in GitHub Desktop.
Method introduction
/*
* Copyright (c) 2012, Luigi R. Viggiano
* All rights reserved.
*
* This software is distributable under the BSD license.
* See the terms of the BSD license in the documentation provided with this software.
*/
package org.aeonbits.owner;
import org.aeonbits.owner.Config.DefaultValue;
import org.aeonbits.owner.Config.Key;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Properties;
import static org.aeonbits.owner.Config.DisableableFeature.PARAMETER_FORMATTING;
import static org.aeonbits.owner.Config.DisableableFeature.VARIABLE_EXPANSION;
import static org.aeonbits.owner.Converters.convert;
import static org.aeonbits.owner.PropertiesMapper.key;
import static org.aeonbits.owner.Util.isFeatureDisabled;
/**
* This {@link InvocationHandler} receives method calls from the delegate instantiated by {@link ConfigFactory} and maps
* it to a property value from a property file, or a {@link DefaultValue} specified in method annotation.
* <p/>
* The {@link Key} annotation can be used to override default mapping between method names and property names.
* <p/>
* Automatic conversion is handled between the property value and the return type expected by the method of the
* delegate.
*
* @author Luigi R. Viggiano
*/
class PropertiesInvocationHandler implements InvocationHandler {
private final Properties properties;
private final StrSubstitutor substitutor;
private static final Method listPrintStream = getMethod(Properties.class, "list", PrintStream.class);
private static final Method listPrintWriter = getMethod(Properties.class, "list", PrintWriter.class);
private static Method getMethod(Class<?> aClass, String name, Class<?>... args) {
try {
return aClass.getMethod(name, args);
} catch (NoSuchMethodException e) {
// this shouldn't happen, btw we handle the case in which the delegate method is not available...
// so, it's fine.
return null;
}
}
PropertiesInvocationHandler(Properties properties) {
this.properties = properties;
this.substitutor = new StrSubstitutor(properties);
}
@Override
public Object invoke(Object proxy, Method method, Object... args) throws Throwable {
Method proxyMethod;
if (null != (proxyMethod = proxyMethod(method)))
return delegate(properties, proxyMethod, args);
return resolveProperty(method, args);
}
private Object resolveProperty(Method method, Object... args) {
String key = key(method);
String value = properties.getProperty(key);
if (value == null)
return null;
return convert(method, format(method, expandVariables(method, value), args));
}
private String format(Method method, String format, Object... args) {
if (isFeatureDisabled(method, PARAMETER_FORMATTING))
return format;
return String.format(format, args);
}
private String expandVariables(Method method, String value) {
if (isFeatureDisabled(method, VARIABLE_EXPANSION))
return value;
return substitutor.replace(value);
}
private Object delegate(Object target, Method method, Object... args) throws InvocationTargetException,
IllegalAccessException {
return method.invoke(target, args);
}
private Method proxyMethod(Method method) {
if (matches(listPrintStream, method))
return listPrintStream;
if (matches(listPrintWriter, method))
return listPrintWriter;
return null;
}
private boolean matches(Method proxied, Method proxy) {
return proxied != null && proxied.getName().equals(proxy.getName())
&& Arrays.equals(proxied.getParameterTypes(), proxy.getParameterTypes());
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment