Added further implementation support for DynamicValues and templates.

Project: http://git-wip-us.apache.org/repos/asf/incubator-tamaya/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-tamaya/commit/4ddf46f7
Tree: http://git-wip-us.apache.org/repos/asf/incubator-tamaya/tree/4ddf46f7
Diff: http://git-wip-us.apache.org/repos/asf/incubator-tamaya/diff/4ddf46f7

Branch: refs/heads/master
Commit: 4ddf46f748b3796db51ed09b43f29868eb0b7338
Parents: 1aa0dc4
Author: anatole <anat...@apache.org>
Authored: Tue Feb 17 00:21:58 2015 +0100
Committer: anatole <anat...@apache.org>
Committed: Tue Feb 17 00:21:58 2015 +0100

----------------------------------------------------------------------
 .../tamaya/inject/ConfigurationInjector.java    |   7 +
 .../org/apache/tamaya/inject/DynamicValue.java  | 374 ++--------------
 .../ConfigTemplateInvocationHandler.java        |  77 +++-
 .../tamaya/inject/internal/ConfiguredField.java |  88 +++-
 .../tamaya/inject/internal/ConfiguredType.java  |   9 +-
 .../internal/DefaultConfigurationInjector.java  |  18 +
 .../inject/internal/DefaultDynamicValue.java    | 441 +++++++++++++++++++
 .../tamaya/inject/internal/InjectionUtils.java  |  35 +-
 .../java/annottext/AnnotatedConfigBean.java     |   8 +
 .../java/annottext/AnnotatedConfigTemplate.java |   8 +-
 .../tamaya/inject/TamayaInjectionTest.java      |  20 +
 11 files changed, 722 insertions(+), 363 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/4ddf46f7/modules/injection/src/main/java/org/apache/tamaya/inject/ConfigurationInjector.java
----------------------------------------------------------------------
diff --git 
a/modules/injection/src/main/java/org/apache/tamaya/inject/ConfigurationInjector.java
 
