diff --git a/archaius2-api/src/main/java/com/netflix/archaius/api/annotations/Configuration.java b/archaius2-api/src/main/java/com/netflix/archaius/api/annotations/Configuration.java
index 24a5e83db..bd2e225b7 100644
--- a/archaius2-api/src/main/java/com/netflix/archaius/api/annotations/Configuration.java
+++ b/archaius2-api/src/main/java/com/netflix/archaius/api/annotations/Configuration.java
@@ -22,8 +22,17 @@
import java.lang.annotation.Target;
/**
- * Marks a field as a configuration item. Governator will auto-assign the value based
- * on the {@link #value()} of the annotation via the set {@link ConfigurationProvider}.
+ * When applied to an interface, marks it as a candidate for binding via a ConfigProxyFactory (from the archaius2-core
+ * module). For this case, the only relevant attributes are {@link #prefix()}, which sets a shared prefix for all the
+ * properties bound to the interface's methods, and {@link #immutable()}, which when set to true creates a static proxy
+ * that always returns the config values as they were at the moment that the proxy object is created.
+ *
+ * Note that an interface can be bound via the ConfigProxyFactory even if it does NOT have this annotation.
+ *
+ * When applied to a field, marks it as a configuration item, to be injected with the value of the specified property
+ * key. This usage is deprecated in favor of using your DI-framework options for injecting configuration values.
+ * @see PropertyName
+ * @see DefaultValue
*/
@Documented
@Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
@@ -31,37 +40,37 @@
public @interface Configuration
{
/**
- * @return name/key of the config to assign
+ * name/key of the config to assign
*/
String prefix() default "";
/**
- * @return field names to use for replacement
+ * field names to use for replacement
*/
String[] params() default {};
/**
- * @return user displayable description of this configuration
+ * user displayable description of this configuration
*/
String documentation() default "";
/**
- * @return true to allow mapping configuration to fields
+ * true to allow mapping configuration to fields
*/
boolean allowFields() default false;
/**
- * @return true to allow mapping configuration to setters
+ * true to allow mapping configuration to setters
*/
boolean allowSetters() default true;
/**
- * @return Method to call after configuration is bound
+ * Method to call after configuration is bound
*/
String postConfigure() default "";
/**
- * @return If true then properties cannot change once set otherwise methods will be
+ * If true then properties cannot change once set otherwise methods will be
* bound to dynamic properties via PropertyFactory.
*/
boolean immutable() default false;
diff --git a/archaius2-core/src/main/java/com/netflix/archaius/ConfigProxyFactory.java b/archaius2-core/src/main/java/com/netflix/archaius/ConfigProxyFactory.java
index 674bb6191..e99312847 100644
--- a/archaius2-core/src/main/java/com/netflix/archaius/ConfigProxyFactory.java
+++ b/archaius2-core/src/main/java/com/netflix/archaius/ConfigProxyFactory.java
@@ -42,7 +42,7 @@
/**
* Factory for binding a configuration interface to properties in a {@link PropertyFactory}
* instance. Getter methods on the interface are mapped by naming convention
- * by the property name may be overridden using the @PropertyName annotation.
+ * by the property name or may be overridden using the @{@link PropertyName} annotation.
*
* For example,
*
@@ -52,11 +52,14 @@
* int getTimeout(); // maps to "foo.timeout"
*
* String getName(); // maps to "foo.name"
+ *
+ * @PropertyName(name="bar")
+ * String getSomeOtherName(); // maps to "foo.bar"
* }
* }
*
*
- * Default values may be set by adding a {@literal @}DefaultValue with a default value string. Note
+ * Default values may be set by adding a {@literal @}{@link DefaultValue} with a default value string. Note
* that the default value type is a string to allow for interpolation. Alternatively, methods can
* provide a default method implementation. Note that {@literal @}DefaultValue cannot be added to a default
* method as it would introduce ambiguity as to which mechanism wins.
@@ -82,7 +85,7 @@
* }
*
*
- * To override the prefix in {@literal @}Configuration or provide a prefix when there is no
+ * To override the prefix in {@literal @}{@link Configuration} or provide a prefix when there is no
* {@literal @}Configuration annotation simply pass in a prefix in the call to newProxy.
*
*
@@ -92,7 +95,10 @@
*
*
* By default, all properties are dynamic and can therefore change from call to call. To make the
- * configuration static set the immutable attributes of @Configuration to true.
+ * configuration static set {@link Configuration#immutable()} to true. Creation of an immutable configuration
+ * will fail if the interface contains parametrized methods or methods that return primitive types and do not have a
+ * value set at the moment of creation, from either the underlying config, a {@link DefaultValue} annotation, or a
+ * default method implementation.
*
* Note that an application should normally have just one instance of ConfigProxyFactory
* and PropertyFactory since PropertyFactory caches {@link com.netflix.archaius.api.Property} objects.
@@ -245,7 +251,8 @@ T newProxy(final Class type, final String initialPrefix, boolean immutabl
if (immutable) {
// Cache the current value of the property and always return that.
- // Note that this will fail for parameterized properties!
+ // Note that this will fail for parameterized properties and for primitive-valued methods
+ // with no value set!
Object value = methodInvokerHolder.invoker.invoke(new Object[]{});
invokers.put(method, (args) -> value);
} else {
@@ -296,7 +303,7 @@ private String derivePrefix(Configuration annot, String prefix) {
}
@SuppressWarnings({"unchecked", "rawtypes"})
- private MethodInvokerHolder buildInvokerForMethod(Class type, String prefix, Method m, T proxyObject, boolean immutable) {
+ private MethodInvokerHolder buildInvokerForMethod(Class proxyObjectType, String prefix, Method m, T proxyObject, boolean immutable) {
try {
final Class> returnType = m.getReturnType();
@@ -304,16 +311,8 @@ private MethodInvokerHolder buildInvokerForMethod(Class type, String pref
final String propName = getPropertyName(prefix, m, nameAnnot);
// A supplier for the value to be returned when the method's associated property is not set
- final Function defaultValueSupplier;
-
- if (m.getAnnotation(DefaultValue.class) != null) {
- defaultValueSupplier = createAnnotatedMethodSupplier(m, m.getGenericReturnType(), config, decoder);
- } else if (m.isDefault()) {
- defaultValueSupplier = createDefaultMethodSupplier(m, type, proxyObject);
- } else {
- // No default specified in proxied interface. Return "empty" for collection types, null for any other type.
- defaultValueSupplier = knownCollections.getOrDefault(returnType, (ignored) -> null);
- }
+ // The proper parametrized type for this would be Function