b/modules/injection/src/main/java/org/apache/tamaya/inject/ConfigurationInjector.java
index de1c29e..33c5227 100644
--- 
a/modules/injection/src/main/java/org/apache/tamaya/inject/ConfigurationInjector.java
+++ 
b/modules/injection/src/main/java/org/apache/tamaya/inject/ConfigurationInjector.java
@@ -37,6 +37,13 @@ public interface ConfigurationInjector {
      */
     <T> T configure(T instance);
 
+    /**
+     * Create a template implementting the annotated methods based on current 
configuration data.
+     *
+     * @param templateType the type of the template to be created.
+     */
+    <T> T createTemplate(Class<T> templateType);
+
 
     /**
      * Creates a supplier for configured instances of the given type {@code T}.

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/4ddf46f7/modules/injection/src/main/java/org/apache/tamaya/inject/DynamicValue.java
----------------------------------------------------------------------
diff --git 
a/modules/injection/src/main/java/org/apache/tamaya/inject/DynamicValue.java 
b/modules/injection/src/main/java/org/apache/tamaya/inject/DynamicValue.java
index 6075666..1979b55 100644
--- a/modules/injection/src/main/java/org/apache/tamaya/inject/DynamicValue.java
+++ b/modules/injection/src/main/java/org/apache/tamaya/inject/DynamicValue.java
@@ -19,40 +19,27 @@
 package org.apache.tamaya.inject;
 
 import java.beans.PropertyChangeEvent;
-import java.io.IOException;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
-import java.io.Serializable;
-import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Objects;
 import java.util.Optional;
 import java.util.function.Consumer;
-import java.util.function.Function;
-import java.util.function.Predicate;
 import java.util.function.Supplier;
-import java.util.logging.Logger;
 
 /**
  * A accessor for a single configured value. This can be used to support 
values that may change during runtime,
  * reconfigured or final. Hereby external code (could be Tamaya configuration 
listners or client code), can set a
  * new value. Depending on the {@link UpdatePolicy} the new value is 
immedeately active or it requires an active commit
- * by client code. Similarly an instance also can ignore all later changes to 
the value.
- * <h3>Implementation Details</h3>
- * This class is
+ * by client code. Similarly an instance also can ignore all later changes to 
the value.<br/>
+ * Types of this interface can be used as injection targets in injected beans 
or as template resiult on configuration
+ * templates.
+ * <h3>Implementation Specification</h3>
+ * Implementation of this interface must be
  * <ul>
  *     <li>Serializable, when also the item stored is serializable</li>
  *     <li>Thread safe</li>
  * </ul>
  * @param <T> The type of the value.
  */
-public final class DynamicValue<T> implements Serializable {
+public interface DynamicValue<T> {
 
-    private static final long serialVersionUID = -2071172847144537443L;
-    
     /**
      * Policy to control how new values are applied to this instance.
      */
@@ -73,69 +60,6 @@ public final class DynamicValue<T> implements Serializable {
         LOG_AND_DISCARD
     }
 
-
-    /** The property name of the entry. */
-    private String propertyName;
-    /**
-     * Policy that defines how new values are applied, be default it is 
applied initially once, but never updated
-     * anymore.
-     */
-    private UpdatePolicy updatePolicy = UpdatePolicy.NEVER;
-    /** The current value, never null. */
-    private transient Optional<T> value;
-    /** The new value, or null. */
-    private transient Optional<T> newValue;
-    /** List of listeners that listen for changes. */
-    private transient WeakList<Consumer<PropertyChangeEvent>> listeners;
-
-    /**
-     * Returns an empty {@code DynamicValue} instance.  No value is present 
for this
-     * DynamicValue.
-     *
-     * NOTE: Though it may be tempting to do so, avoid testing if an object
-     * is empty by comparing with {@code ==} against instances returned by
-     * {@code Option.empty()}. There is no guarantee that it is a singleton.
-     * Instead, use {@link #isPresent()}.
-     *
-     * @param <T> Type of the non-existent value
-     * @return an empty {@code DynamicValue}
-     */
-    public static <T> DynamicValue<T> empty(String propertyName) {
-        return new DynamicValue<T>(propertyName, null);
-    }
-
-    /**
-     * Constructor.
-     * @param propertyName the key of the property, not null.
-     * @param item the initial value.
-     */
-    private DynamicValue(String propertyName, Optional<T> item){
-        this.propertyName = Objects.requireNonNull(propertyName);
-        this.value = item;
-    }
-
-    /**
-     * Creates a new instance.
-     * @param propertyName the key of the property, not null.
-     * @param value the initial value, not null.
-     * @param <T> the type
-     * @return a new instance, never null
-     */
-    public static <T> DynamicValue<T> of(String propertyName, T value){
-        return new DynamicValue<T>(propertyName, Optional.of(value));
-    }
-
-    /**
-     * Creates a new instance.
-     * @param propertyName the key of the property, not null.
-     * @param value the initial value
-     * @param <T> the target type.
-     * @return a new instance, never null
-     */
-    public static <T> DynamicValue<T> ofNullable(String propertyName, T value){
-        return value == null ? empty(propertyName) : of(propertyName, value);
-    }
-
     /**
      * Performs a commit, if necessary, and returns the current value.
      *
@@ -144,7 +68,7 @@ public final class DynamicValue<T> implements Serializable {
      *
      * @see DynamicValue#isPresent()
      */
-    public T commitAndGet(){
+    default T commitAndGet(){
         commit();
         return get();
     }
@@ -153,57 +77,30 @@ public final class DynamicValue<T> implements Serializable 
{
      * Commits a new value that has not been committed yet, make it the new 
value of the instance. On change any
      * registered listeners will be triggered.
      */
-    public void commit(){
-        synchronized (this){
-            if(newValue!=null){
-                PropertyChangeEvent evt = new PropertyChangeEvent(this, 
propertyName, value.orElse(null),
-                        newValue.orElse(null));
-                value = newValue;
-                newValue = null;
-                for(Consumer<PropertyChangeEvent> consumer: listeners.get()){
-                    consumer.accept(evt);
-                }
-            }
-        }
-    }
+    void commit();
 
     /**
      * Discards a new value that was published. No listeners will be informed.
      */
-    public void discard(){
-        newValue = null;
-    }
-
-
+    void discard();
 
     /**
      * Access the {@link UpdatePolicy} used for updating this value.
      * @return the update policy, never null.
      */
-    public UpdatePolicy getUpdatePolicy() {
-        return updatePolicy;
-    }
+    UpdatePolicy getUpdatePolicy();
 
     /**
      * Add a listener to be called as weak reference, when this value has been 
changed.
      * @param l the listener, not null
      */
-    public void addListener(Consumer<PropertyChangeEvent> l) {
-        if(listeners==null){
-            listeners = new WeakList<>();
-        }
-        listeners.add(l);
-    }
+    void addListener(Consumer<PropertyChangeEvent> l);
 
     /**
      * Removes a listener to be called, when this value has been changed.
      * @param l the listner to be removed, not null
      */
-    public void removeListener(Consumer<PropertyChangeEvent> l) {
-        if(listeners!=null){
-            listeners.remove(l);
-        }
-    }
+    void removeListener(Consumer<PropertyChangeEvent> l);
 
     /**
      * If a value is present in this {@code DynamicValue}, returns the value,
@@ -214,64 +111,40 @@ public final class DynamicValue<T> implements 
Serializable {
      *
      * @see DynamicValue#isPresent()
      */
-    public T get() {
-        return value.get();
-    }
+    T get();
 
     /**
-     * Method to apply a new value. Depending on the {@link  UpdatePolicy}
+     * Method to check for and apply a new value. Depending on the {@link  
UpdatePolicy}
      * the value is immediately or deferred visible (or it may even be ignored 
completely).
-     * @param newValue the new value, may also be null.
+     * @return true, if a new value has been detected. The value may not be 
visible depending on the current
+     * {@link org.apache.tamaya.inject.DynamicValue.UpdatePolicy} in place.
      */
-    public void setNewValue(T newValue){
-        switch(this.updatePolicy){
-            case IMMEDIATE:
-                this.newValue = Optional.ofNullable(newValue);
-                commit();
-                break;
-            case LOG_AND_DISCARD:
-                Logger.getLogger(getClass().getName()).info("Discard change on 
" + this + ", newValue="+newValue);
-                this.newValue = null;
-                break;
-            case NEVER:
-                this.newValue = null;
-                break;
-            case EXPLCIT:
-            default:
-                this.newValue = Optional.ofNullable(newValue);
-                break;
-        }
+    boolean updateValue();
 
-    }
+    /**
+     * Evaluates the current value dynamically from the underlying 
configuration.
+     * @return the current actual value, or null.
+     */
+    T evaluateValue();
 
     /**
      * Sets a new {@link UpdatePolicy}.
      * @param updatePolicy the new policy, not null.
      */
-    public void setUpdatePolicy(UpdatePolicy updatePolicy){
-        this.updatePolicy = Objects.requireNonNull(updatePolicy);
-    }
+    void setUpdatePolicy(UpdatePolicy updatePolicy);
 
     /**
      * Access a new value that has not yet been committed.
      * @return the uncommitted new value, or null.
      */
-    public T getNewValue(){
-        Optional<T> nv = newValue;
-        if(nv!=null){
-            return nv.orElse(null);
-        }
-        return null;
-    }
+    T getNewValue();
 
     /**
      * Return {@code true} if there is a value present, otherwise {@code 
false}.
      *
      * @return {@code true} if there is a value present, otherwise {@code 
false}
      */
-    public boolean isPresent() {
-        return value.isPresent();
-    }
+    boolean isPresent();
 
     /**
      * If a value is present, invoke the specified consumer with the value,
@@ -281,89 +154,10 @@ public final class DynamicValue<T> implements 
Serializable {
      * @throws NullPointerException if value is present and {@code consumer} is
      * null
      */
-    public void ifPresent(Consumer<? super T> consumer) {
-        value.ifPresent(consumer);
-    }
-
-    /**
-     * If a value is present, and the value matches the given predicate,
-     * return an {@code Optional} describing the value, otherwise return an
-     * empty {@code Optional}.
-     *
-     * @param predicate a predicate to apply to the value, if present
-     * @return an {@code Optional} describing the value of this {@code 
Optional}
-     * if a value is present and the value matches the given predicate,
-     * otherwise an empty {@code Optional}
-     * @throws NullPointerException if the predicate is null
-     */
-    public DynamicValue<T> filter(Predicate<? super T> predicate) {
-        Objects.requireNonNull(predicate);
-        if (!isPresent()) {
-            return this;
+    default void ifPresent(Consumer<? super T> consumer){
+        if(isPresent()){
+            consumer.accept(get());
         }
-        return predicate.test(value.get()) ? this : empty(propertyName);
-    }
-
-    /**
-     * If a value is present, apply the provided mapping function to it,
-     * and if the result is non-null, return an {@code Optional} describing the
-     * result.  Otherwise return an empty {@code Optional}.
-     *
-     * NOTE This method supports post-processing on optional values, without
-     * the need to explicitly check for a return status.  For example, the
-     * following code traverses a stream of file names, selects one that has
-     * not yet been processed, and then opens that file, returning an
-     * {@code Optional<FileInputStream>}:
-     *
-     * <pre>{@code
-     *     Optional<FileInputStream> fis =
-     *         names.stream().filter(name -> !isProcessedYet(name))
-     *                       .findFirst()
-     *                       .map(name -> new FileInputStream(name));
-     * }</pre>
-     *
-     * Here, {@code findFirst} returns an {@code Optional<String>}, and then
-     * {@code map} returns an {@code Optional<FileInputStream>} for the desired
-     * file if one exists.
-     *
-     * @param <U> The type of the result of the mapping function
-     * @param mapper a mapping function to apply to the value, if present
-     * @return an {@code Optional} describing the result of applying a mapping
-     * function to the value of this {@code Optional}, if a value is present,
-     * otherwise an empty {@code Optional}
-     * @throws NullPointerException if the mapping function is null
-     */
-    public <U> DynamicValue<U> map(Function<? super T, ? extends U> mapper) {
-        Objects.requireNonNull(mapper);
-        if (!isPresent()) {
-            return empty(propertyName);
-        }
-        return DynamicValue.ofNullable(propertyName, 
mapper.apply(value.get()));
-    }
-
-    /**
-     * If a value is present, apply the provided {@code Optional}-bearing
-     * mapping function to it, return that result, otherwise return an empty
-     * {@code Optional}.  This method is similar to {@link #map(Function)},
-     * but the provided mapper is one whose result is already an {@code 
Optional},
-     * and if invoked, {@code flatMap} does not wrap it with an additional
-     * {@code Optional}.
-     *
-     * @param <U> The type parameter to the {@code Optional} returned by
-     * @param mapper a mapping function to apply to the value, if present
-     *           the mapping function
-     * @return the result of applying an {@code Optional}-bearing mapping
-     * function to the value of this {@code Optional}, if a value is present,
-     * otherwise an empty {@code Optional}
-     * @throws NullPointerException if the mapping function is null or returns
-     * a null result
-     */
-    public <U> DynamicValue<U> flatMap(Function<? super T, DynamicValue<U>> 
mapper) {
-        Objects.requireNonNull(mapper);
-        if (!isPresent()) {
-            return empty(propertyName);
-        }
-        return Objects.requireNonNull(mapper.apply(value.get()));
     }
 
     /**
@@ -373,9 +167,12 @@ public final class DynamicValue<T> implements Serializable 
{
      * be null
      * @return the value, if present, otherwise {@code other}
      */
-    public T orElse(T other) {
-        return value.orElse(other);
-    }
+   default T orElse(T other){
+       if(isPresent()){
+           return get();
+       }
+       return other;
+   }
 
     /**
      * Return the value if present, otherwise invoke {@code other} and return
@@ -387,8 +184,11 @@ public final class DynamicValue<T> implements Serializable 
{
      * @throws NullPointerException if value is not present and {@code other} 
is
      * null
      */
-    public T orElseGet(Supplier<? extends T> other) {
-        return value.orElseGet(other);
+    default T orElseGet(Supplier<? extends T> other){
+        if(isPresent()){
+            return get();
+        }
+        return other.get();
     }
 
     /**
@@ -407,100 +207,22 @@ public final class DynamicValue<T> implements 
Serializable {
      * @throws NullPointerException if no value is present and
      * {@code exceptionSupplier} is null
      */
-    public <X extends Throwable> T orElseThrow(Supplier<? extends X> 
exceptionSupplier) throws X {
-        return value.orElseThrow(exceptionSupplier);
+    default <X extends Throwable> T orElseThrow(Supplier<? extends X> 
exceptionSupplier) throws X{
+        if(isPresent()){
+            return  get();
+        }
+        throw exceptionSupplier.get();
     }
 
     /**
      * Converts the instance to an {@link java.util.Optional} instance.
      * @return the corresponding Optional value.
      */
-    public Optional<T> toOptional(){
-        return value;
-    }
-
-    /**
-     * Serialization implementation that strips away the non serializable 
Optional part.
-     * @param oos the output stream
-     * @throws IOException if serialization fails.
-     */
-    private void writeObject(ObjectOutputStream oos)throws IOException {
-        oos.writeObject(updatePolicy);
-        if(isPresent()) {
-            oos.writeObject(this.value.get());
-        }  else{
-            oos.writeObject(null);
-        }
-    }
-
-    /**
-     * Reads an instance from the input stream.
-     * @param ois the object input stream
-     * @throws IOException if deserialization fails.
-     * @throws ClassNotFoundException
-     */
-    private void readObject(ObjectInputStream ois) throws IOException, 
ClassNotFoundException {
-        this.updatePolicy = (UpdatePolicy)ois.readObject();
-        if(isPresent()) {
-            this.value = Optional.of((T) ois.readObject());
-        }
-        newValue = null;
-    }
-
-
-    /**
-     * Simple helper that allows keeping the listeners registered as weak 
references, hereby avoiding any
-     * memory leaks.
-     * @param <I> the type
-     */
-    private class WeakList<I>{
-        final List<WeakReference<I>> refs = new LinkedList<>();
-
-        /**
-         * Adds a new instance.
-         * @param t the new instance, not null.
-         */
-        void add(I t){
-            refs.add(new WeakReference<I>(t));
-        }
-
-        /**
-         * Removes a instance.
-         * @param t the instance to be removed.
-         */
-        void remove(I t){
-            synchronized (refs){
-                for(Iterator<WeakReference<I>> iterator = 
refs.iterator();iterator.hasNext();){
-                    WeakReference<I> ref = iterator.next();
-                    I instance = ref.get();
-                    if(instance==null || instance == t){
-                        iterator.remove();
-                        break;
-                    }
-                }
-            }
-        }
-
-
-        /**
-         * Access a list (copy) of the current instances that were not 
discarded by the GC.
-         * @return the list of accessible items.
-         */
-        public List<I> get() {
-            synchronized (refs) {
-                List<I> res = new ArrayList<>();
-                for (Iterator<WeakReference<I>> iterator = refs.iterator(); 
iterator.hasNext(); ) {
-                    WeakReference<I> ref = iterator.next();
-                    I instance = ref.get();
-                    if(instance==null){
-                        iterator.remove();
-                    } else{
-                        res.add(instance);
-                    }
-                }
-                return res;
-            }
+    default Optional<T> toOptional(){
+        if(isPresent()){
+            return Optional.of(get());
         }
+        return Optional.empty();
     }
 
 }

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/4ddf46f7/modules/injection/src/main/java/org/apache/tamaya/inject/internal/ConfigTemplateInvocationHandler.java
----------------------------------------------------------------------
diff --git 
a/modules/injection/src/main/java/org/apache/tamaya/inject/internal/ConfigTemplateInvocationHandler.java
 
b/modules/injection/src/main/java/org/apache/tamaya/inject/internal/ConfigTemplateInvocationHandler.java
index 9e9ee73..4909207 100644
--- 
a/modules/injection/src/main/java/org/apache/tamaya/inject/internal/ConfigTemplateInvocationHandler.java
+++ 
b/modules/injection/src/main/java/org/apache/tamaya/inject/internal/ConfigTemplateInvocationHandler.java
@@ -18,11 +18,17 @@
  */
 package org.apache.tamaya.inject.internal;
 
+import org.apache.tamaya.ConfigException;
 import org.apache.tamaya.Configuration;
+import org.apache.tamaya.PropertyConverter;
 import org.apache.tamaya.TypeLiteral;
+import org.apache.tamaya.inject.DynamicValue;
+import org.apache.tamaya.inject.WithPropertyConverter;
 
 import java.lang.reflect.InvocationHandler;
 import java.lang.reflect.Method;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
 import java.util.Objects;
 
 /**
@@ -30,43 +36,78 @@ import java.util.Objects;
  */
 public final class ConfigTemplateInvocationHandler implements 
InvocationHandler {
 
-    /*
-    TODO
-    the given method (in case of a template) can use different caching 
strategies:
-    1) no caching (always evaluate the values completely) - slow.
-    2) instance caching (a cache per instance).
-    3) classloader caching...
-    4) global shared cache.
-     */
-
-
     /**
      * The configured type.
      */
     private ConfiguredType type;
 
     /**
-     * Creates a new handler instance.
-     * @param type           the target type, not null.
-     * @param configurations overriding configurations to be used for 
evaluating the values for injection into {@code instance}, not null.
-     *                       If no such config is passed, the default 
configurationa provided by the current
-     *                       registered providers are used.
+     * The configuration instance of this proxy.
      */
-    public ConfigTemplateInvocationHandler(Class<?> type, Configuration... 
configurations) {
-        Objects.requireNonNull(configurations);
+    private Configuration configuration;
 
+    /**
+     * Creates a new handler instance.
+     *
+     * @param type          the target type, not null.
+     * @param configuration the configuration to be used for evaluating the 
values for injection into {@code instance},
+     *                      not null.
+     */
+    public ConfigTemplateInvocationHandler(Class<?> type, Configuration 
configuration) {
+        Objects.requireNonNull(configuration);
         this.type = new ConfiguredType(Objects.requireNonNull(type));
         if (!type.isInterface()) {
             throw new IllegalArgumentException("Can only proxy interfaces as 
configuration templates.");
         }
+        this.configuration = Objects.requireNonNull(configuration);
     }
 
     @Override
     public Object invoke(Object proxy, Method method, Object[] args) throws 
Throwable {
         if ("toString".equals(method.getName())) {
             return "Configured Proxy -> " + this.type.getType().getName();
+        } else if ("hashCode".equals(method.getName())) {
+            return Objects.hashCode(proxy);
+        } else if ("equals".equals(method.getName())) {
+            return Objects.equals(proxy, args[0]);
+        } else if ("get".equals(method.getName())) {
+            return this.configuration;
+        }
+        if (method.getReturnType() == DynamicValue.class) {
+            // Check for adapter/filter
+            Type targetType = method.getGenericReturnType();
+            if (targetType == null) {
+                throw new ConfigException("Failed to evaluate target type for 
" + method.getDeclaringClass()
+                        .getTypeName() + '.' + method.getName());
+            }
+            if (targetType instanceof ParameterizedType) {
+                ParameterizedType pt = (ParameterizedType) targetType;
+                Type[] types = pt.getActualTypeArguments();
+                if (types.length != 1) {
+                    throw new ConfigException("Failed to evaluate target type 
for " + method.getDeclaringClass()
+                            .getTypeName() + '.' + method.getName());
+                }
+                targetType = (Class) types[0];
+            }
+            PropertyConverter<Object> propertyConverter = null;
+            WithPropertyConverter annot = 
method.getAnnotation(WithPropertyConverter.class);
+            if (annot != null) {
+                try {
+                    propertyConverter = (PropertyConverter<Object>) 
annot.value().newInstance();
+                } catch (Exception e) {
+                    throw new ConfigException("Failed to instantiate annotated 
PropertyConverter on " +
+                            method.getDeclaringClass().getTypeName()
+                            + '.' + method.getName(), e);
+                }
+            }
+            return new DefaultDynamicValue<Object>(method.getName(),
+                    this.configuration, TypeLiteral.of(targetType), 
propertyConverter, InjectionUtils.getKeys(method));
         }
         String configValue = InjectionUtils.getConfigValue(method);
-        return InjectionUtils.adaptValue(method,  
TypeLiteral.of(method.getReturnType()), configValue);
+        Object result = InjectionUtils.adaptValue(method, 
TypeLiteral.of(method.getReturnType()), configValue);
+        if (result == null && method.isDefault()) {
+            result = method.getDefaultValue();
+        }
+        return result;
     }
 }

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/4ddf46f7/modules/injection/src/main/java/org/apache/tamaya/inject/internal/ConfiguredField.java
----------------------------------------------------------------------
diff --git 
a/modules/injection/src/main/java/org/apache/tamaya/inject/internal/ConfiguredField.java
 
b/modules/injection/src/main/java/org/apache/tamaya/inject/internal/ConfiguredField.java
index 8bde306..a2a01ea 100644
--- 
a/modules/injection/src/main/java/org/apache/tamaya/inject/internal/ConfiguredField.java
+++ 
b/modules/injection/src/main/java/org/apache/tamaya/inject/internal/ConfiguredField.java
@@ -18,16 +18,24 @@
  */
 package org.apache.tamaya.inject.internal;
 
+import org.apache.tamaya.ConfigException;
+import org.apache.tamaya.Configuration;
+import org.apache.tamaya.ConfigurationProvider;
+import org.apache.tamaya.PropertyConverter;
+import org.apache.tamaya.TypeLiteral;
+import org.apache.tamaya.inject.ConfigRoot;
+import org.apache.tamaya.inject.ConfiguredProperty;
+import org.apache.tamaya.inject.DynamicValue;
+import org.apache.tamaya.inject.WithPropertyConverter;
+
 import java.lang.reflect.Field;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
 import java.security.AccessController;
 import java.security.PrivilegedExceptionAction;
 import java.util.List;
 import java.util.Objects;
-
-import org.apache.tamaya.ConfigException;
-import org.apache.tamaya.TypeLiteral;
-import org.apache.tamaya.inject.ConfigRoot;
-import org.apache.tamaya.inject.ConfiguredProperty;
+import java.util.logging.Logger;
 
 /**
  * Small class that contains and manages all information anc access to a 
configured field and a concrete instance current
@@ -35,8 +43,10 @@ import org.apache.tamaya.inject.ConfiguredProperty;
  * final keys by reflection.
  */
 public class ConfiguredField {
-
-
+    /**
+     * The logger used.
+     */
+    private static final Logger LOG = 
Logger.getLogger(ConfiguredField.class.getName());
     /**
      * The configured field instance.
      */
@@ -59,12 +69,66 @@ public class ConfiguredField {
      * @throws ConfigException if evaluation or conversion failed.
      */
     public void applyInitialValue(Object target) throws ConfigException {
-        String configValue = 
InjectionUtils.getConfigValue(this.annotatedField);
-        applyValue(target, configValue, false);
+        if (this.annotatedField.getType() == DynamicValue.class) {
+            initDynamicValue(target);
+        } else {
+            String configValue = 
InjectionUtils.getConfigValue(this.annotatedField);
+            applyValue(target, configValue, false);
+        }
     }
 
 
     /**
+     * This method instantiates and assigns a dynamic value.
+     *
+     * @param target the target instance, not null.
+     * @throws ConfigException if the configuration required could not be 
resolved or converted.
+     */
+    public void initDynamicValue(Object target) throws ConfigException {
+        Objects.requireNonNull(target);
+        try {
+            // Check for adapter/filter
+            Type targetType = this.annotatedField.getGenericType();
+            if (targetType == null) {
+                throw new ConfigException("Failed to evaluate target type for 
" + annotatedField.getAnnotatedType().getType().getTypeName()
+                        + '.' + annotatedField.getName());
+            }
+            if (targetType instanceof ParameterizedType) {
+                ParameterizedType pt = (ParameterizedType) targetType;
+                Type[] types = pt.getActualTypeArguments();
+                if (types.length != 1) {
+                    throw new ConfigException("Failed to evaluate target type 
for " + annotatedField.getAnnotatedType().getType().getTypeName()
+                            + '.' + annotatedField.getName());
+                }
+                targetType = (Class) types[0];
+            }
+            PropertyConverter<?> propertyConverter = null;
+            WithPropertyConverter annot = 
this.annotatedField.getAnnotation(WithPropertyConverter.class);
+            if (annot != null) {
+                try {
+                    propertyConverter = annot.value().newInstance();
+                } catch (Exception e) {
+                    throw new ConfigException("Failed to instantiate annotated 
PropertyConverter on " +
+                            
annotatedField.getAnnotatedType().getType().getTypeName()
+                            + '.' + annotatedField.getName(), e);
+                }
+            }
+            List<String> keys = InjectionUtils.getKeys(this.annotatedField);
+            Configuration configuration = 
ConfigurationProvider.getConfiguration();
+            Object value = new 
DefaultDynamicValue(this.annotatedField.getName(), configuration,
+                    TypeLiteral.of(targetType), propertyConverter, keys);
+            AccessController.doPrivileged((PrivilegedExceptionAction<Object>) 
() -> {
+                annotatedField.setAccessible(true);
+                return annotatedField;
+            });
+            annotatedField.set(target, value);
+        } catch (Exception e) {
+            throw new ConfigException("Failed to annotation configured field: 
" + this.annotatedField.getDeclaringClass()
+                    .getName() + '.' + annotatedField.getName(), e);
+        }
+    }
+
+    /**
      * This method reapplies a changed configuration keys to the field.
      *
      * @param target      the target instance, not null.
@@ -111,4 +175,10 @@ public class ConfiguredField {
         return keys.contains(key);
     }
 
+    @Override
+    public String toString() {
+        return "ConfiguredField{" +
+                annotatedField.getName() + ": " +
+                " " + 
annotatedField.getAnnotatedType().getType().getTypeName() + '}';
+    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/4ddf46f7/modules/injection/src/main/java/org/apache/tamaya/inject/internal/ConfiguredType.java
----------------------------------------------------------------------
diff --git 
a/modules/injection/src/main/java/org/apache/tamaya/inject/internal/ConfiguredType.java
 
b/modules/injection/src/main/java/org/apache/tamaya/inject/internal/ConfiguredType.java
index 8c4f68f..8828598 100644
--- 
a/modules/injection/src/main/java/org/apache/tamaya/inject/internal/ConfiguredType.java
+++ 
b/modules/injection/src/main/java/org/apache/tamaya/inject/internal/ConfiguredType.java
@@ -94,10 +94,6 @@ public class ConfiguredType {
                     if (m.isDefault()) {
                         addObserverMethod(m);
                     }
-                } else {
-                    if (m.isDefault()) {
-                        addPropertySetter(m, prop);
-                    }
                 }
             } else {
                 if (mAnnot != null) {
@@ -192,4 +188,9 @@ public class ConfiguredType {
     public Class getType() {
         return this.type;
     }
+
+    @Override
+    public String toString() {
+        return "ConfiguredType{"+ this.getType().getName() + '}';
+    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/4ddf46f7/modules/injection/src/main/java/org/apache/tamaya/inject/internal/DefaultConfigurationInjector.java
----------------------------------------------------------------------
diff --git 
a/modules/injection/src/main/java/org/apache/tamaya/inject/internal/DefaultConfigurationInjector.java
 
b/modules/injection/src/main/java/org/apache/tamaya/inject/internal/DefaultConfigurationInjector.java
index 6f6794b..baa397d 100644
--- 
a/modules/injection/src/main/java/org/apache/tamaya/inject/internal/DefaultConfigurationInjector.java
+++ 
b/modules/injection/src/main/java/org/apache/tamaya/inject/internal/DefaultConfigurationInjector.java
@@ -18,9 +18,11 @@
  */
 package org.apache.tamaya.inject.internal;
 
+import org.apache.tamaya.ConfigurationProvider;
 import org.apache.tamaya.inject.ConfigurationInjector;
 
 import javax.annotation.Priority;
+import java.lang.reflect.Proxy;
 import java.util.Map;
 import java.util.Objects;
 import java.util.concurrent.ConcurrentHashMap;
@@ -54,6 +56,7 @@ public final class DefaultConfigurationInjector implements 
ConfigurationInjector
      *
      * @param instance the instance to be configured
      */
+    @Override
     public <T> T configure(T instance) {
         Class type = Objects.requireNonNull(instance).getClass();
         ConfiguredType configuredType = registerTypeInternal(type);
@@ -61,6 +64,21 @@ public final class DefaultConfigurationInjector implements 
ConfigurationInjector
         return instance;
     }
 
+    /**
+     * Create a template implementting the annotated methods based on current 
configuration data.
+     *
+     * @param templateType the type of the template to be created.
+     */
+    @Override
+    public <T> T createTemplate(Class<T> templateType) {
+        ClassLoader cl = Thread.currentThread().getContextClassLoader();
+        if(cl==null){
+            cl = this.getClass().getClassLoader();
+        }
+        return (T)Proxy.newProxyInstance(cl,new Class[]{Supplier.class, 
Objects.requireNonNull(templateType)},
+                new ConfigTemplateInvocationHandler(templateType, 
ConfigurationProvider.getConfiguration()));
+    }
+
 
     @Override
     public <T> Supplier<T> getConfiguredSupplier(Supplier<T> supplier) {

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/4ddf46f7/modules/injection/src/main/java/org/apache/tamaya/inject/internal/DefaultDynamicValue.java
----------------------------------------------------------------------
diff --git 
a/modules/injection/src/main/java/org/apache/tamaya/inject/internal/DefaultDynamicValue.java
 
b/modules/injection/src/main/java/org/apache/tamaya/inject/internal/DefaultDynamicValue.java
new file mode 100644
index 0000000..9f97ad1
--- /dev/null
+++ 
b/modules/injection/src/main/java/org/apache/tamaya/inject/internal/DefaultDynamicValue.java
@@ -0,0 +1,441 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tamaya.inject.internal;
+
+import org.apache.tamaya.Configuration;
+import org.apache.tamaya.PropertyConverter;
+import org.apache.tamaya.TypeLiteral;
+import org.apache.tamaya.inject.DynamicValue;
+
+import java.beans.PropertyChangeEvent;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+import java.util.logging.Logger;
+
+/**
+ * A accessor for a single configured value. This can be used to support 
values that may change during runtime,
+ * reconfigured or final. Hereby external code (could be Tamaya configuration 
listners or client code), can set a
+ * new value. Depending on the {@link UpdatePolicy} the new value is 
immedeately active or it requires an active commit
+ * by client code. Similarly an instance also can ignore all later changes to 
the value.
+ * <h3>Implementation Details</h3>
+ * This class is
+ * <ul>
+ * <li>Serializable, when also the item stored is serializable</li>
+ * <li>Thread safe</li>
+ * </ul>
+ *
+ * @param <T> The type of the value.
+ */
+public final class DefaultDynamicValue<T> implements DynamicValue<T>, 
Serializable {
+
+    private static final long serialVersionUID = -2071172847144537443L;
+
+    /**
+     * The property name of the entry.
+     */
+    private String propertyName;
+    /**
+     * The keys to be resolved.
+     */
+    private String[] keys;
+    /**
+     * Back reference to the base configuration instance. This reference is 
used reevalaute the given property and
+     * compare the result with the previous value after a configuration change 
was triggered.
+     */
+    private Configuration configuration;
+    /**
+     * The target type of the property used to lookup a matching {@link 
org.apache.tamaya.PropertyConverter}.
+     * If null, {@code propertyConverter} is set and used instead.
+     */
+    private TypeLiteral<T> targetType;
+    /**
+     * The property converter to be applied, may be null. In the ladder case 
targetType is not null.
+     */
+    private PropertyConverter<T> propertyConverter;
+    /**
+     * Policy that defines how new values are applied, be default it is 
applied initially once, but never updated
+     * anymore.
+     */
+    private UpdatePolicy updatePolicy = UpdatePolicy.NEVER;
+    /**
+     * The current value, never null.
+     */
+    private transient Optional<T> value;
+    /**
+     * The new value, or null.
+     */
+    private transient Optional<T> newValue;
+    /**
+     * List of listeners that listen for changes.
+     */
+    private transient WeakList<Consumer<PropertyChangeEvent>> listeners;
+
+    /**
+     * Constructor.
+     *
+     * @param propertyName      the name of the fields' property/method.
+     * @param keys              the keys of the property, not null.
+     * @param configuration     the configuration, not null.
+     * @param targetType        the target type, not null.
+     * @param propertyConverter the optional converter to be used.
+     */
+    DefaultDynamicValue(String propertyName, Configuration configuration, 
TypeLiteral<T> targetType,
+                        PropertyConverter<T> propertyConverter, List<String> 
keys) {
+        this.propertyName = Objects.requireNonNull(propertyName);
+        this.keys = keys.toArray(new String[keys.size()]);
+        this.configuration = Objects.requireNonNull(configuration);
+        this.propertyConverter = propertyConverter;
+        this.targetType = targetType;
+        this.value = Optional.ofNullable(evaluateValue());
+    }
+
+
+    /**
+     * Performs a commit, if necessary, and returns the current value.
+     *
+     * @return the non-null value held by this {@code DynamicValue}
+     * @throws org.apache.tamaya.ConfigException if there is no value present
+     * @see DefaultDynamicValue#isPresent()
+     */
+    public T commitAndGet() {
+        commit();
+        return get();
+    }
+
+    /**
+     * Commits a new value that has not been committed yet, make it the new 
value of the instance. On change any
+     * registered listeners will be triggered.
+     */
+    public void commit() {
+        synchronized (this) {
+            if (newValue != null) {
+                PropertyChangeEvent evt = new PropertyChangeEvent(this, 
propertyName, value.orElse(null),
+                        newValue.orElse(null));
+                value = newValue;
+                newValue = null;
+                for (Consumer<PropertyChangeEvent> consumer : listeners.get()) 
{
+                    consumer.accept(evt);
+                }
+            }
+        }
+    }
+
+    /**
+     * Discards a new value that was published. No listeners will be informed.
+     */
+    public void discard() {
+        newValue = null;
+    }
+
+
+    /**
+     * Access the {@link UpdatePolicy} used for updating this value.
+     *
+     * @return the update policy, never null.
+     */
+    public UpdatePolicy getUpdatePolicy() {
+        return updatePolicy;
+    }
+
+    /**
+     * Sets a new {@link UpdatePolicy}.
+     *
+     * @param updatePolicy the new policy, not null.
+     */
+    public void setUpdatePolicy(UpdatePolicy updatePolicy) {
+        this.updatePolicy = Objects.requireNonNull(updatePolicy);
+    }
+
+    /**
+     * Add a listener to be called as weak reference, when this value has been 
changed.
+     *
+     * @param l the listener, not null
+     */
+    public void addListener(Consumer<PropertyChangeEvent> l) {
+        if (listeners == null) {
+            listeners = new WeakList<>();
+        }
+        listeners.add(l);
+    }
+
+    /**
+     * Removes a listener to be called, when this value has been changed.
+     *
+     * @param l the listner to be removed, not null
+     */
+    public void removeListener(Consumer<PropertyChangeEvent> l) {
+        if (listeners != null) {
+            listeners.remove(l);
+        }
+    }
+
+    /**
+     * If a value is present in this {@code DynamicValue}, returns the value,
+     * otherwise throws {@code ConfigException}.
+     *
+     * @return the non-null value held by this {@code Optional}
+     * @throws org.apache.tamaya.ConfigException if there is no value present
+     * @see DefaultDynamicValue#isPresent()
+     */
+    public T get() {
+        return value.get();
+    }
+
+    /**
+     * Method to check for and apply a new value. Depending on the {@link  
UpdatePolicy}
+     * the value is immediately or deferred visible (or it may even be ignored 
completely).
+     *
+     * @return true, if a new value has been detected. The value may not be 
visible depending on the current
+     * {@link DefaultDynamicValue.UpdatePolicy} in place.
+     */
+    public boolean updateValue() {
+        T newValue = evaluateValue();
+        if (Objects.equals(newValue, this.value.orElse(null))) {
+            return false;
+        }
+        switch (this.updatePolicy) {
+            case IMMEDIATE:
+                this.newValue = Optional.ofNullable(newValue);
+                commit();
+                break;
+            case LOG_AND_DISCARD:
+                Logger.getLogger(getClass().getName()).info("Discard change on 
" + this + ", newValue=" + newValue);
+                this.newValue = null;
+                break;
+            case NEVER:
+                this.newValue = null;
+                break;
+            case EXPLCIT:
+            default:
+                this.newValue = Optional.ofNullable(newValue);
+                break;
+        }
+        return true;
+    }
+
+    /**
+     * Evaluates the current value dynamically from the underlying 
configuration.
+     *
+     * @return the current actual value, or null.
+     */
+    public T evaluateValue() {
+        for (String key : keys) {
+            T value;
+            if (propertyConverter == null) {
+                value = configuration.get(key, targetType);
+            } else {
+                value = configuration.get(key, propertyConverter);
+            }
+            if (value != null) {
+                return value;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Access a new value that has not yet been committed.
+     *
+     * @return the uncommitted new value, or null.
+     */
+    public T getNewValue() {
+        Optional<T> nv = newValue;
+        if (nv != null) {
+            return nv.orElse(null);
+        }
+        return null;
+    }
+
+    /**
+     * Return {@code true} if there is a value present, otherwise {@code 
false}.
+     *
+     * @return {@code true} if there is a value present, otherwise {@code 
false}
+     */
+    public boolean isPresent() {
+        return value.isPresent();
+    }
+
+    /**
+     * If a value is present, invoke the specified consumer with the value,
+     * otherwise do nothing.
+     *
+     * @param consumer block to be executed if a value is present
+     * @throws NullPointerException if value is present and {@code consumer} is
+     *                              null
+     */
+    public void ifPresent(Consumer<? super T> consumer) {
+        value.ifPresent(consumer);
+    }
+
+    /**
+     * Return the value if present, otherwise return {@code other}.
+     *
+     * @param other the value to be returned if there is no value present, may
+     *              be null
+     * @return the value, if present, otherwise {@code other}
+     */
+    public T orElse(T other) {
+        return value.orElse(other);
+    }
+
+    /**
+     * Return the value if present, otherwise invoke {@code other} and return
+     * the result of that invocation.
+     *
+     * @param other a {@code Supplier} whose result is returned if no value
+     *              is present
+     * @return the value if present otherwise the result of {@code other.get()}
+     * @throws NullPointerException if value is not present and {@code other} 
is
+     *                              null
+     */
+    public T orElseGet(Supplier<? extends T> other) {
+        return value.orElseGet(other);
+    }
+
+    /**
+     * Return the contained value, if present, otherwise throw an exception
+     * to be created by the provided supplier.
+     * <p>
+     * NOTE A method reference to the exception constructor with an empty
+     * argument list can be used as the supplier. For example,
+     * {@code IllegalStateException::new}
+     *
+     * @param <X>               Type of the exception to be thrown
+     * @param exceptionSupplier The supplier which will return the exception to
+     *                          be thrown
+     * @return the present value
+     * @throws X                    if there is no value present
+     * @throws NullPointerException if no value is present and
+     *                              {@code exceptionSupplier} is null
+     */
+    public <X extends Throwable> T orElseThrow(Supplier<? extends X> 
exceptionSupplier) throws X {
+        return value.orElseThrow(exceptionSupplier);
+    }
+
+    /**
+     * Converts the instance to an {@link java.util.Optional} instance.
+     *
+     * @return the corresponding Optional value.
+     */
+    public Optional<T> toOptional() {
+        return value;
+    }
+
+    /**
+     * Serialization implementation that strips away the non serializable 
Optional part.
+     *
+     * @param oos the output stream
+     * @throws java.io.IOException if serialization fails.
+     */
+    private void writeObject(ObjectOutputStream oos) throws IOException {
+        oos.writeObject(updatePolicy);
+        if (isPresent()) {
+            oos.writeObject(this.value.get());
+        } else {
+            oos.writeObject(null);
+        }
+    }
+
+    /**
+     * Reads an instance from the input stream.
+     *
+     * @param ois the object input stream
+     * @throws java.io.IOException    if deserialization fails.
+     * @throws ClassNotFoundException
+     */
+    private void readObject(ObjectInputStream ois) throws IOException, 
ClassNotFoundException {
+        this.updatePolicy = (UpdatePolicy) ois.readObject();
+        if (isPresent()) {
+            this.value = Optional.of((T) ois.readObject());
+        }
+        newValue = null;
+    }
+
+
+    /**
+     * Simple helper that allows keeping the listeners registered as weak 
references, hereby avoiding any
+     * memory leaks.
+     *
+     * @param <I> the type
+     */
+    private class WeakList<I> {
+        final List<WeakReference<I>> refs = new LinkedList<>();
+
+        /**
+         * Adds a new instance.
+         *
+         * @param t the new instance, not null.
+         */
+        void add(I t) {
+            refs.add(new WeakReference<>(t));
+        }
+
+        /**
+         * Removes a instance.
+         *
+         * @param t the instance to be removed.
+         */
+        void remove(I t) {
+            synchronized (refs) {
+                for (Iterator<WeakReference<I>> iterator = refs.iterator(); 
iterator.hasNext(); ) {
+                    WeakReference<I> ref = iterator.next();
+                    I instance = ref.get();
+                    if (instance == null || instance == t) {
+                        iterator.remove();
+                        break;
+                    }
+                }
+            }
+        }
+
+
+        /**
+         * Access a list (copy) of the current instances that were not 
discarded by the GC.
+         *
+         * @return the list of accessible items.
+         */
+        public List<I> get() {
+            synchronized (refs) {
+                List<I> res = new ArrayList<>();
+                for (Iterator<WeakReference<I>> iterator = refs.iterator(); 
iterator.hasNext(); ) {
+                    WeakReference<I> ref = iterator.next();
+                    I instance = ref.get();
+                    if (instance == null) {
+                        iterator.remove();
+                    } else {
+                        res.add(instance);
+                    }
+                }
+                return res;
+            }
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/4ddf46f7/modules/injection/src/main/java/org/apache/tamaya/inject/internal/InjectionUtils.java
----------------------------------------------------------------------
diff --git 
a/modules/injection/src/main/java/org/apache/tamaya/inject/internal/InjectionUtils.java
 
b/modules/injection/src/main/java/org/apache/tamaya/inject/internal/InjectionUtils.java
index 765331b..fae86b5 100644
--- 
a/modules/injection/src/main/java/org/apache/tamaya/inject/internal/InjectionUtils.java
+++ 
b/modules/injection/src/main/java/org/apache/tamaya/inject/internal/InjectionUtils.java
@@ -74,6 +74,9 @@ final class InjectionUtils {
      * @return the list current keys in order how they should be 
processed/looked up.
      */
     public static List<String> evaluateKeys(Member member, ConfigRoot 
areasAnnot, ConfiguredProperty propertyAnnotation) {
+        if(propertyAnnotation==null){
+            return evaluateKeys(member, areasAnnot);
+        }
         List<String> keys = new 
ArrayList<>(Arrays.asList(propertyAnnotation.keys()));
         if (keys.isEmpty()) {
             keys.add(member.getName());
@@ -159,19 +162,41 @@ final class InjectionUtils {
         ConfiguredProperty prop = 
element.getAnnotation(ConfiguredProperty.class);
         DefaultValue defaultAnnot = element.getAnnotation(DefaultValue.class);
         String configValue = null;
+        List<String> keys = null;
         if (prop == null) {
-            List<String> keys = InjectionUtils.evaluateKeys((Member) element, 
areasAnnot);
-            configValue = evaluteConfigValue(keys);
+            keys = InjectionUtils.evaluateKeys((Member) element, areasAnnot);
         } else {
-            List<String> keys = InjectionUtils.evaluateKeys((Member) element, 
areasAnnot, prop);
-            configValue = evaluteConfigValue(keys);
+            keys = InjectionUtils.evaluateKeys((Member) element, areasAnnot, 
prop);
         }
+        configValue = evaluteConfigValue(keys);
         if (configValue == null && defaultAnnot != null) {
             return defaultAnnot.value();
         }
         return configValue;
     }
 
+    /**
+     * Collects all keys to be be accessed as defined by any annotations of 
type
+     * {@link org.apache.tamaya.inject.ConfigRoot}, {@link 
org.apache.tamaya.inject.ConfiguredProperty}.
+     * @param field the (optionally) annotated field instance
+     * @return the regarding key list to be accessed fomr the {@link 
org.apache.tamaya.Configuration}.
+     */
+    public static List<String> getKeys(Field field) {
+        ConfigRoot areasAnnot = 
field.getDeclaringClass().getAnnotation(ConfigRoot.class);
+        return InjectionUtils.evaluateKeys((Member) field, areasAnnot, 
field.getAnnotation(ConfiguredProperty.class));
+    }
+
+    /**
+     * Collects all keys to be be accessed as defined by any annotations of 
type
+     * {@link org.apache.tamaya.inject.ConfigRoot}, {@link 
org.apache.tamaya.inject.ConfiguredProperty}.
+     * @param method the (optionally) annotated method instance
+     * @return the regarding key list to be accessed fomr the {@link 
org.apache.tamaya.Configuration}.
+     */
+    public static List<String> getKeys(Method method) {
+        ConfigRoot areasAnnot = 
method.getDeclaringClass().getAnnotation(ConfigRoot.class);
+        return InjectionUtils.evaluateKeys((Member) method, areasAnnot, 
method.getAnnotation(ConfiguredProperty.class));
+    }
+
     private static String evaluteConfigValue(List<String> keys) {
         String configValue = null;
         for (String key : keys) {
@@ -235,4 +260,6 @@ final class InjectionUtils {
         }
         return value;
     }
+
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/4ddf46f7/modules/injection/src/test/java/annottext/AnnotatedConfigBean.java
----------------------------------------------------------------------
diff --git a/modules/injection/src/test/java/annottext/AnnotatedConfigBean.java 
b/modules/injection/src/test/java/annottext/AnnotatedConfigBean.java
index c1eb39c..94eb570 100644
--- a/modules/injection/src/test/java/annottext/AnnotatedConfigBean.java
+++ b/modules/injection/src/test/java/annottext/AnnotatedConfigBean.java
@@ -20,6 +20,7 @@ package annottext;
 
 import org.apache.tamaya.inject.ConfiguredProperty;
 import org.apache.tamaya.inject.DefaultValue;
+import org.apache.tamaya.inject.DynamicValue;
 import org.apache.tamaya.inject.LoadPolicy;
 import org.apache.tamaya.inject.WithLoadPolicy;
 
@@ -46,6 +47,9 @@ public class AnnotatedConfigBean {
     @ConfiguredProperty(keys = "host.name")
     private String hostName;
 
+    @ConfiguredProperty(keys = "host.name")
+    private DynamicValue<String> dynamicHostname;
+
     public String getAnotherValue(){
         return anotherValue;
     }
@@ -54,4 +58,8 @@ public class AnnotatedConfigBean {
         return hostName;
     }
 
+    public DynamicValue<String> getDynamicValue(){
+        return dynamicHostname;
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/4ddf46f7/modules/injection/src/test/java/annottext/AnnotatedConfigTemplate.java
----------------------------------------------------------------------
diff --git 
a/modules/injection/src/test/java/annottext/AnnotatedConfigTemplate.java 
b/modules/injection/src/test/java/annottext/AnnotatedConfigTemplate.java
index 8aa3f54..94fc188 100644
--- a/modules/injection/src/test/java/annottext/AnnotatedConfigTemplate.java
+++ b/modules/injection/src/test/java/annottext/AnnotatedConfigTemplate.java
@@ -20,6 +20,7 @@ package annottext;
 
 import org.apache.tamaya.inject.ConfiguredProperty;
 import org.apache.tamaya.inject.DefaultValue;
+import org.apache.tamaya.inject.DynamicValue;
 import org.apache.tamaya.inject.LoadPolicy;
 import org.apache.tamaya.inject.WithLoadPolicy;
 
@@ -32,7 +33,7 @@ import org.apache.tamaya.inject.WithLoadPolicy;
 public interface AnnotatedConfigTemplate {
 
     @ConfiguredProperty(keys = {"foo.bar.myprop", 
"mp","common.testdata.myProperty"})
-    @DefaultValue("myValue_${env.stage}")
+    @DefaultValue("ET")
     // @ConfigLoadPolicy(listener = MyListener.class)
     String myParameter();
 
@@ -41,9 +42,12 @@ public interface AnnotatedConfigTemplate {
     String simpleValue();
 
     @ConfiguredProperty
-    String simplestValue();
+    default String simplestValue(){return "HALLO!";}
 
     @ConfiguredProperty(keys = "host.name")
     String hostName();
 
+    @ConfiguredProperty(keys = "host.name")
+    DynamicValue<String> getDynamicValue();
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/4ddf46f7/modules/injection/src/test/java/org/apache/tamaya/inject/TamayaInjectionTest.java
----------------------------------------------------------------------
diff --git 
a/modules/injection/src/test/java/org/apache/tamaya/inject/TamayaInjectionTest.java
 
b/modules/injection/src/test/java/org/apache/tamaya/inject/TamayaInjectionTest.java
index 654e97a..aaed64b 100644
--- 
a/modules/injection/src/test/java/org/apache/tamaya/inject/TamayaInjectionTest.java
+++ 
b/modules/injection/src/test/java/org/apache/tamaya/inject/TamayaInjectionTest.java
@@ -24,6 +24,7 @@ import org.junit.Test;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
 
 /**
  * Created by Anatole on 12.01.2015.
@@ -43,6 +44,25 @@ public class TamayaInjectionTest {
         assertEquals(testInstance.getAnotherValue(), "HALLO!");
         assertEquals(testInstance.myParameter, "ET");
         assertEquals(testInstance.simpleValue, "aSimpleValue");
+        assertNotNull(testInstance.getDynamicValue());
+        assertTrue(testInstance.getDynamicValue().isPresent());
+        assertEquals(testInstance.getDynamicValue().get(), 
"tamaya01.incubator.apache.org");
+        assertEquals(testInstance.getHostName(), 
testInstance.getDynamicValue().get());
+    }
+
+    @Test
+    public void testConfigTemplate(){
+        assertNotNull(ConfigurationInjector.getInstance());
+        AnnotatedConfigTemplate testInstance = 
ConfigurationInjector.getInstance()
+                .createTemplate(AnnotatedConfigTemplate.class);
+        assertEquals(testInstance.hostName(), "tamaya01.incubator.apache.org");
+        assertEquals(testInstance.myParameter(), "ET");
+        assertEquals(testInstance.simpleValue(), "aSimpleValue");
+        assertNotNull(testInstance.getDynamicValue());
+        assertTrue(testInstance.getDynamicValue().isPresent());
+        assertEquals(testInstance.getDynamicValue().get(), 
"tamaya01.incubator.apache.org");
+        assertEquals(testInstance.hostName(), 
testInstance.getDynamicValue().get());
+//        assertEquals(testInstance.simplestValue(), "HALLO!");
     }
 
 }

Reply via email to