One note - hardcoding "isAlternative" to true breaks in Weld.  Unless there
is a base bean of same type, the alternative is ignored.  Hence why I only
did isAlternative on the provider type, all others are just regular beans.

John

On Tue, Aug 8, 2017 at 6:55 AM <strub...@apache.org> wrote:

> Author: struberg
> Date: Tue Aug  8 10:55:56 2017
> New Revision: 1804397
>
> URL: http://svn.apache.org/viewvc?rev=1804397&view=rev
> Log:
> GERONIMO-6577 move back to a more dynamic version
>
> The goal of r1800748 to calculate all information upfront could not be
> achieved
> so we move back to the old version
>
> Modified:
>     geronimo/components/config/trunk/impl/debug-suite.xml
>     geronimo/components/config/trunk/impl/pom.xml
>
> geronimo/components/config/trunk/impl/src/main/java/org/apache/geronimo/config/cdi/ConfigExtension.java
>
> geronimo/components/config/trunk/impl/src/main/java/org/apache/geronimo/config/cdi/ConfigInjectionBean.java
>
> geronimo/components/config/trunk/impl/src/test/java/org/apache/geronimo/config/test/internal/ProviderTest.java
>     geronimo/components/config/trunk/pom.xml
>
> Modified: geronimo/components/config/trunk/impl/debug-suite.xml
> URL:
> http://svn.apache.org/viewvc/geronimo/components/config/trunk/impl/debug-suite.xml?rev=1804397&r1=1804396&r2=1804397&view=diff
>
> ==============================================================================
> --- geronimo/components/config/trunk/impl/debug-suite.xml (original)
> +++ geronimo/components/config/trunk/impl/debug-suite.xml Tue Aug  8
> 10:55:56 2017
> @@ -24,7 +24,7 @@
>      <classes>
>          <!-- Issues in the spec -->
>          <!-- CDI-437 -->
> -        <class
> name="org.eclipse.microprofile.config.tck.CdiOptionalInjectionTest">
> +        <class
> name="org.eclipse.microprofile.config.tck.CDIPlainInjectionTest">
>              <methods>
>                  <include name=".*"/>
>              </methods>
>
> Modified: geronimo/components/config/trunk/impl/pom.xml
> URL:
> http://svn.apache.org/viewvc/geronimo/components/config/trunk/impl/pom.xml?rev=1804397&r1=1804396&r2=1804397&view=diff
>
> ==============================================================================
> --- geronimo/components/config/trunk/impl/pom.xml (original)
> +++ geronimo/components/config/trunk/impl/pom.xml Tue Aug  8 10:55:56 2017
> @@ -27,7 +27,6 @@
>      </parent>
>
>      <artifactId>geronimo-config-impl</artifactId>
> -    <name>Geronimo Microprofile Configuration :: Implementation</name>
>
>      <dependencyManagement>
>          <dependencies>
>
> Modified:
> geronimo/components/config/trunk/impl/src/main/java/org/apache/geronimo/config/cdi/ConfigExtension.java
> URL:
> http://svn.apache.org/viewvc/geronimo/components/config/trunk/impl/src/main/java/org/apache/geronimo/config/cdi/ConfigExtension.java?rev=1804397&r1=1804396&r2=1804397&view=diff
>
> ==============================================================================
> ---
> geronimo/components/config/trunk/impl/src/main/java/org/apache/geronimo/config/cdi/ConfigExtension.java
> (original)
> +++
> geronimo/components/config/trunk/impl/src/main/java/org/apache/geronimo/config/cdi/ConfigExtension.java
> Tue Aug  8 10:55:56 2017
> @@ -16,54 +16,38 @@
>   */
>  package org.apache.geronimo.config.cdi;
>
> -import org.apache.geronimo.config.ConfigImpl;
> -import org.eclipse.microprofile.config.Config;
> -import org.eclipse.microprofile.config.inject.ConfigProperty;
> -import org.eclipse.microprofile.config.spi.ConfigProviderResolver;
> +import java.lang.reflect.Type;
> +import java.util.ArrayList;
> +import java.util.HashMap;
> +import java.util.HashSet;
> +import java.util.List;
> +import java.util.Map;
> +import java.util.Optional;
> +import java.util.Set;
> +import java.util.stream.Collectors;
>
> -import javax.enterprise.context.spi.CreationalContext;
>  import javax.enterprise.event.Observes;
>  import javax.enterprise.inject.spi.AfterBeanDiscovery;
>  import javax.enterprise.inject.spi.AfterDeploymentValidation;
> -import javax.enterprise.inject.spi.AnnotatedMember;
> -import javax.enterprise.inject.spi.AnnotatedType;
>  import javax.enterprise.inject.spi.BeanManager;
> -import javax.enterprise.inject.spi.BeforeBeanDiscovery;
>  import javax.enterprise.inject.spi.BeforeShutdown;
> +import javax.enterprise.inject.spi.DeploymentException;
>  import javax.enterprise.inject.spi.Extension;
>  import javax.enterprise.inject.spi.InjectionPoint;
>  import javax.enterprise.inject.spi.ProcessInjectionPoint;
>  import javax.inject.Provider;
> -import java.lang.reflect.ParameterizedType;
> -import java.lang.reflect.Type;
> -import java.util.ArrayList;
> -import java.util.Arrays;
> -import java.util.Collection;
> -import java.util.HashMap;
> -import java.util.HashSet;
> -import java.util.List;
> -import java.util.Map;
> -import java.util.Objects;
> -import java.util.Optional;
> -import java.util.Set;
> -import java.util.function.BiFunction;
> -import java.util.stream.Stream;
>
> -import static java.util.function.Function.identity;
> -import static java.util.stream.Collectors.toMap;
> -import static org.eclipse.microprofile.config.ConfigProvider.getConfig;
> +import org.apache.geronimo.config.DefaultConfigProvider;
> +import org.eclipse.microprofile.config.Config;
> +import org.eclipse.microprofile.config.ConfigProvider;
> +import org.eclipse.microprofile.config.inject.ConfigProperty;
>
>  /**
>   * @author <a href="mailto:strub...@yahoo.de";>Mark Struberg</a>
>   */
>  public class ConfigExtension implements Extension {
> -    private static final Object NULL = new Object();
> -
>      private Config config;
> -    private ConfigProviderResolver resolver;
>
> -    private Set<Injection> injections = new HashSet<>();
> -    private List<Throwable> deploymentProblems = new ArrayList<>();
>      private static final Map<Type, Type> REPLACED_TYPES = new HashMap<>();
>
>      static {
> @@ -74,336 +58,65 @@ public class ConfigExtension implements
>          REPLACED_TYPES.put(boolean.class, Boolean.class);
>      }
>
> -    void init(@Observes final BeforeBeanDiscovery beforeBeanDiscovery,
> final BeanManager bm) {
> -        resolver = ConfigProviderResolver.instance();
> -        config = getConfig();
> -    }
> +    private Set<InjectionPoint> injectionPoints = new HashSet<>();
> +
>
>      public void collectConfigProducer(@Observes ProcessInjectionPoint<?,
> ?> pip) {
> -        final InjectionPoint injectionPoint = pip.getInjectionPoint();
> -        final ConfigProperty configProperty =
> injectionPoint.getAnnotated().getAnnotation(ConfigProperty.class);
> +        ConfigProperty configProperty =
> pip.getInjectionPoint().getAnnotated().getAnnotation(ConfigProperty.class);
>          if (configProperty != null) {
> -            Type replacedType =
> REPLACED_TYPES.getOrDefault(injectionPoint.getType(),
> injectionPoint.getType());
> -            Injection injection = new Injection(replacedType);
> -            final String key = getConfigKey(injectionPoint,
> configProperty);
> -            final boolean defaultUnset =
> isDefaultUnset(configProperty.defaultValue());
> -            if (!injections.add(injection)) {
> -                final Injection ref = injection;
> -                injection = injections.stream().filter(i ->
> i.equals(ref)).findFirst().get();
> -            }
> -            injection.keys.add(key);
> -            injection.defaultValues.add(configProperty.defaultValue());
> -
> -            final ConfigImpl configImpl = unwrapConfig();
> -
> -            // what about lazy runtime lookup, not consistent with tck
> and system prop usage, for now assume optional=optional ;)
> -            boolean hasValue = true;
> -            if (defaultUnset) { // value validation
> -                if (ParameterizedType.class.isInstance(injection.type)) {
> -                    final ParameterizedType pt =
> ParameterizedType.class.cast(injection.type);
> -                    if (pt.getRawType() != Optional.class &&
> !configImpl.getOptionalValue(key, String.class).isPresent()) {
> -                        hasValue = false;
> -                    }
> -                } else if (!configImpl.getOptionalValue(key,
> String.class).isPresent()) {
> -                    hasValue = false;
> -                }
> -                if (!hasValue) {
> -                    deploymentProblems.add(new
> IllegalArgumentException("No configured value for '" + key + "' from " +
> injectionPoint));
> -                }
> -            }
> -
> -            Class<?> instanceType = null;
> -            if (ParameterizedType.class.isInstance(injection.type)) { //
> converters validation
> -                final ParameterizedType pt =
> ParameterizedType.class.cast(injection.type);
> -                if (pt.getRawType() == Provider.class &&
> pt.getActualTypeArguments().length == 1 &&
> Class.class.isInstance(pt.getActualTypeArguments()[0])
> -                        &&
> !configImpl.getConverters().containsKey(Class.class.cast(pt.getActualTypeArguments()[0])))
> {
> -                    instanceType =
> Class.class.cast(pt.getActualTypeArguments()[0]);
> -                } // else if Optional it is fine, else we don't know how
> to process
> -            } else if (Class.class.isInstance(injection.type)) {
> -                instanceType = Class.class.cast(injection.type);
> -            }
> -            if (instanceType != null) { // validate we have a converter +
> we can convert the existing value
> -                if
> (!configImpl.getConverters().containsKey(instanceType)) {
> -                    deploymentProblems.add(new
> IllegalArgumentException("Missing converter for '" + key + "' from " +
> injectionPoint));
> -                } else if (hasValue) {
> -                    try {
> -
> configImpl.getConverters().get(injection.type).convert(configImpl.getValue(key));
> -                    } catch (final RuntimeException re) {
> -                        deploymentProblems.add(re);
> -                    }
> -                }
> -            }
> +            injectionPoints.add(pip.getInjectionPoint());
>          }
>      }
>
>      public void registerConfigProducer(@Observes AfterBeanDiscovery abd,
> BeanManager bm) {
> -        injections.stream()
> -                .flatMap(injection -> {
> -                    final BiFunction<CreationalContext<?>,
> ConfigInjectionBean<?>, String> keyProvider;
> -                    if (injection.keys.size() == 1) {
> -                        final String key =
> injection.keys.iterator().next();
> -                        keyProvider = (ctx, bean) -> key;
> -                    } else {
> -                        keyProvider = (ctx, bean) ->
> getName(findInjectionPoint(bm, ctx, bean));
> -                    }
> -
> -                    if
> (ParameterizedType.class.isInstance(injection.type)) {
> -                        final ParameterizedType paramType =
> ParameterizedType.class.cast(injection.type);
> -                        final Type rawType = paramType.getRawType();
> -
> -                        // todo: do we care of Instance injection? doesnt
> make much sense right?
> -                        if (Provider.class == rawType &&
> paramType.getActualTypeArguments().length == 1) {
> -                            if
> (!Class.class.isInstance(paramType.getActualTypeArguments()[0])) {
> -                                deploymentProblems.add(new
> IllegalArgumentException("@ConfigProperty can only be used with Provider<T>
> where T is a Class"));
> -                                return Stream.empty();
> -                            }
> -                            final Class<?> providerType =
> Class.class.cast(paramType.getActualTypeArguments()[0]);
> -                            return Stream.of(new
> ConfigInjectionBean<Provider<?>>(injection.type, true) {
> -                                @Override
> -                                public Provider<?> create(final
> CreationalContext<Provider<?>> context) {
> -                                    return () ->
> config.getValue(keyProvider.apply(context, this), providerType);
> -                                }
> -                            });
> -                        } else if (Optional.class == rawType &&
> paramType.getActualTypeArguments().length == 1) {
> -                            if
> (!Class.class.isInstance(paramType.getActualTypeArguments()[0])) {
> -                                deploymentProblems.add(new
> IllegalArgumentException("@ConfigProperty can only be used with Optional<T>
> where T is a Class"));
> -                                return null;
> -                            }
> -                            final Class<?> optionalType =
> Class.class.cast(paramType.getActualTypeArguments()[0]);
> -                            return Stream.of(new
> ConfigInjectionBean<Optional<?>>(injection.type) {
> -                                @Override
> -                                public Optional<?> create(final
> CreationalContext<Optional<?>> context) {
> -                                    return
> config.getOptionalValue(keyProvider.apply(context, this), optionalType);
> -                                }
> -                            });
> -                        } else {
> -                            deploymentProblems.add(new
> IllegalArgumentException("Unsupported parameterized type " + paramType));
> -                            return Stream.empty();
> -                        }
> -                    } else if (Class.class.isInstance(injection.type)) {
> -                        final Class clazz =
> Class.class.cast(injection.type);
> -                        final ConfigInjectionBean bean;
> -                        if (injection.defaultValues.isEmpty()) {
> -                            bean = new
> ConfigInjectionBean<Object>(injection.type) {
> -                                @Override
> -                                public Object create(final
> CreationalContext<Object> context) {
> -                                    return
> config.getOptionalValue(keyProvider.apply(context, this), clazz);
> -                                }
> -                            };
> -                        } else if (injection.defaultValues.size() == 1) {
> // common enough to be optimized
> -                            final String defVal =
> injection.defaultValues.iterator().next();
> -                            final Object alternativeVal =
> isDefaultUnset(defVal) ? null : unwrapConfig().convert(defVal, clazz);
> -                            bean = new
> ConfigInjectionBean<Object>(injection.type) {
> -                                @Override
> -                                public Object create(final
> CreationalContext<Object> context) {
> -                                    final Optional optionalValue =
> config.getOptionalValue(keyProvider.apply(context, this), clazz);
> -                                    return
> optionalValue.orElse(alternativeVal);
> -                                }
> -                            };
> -                        } else { // sadly we need to get back to the
> injection point to know which one we need to use
> -                            final Map<String, Object> prepared =
> injection.defaultValues.stream()
> -                                    .collect(toMap(identity(), k ->
> isDefaultUnset(k) ? NULL : unwrapConfig().convert(k, clazz), (a, b) -> b));
> -                            bean = new
> ConfigInjectionBean<Object>(injection.type) {
> -                                @Override
> -                                public Object create(final
> CreationalContext<Object> context) {
> -                                    final InjectionPoint ip =
> findInjectionPoint(bm, context, this);
> -                                    if (ip == null) {
> -                                        throw new
> IllegalStateException("Could not retrieve InjectionPoint");
> -                                    }
> -                                    return
> config.getOptionalValue(ConfigExtension.this.getName(ip), clazz)
> -                                            .orElseGet(() -> {
> -                                                final Object val =
> prepared.get(ip.getAnnotated().getAnnotation(ConfigProperty.class).defaultValue());
> -                                                return val == NULL ? null
> : val;
> -                                            });
> -                                }
> -                            };
> -                        }
> -
> -                        final Collection<ConfigInjectionBean<?>> beans =
> new ArrayList<>();
> -                        beans.add(bean);
> -
> -                        // is adding these beans is that useful? we
> captured them all so only a programmatic lookup would justify it
> -                        // and not sure it would be done this way anyway
> -                        final ParameterizedTypeImpl providerType = new
> ParameterizedTypeImpl(Provider.class, injection.type);
> -                        if (injections.stream().noneMatch(i ->
> i.type.equals(providerType))) {
> -                            beans.add(new
> ConfigInjectionBean<Provider<?>>(providerType, true) {
> -                                @Override
> -                                public Provider<?> create(final
> CreationalContext<Provider<?>> context) {
> -                                    return () -> bean.create(context);
> -                                }
> -                            });
> -                        }
> -
> -                        final ParameterizedTypeImpl optionalType = new
> ParameterizedTypeImpl(Optional.class, injection.type);
> -                        if (injections.stream().noneMatch(i ->
> i.type.equals(optionalType))) {
> -                            beans.add(new
> ConfigInjectionBean<Optional<?>>(optionalType) {
> -                                @Override
> -                                public Optional<?> create(final
> CreationalContext<Optional<?>> context) {
> -                                    return
> Optional.ofNullable(bean.create(context));
> -                                }
> -                            });
> -                        }
> -
> -                        return beans.stream();
> -                    } else {
> -                        deploymentProblems.add(new
> IllegalArgumentException("Unknown type " + injection.type));
> -                        return Stream.empty();
> -                    }
> -                })
> -                .forEach(abd::addBean);
> -    }
> +        Set<Class> types = injectionPoints.stream()
> +                .filter(ip -> ip.getType() instanceof Class)
> +                .map(ip -> (Class)
> REPLACED_TYPES.getOrDefault(ip.getType(), ip.getType()))
> +                .collect(Collectors.toSet());
> +
> +        // Provider and Optional are ParameterizedTypes and not a Class,
> so we need to add them manually
> +        types.add(Provider.class);
> +        types.add(Optional.class);
>
> -    public void validate(@Observes AfterDeploymentValidation add) {
> -        deploymentProblems.forEach(add::addDeploymentProblem);
> -        injections.clear();
> -        deploymentProblems.clear();
> +        types.forEach(type -> abd.addBean(new ConfigInjectionBean(bm,
> type)));
>      }
>
> -    public void shutdown(@Observes BeforeShutdown bsd) {
> -        resolver.releaseConfig(config);
> -    }
> +    public void validate(@Observes AfterDeploymentValidation add) {
> +        List<String> deploymentProblems = new ArrayList<>();
>
> -    private ConfigImpl unwrapConfig() {
> -        return ConfigImpl.class.cast(config);
> -    }
> +        config = ConfigProvider.getConfig();
>
> -    private static String getName(final InjectionPoint ip) {
> -        final ConfigProperty annotation =
> ip.getAnnotated().getAnnotation(ConfigProperty.class);
> -        final String name = annotation.name();
> -        return isDefaultUnset(name) ? getConfigKey(ip, annotation) : name;
> -    }
> +        for (InjectionPoint injectionPoint : injectionPoints) {
> +            Type type = injectionPoint.getType();
>
> -    /**
> -     * Get the property key to use.
> -     * In case the {@link ConfigProperty#name()} is empty we will try to
> determine the key name from the InjectionPoint.
> -     */
> -    private static String getConfigKey(InjectionPoint ip, ConfigProperty
> configProperty) {
> -        String key = configProperty.name();
> -        if (!key.isEmpty()) {
> -            return key;
> -        }
> -        if (ip.getAnnotated() instanceof AnnotatedMember) {
> -            AnnotatedMember member = (AnnotatedMember) ip.getAnnotated();
> -            AnnotatedType declaringType = member.getDeclaringType();
> -            if (declaringType != null) {
> -                String[] parts =
> declaringType.getJavaClass().getCanonicalName().split("\\.");
> -                String cn = parts[parts.length - 1];
> -                parts[parts.length - 1] =
> Character.toLowerCase(cn.charAt(0)) + (cn.length() > 1 ? cn.substring(1) :
> "");
> -                StringBuilder sb = new StringBuilder(parts[0]);
> -                for (int i = 1; i < parts.length; i++) {
> -                    sb.append(".").append(parts[i]);
> +            // replace native types with their Wrapper types
> +            type = REPLACED_TYPES.getOrDefault(type, type);
> +
> +            ConfigProperty configProperty =
> injectionPoint.getAnnotated().getAnnotation(ConfigProperty.class);
> +            if (type instanceof Class) {
> +                // a direct injection of a ConfigProperty
> +                // that means a Converter must exist.
> +                String key =
> ConfigInjectionBean.getConfigKey(injectionPoint, configProperty);
> +                if ((isDefaultUnset(configProperty.defaultValue()))
> +                        && !config.getOptionalValue(key, (Class)
> type).isPresent()) {
> +                    deploymentProblems.add("No Config Value exists for "
> + key);
>                  }
> -
> -                // now add the field name
> -                sb.append(".").append(member.getJavaMember().getName());
> -                return sb.toString();
>              }
>          }
>
> -        throw new IllegalStateException("Could not find default name for
> @ConfigProperty InjectionPoint " + ip);
> -    }
> -
> -    private static boolean isDefaultUnset(String defaultValue) {
> -        return defaultValue == null || defaultValue.length() == 0 ||
> defaultValue.equals(ConfigProperty.UNCONFIGURED_VALUE);
> -    }
> -
> -    private static InjectionPoint findInjectionPoint(final BeanManager
> bm, final CreationalContext<?> ctx,
> -                                                     ConfigInjectionBean
> bean) {
> -        return
> InjectionPoint.class.cast(bm.getInjectableReference(bean.getSimpleInjectionPoint(),
> ctx));
> -    }
> -
> -    private static final class Injection {
> -        private final Type type;
> -        private final Collection<String> keys = new ArrayList<>();
> -        private final Collection<String> defaultValues = new
> ArrayList<>();
> -
> -        private Injection(final Type type) {
> -            this.type = type;
> -        }
> -
> -        @Override
> -        public boolean equals(final Object o) {
> -            if (this == o) {
> -                return true;
> -            }
> -            if (o == null || Injection.class != o.getClass()) {
> -                return false;
> -            }
> -            final Injection injection = Injection.class.cast(o);
> -            return Objects.equals(type, injection.type);
> +        if (!deploymentProblems.isEmpty()) {
> +            add.addDeploymentProblem(new DeploymentException("Error while
> validating Configuration\n"
> +                                                             +
> String.join("\n", deploymentProblems)));
>          }
>
> -        @Override
> -        public int hashCode() {
> -            return type.hashCode();
> -        }
>      }
>
> -    private class ParameterizedTypeImpl implements ParameterizedType {
> -        private final Type rawType;
> -        private final Type[] types;
> -
> -        private ParameterizedTypeImpl(final Type raw, final Type...
> types) {
> -            this.rawType = raw;
> -            this.types = types;
> -        }
> -
> -        @Override
> -        public Type[] getActualTypeArguments() {
> -            return types.clone();
> -        }
> -
> -        @Override
> -        public Type getOwnerType() {
> -            return null;
> -        }
> -
> -        @Override
> -        public Type getRawType() {
> -            return rawType;
> -        }
> -
> -        @Override
> -        public int hashCode() {
> -            return Arrays.hashCode(types) ^ rawType.hashCode();
> -        }
> -
> -        @Override
> -        public boolean equals(final Object obj) {
> -            if (this == obj) {
> -                return true;
> -            }
> -            if (ParameterizedType.class.isInstance(obj)) {
> -                final ParameterizedType that =
> ParameterizedType.class.cast(obj);
> -                final Type thatRawType = that.getRawType();
> -                return (rawType == null ? thatRawType == null :
> rawType.equals(thatRawType))
> -                        && Arrays.equals(types,
> that.getActualTypeArguments());
> -            }
> -            return false;
> -        }
> +    public void shutdown(@Observes BeforeShutdown bsd) {
> +        DefaultConfigProvider.instance().releaseConfig(config);
> +    }
>
> -        @Override
> -        public String toString() {
> -            final StringBuilder buffer = new StringBuilder();
> -            buffer.append(Class.class.cast(rawType).getName());
> -            final Type[] actualTypes = getActualTypeArguments();
> -            if (actualTypes.length > 0) {
> -                buffer.append("<");
> -                final int length = actualTypes.length;
> -                for (int i = 0; i < length; i++) {
> -                    if (actualTypes[i] instanceof Class) {
> -                        buffer.append(((Class<?>)
> actualTypes[i]).getSimpleName());
> -                    } else {
> -                        buffer.append(actualTypes[i].toString());
> -                    }
> -                    if (i != actualTypes.length - 1) {
> -                        buffer.append(",");
> -                    }
> -                }
>
> -                buffer.append(">");
> -            }
> -            return buffer.toString();
> -        }
> +    static boolean isDefaultUnset(String defaultValue) {
> +        return defaultValue.equals(ConfigProperty.UNCONFIGURED_VALUE);
>      }
>  }
>
> Modified:
> geronimo/components/config/trunk/impl/src/main/java/org/apache/geronimo/config/cdi/ConfigInjectionBean.java
> URL:
> http://svn.apache.org/viewvc/geronimo/components/config/trunk/impl/src/main/java/org/apache/geronimo/config/cdi/ConfigInjectionBean.java?rev=1804397&r1=1804396&r2=1804397&view=diff
>
> ==============================================================================
> ---
> geronimo/components/config/trunk/impl/src/main/java/org/apache/geronimo/config/cdi/ConfigInjectionBean.java
> (original)
> +++
> geronimo/components/config/trunk/impl/src/main/java/org/apache/geronimo/config/cdi/ConfigInjectionBean.java
> Tue Aug  8 10:55:56 2017
> @@ -16,49 +16,59 @@
>   */
>  package org.apache.geronimo.config.cdi;
>
> -import org.eclipse.microprofile.config.inject.ConfigProperty;
> +import java.io.IOException;
> +import java.io.Serializable;
> +import java.lang.annotation.Annotation;
> +import java.lang.reflect.ParameterizedType;
> +import java.lang.reflect.Type;
> +import java.util.Collections;
> +import java.util.HashSet;
> +import java.util.Optional;
> +import java.util.Set;
>
>  import javax.enterprise.context.Dependent;
>  import javax.enterprise.context.spi.CreationalContext;
> -import javax.enterprise.inject.Default;
>  import javax.enterprise.inject.spi.Annotated;
> +import javax.enterprise.inject.spi.AnnotatedMember;
> +import javax.enterprise.inject.spi.AnnotatedType;
>  import javax.enterprise.inject.spi.Bean;
> +import javax.enterprise.inject.spi.BeanManager;
>  import javax.enterprise.inject.spi.InjectionPoint;
>  import javax.enterprise.inject.spi.PassivationCapable;
>  import javax.enterprise.util.AnnotationLiteral;
> -import java.lang.annotation.Annotation;
> -import java.lang.reflect.Member;
> -import java.lang.reflect.ParameterizedType;
> -import java.lang.reflect.Type;
> -import java.util.Collections;
> -import java.util.HashSet;
> -import java.util.Set;
> +import javax.inject.Provider;
> +
> +import org.apache.geronimo.config.ConfigImpl;
> +import org.eclipse.microprofile.config.Config;
> +import org.eclipse.microprofile.config.ConfigProvider;
> +import org.eclipse.microprofile.config.inject.ConfigProperty;
> +import org.eclipse.microprofile.config.spi.ConfigProviderResolver;
>
>  /**
>   * @author <a href="mailto:strub...@yahoo.de";>Mark Struberg</a>
>   */
> -public abstract class ConfigInjectionBean<T> implements Bean<T>,
> PassivationCapable {
> +public class ConfigInjectionBean<T> implements Bean<T>,
> PassivationCapable {
>
>      private final static Set<Annotation> QUALIFIERS = new HashSet<>();
>      static {
>          QUALIFIERS.add(new ConfigPropertyLiteral());
>      }
>
> +    private final BeanManager bm;
>      private final Class rawType;
>      private final Set<Type> types;
> -    private final String id;
> -    private final boolean alternative;
> -
> -    ConfigInjectionBean(Type type) {
> -        this(type,false);
> -    }
>
> -    ConfigInjectionBean(Type type, boolean alternative) {
> -        this.types = new HashSet<>();
> -        this.types.add(type);
> -        this.rawType = getRawType(type);
> -        this.id = "ConfigInjectionBean_" + type.toString();
> -        this.alternative = alternative;
> +    /**
> +     * only access via {@link #getConfig(}
> +     */
> +    private Config _config;
> +
> +    public ConfigInjectionBean(BeanManager bm, Type type) {
> +        this.bm = bm;
> +
> +        types = new HashSet<>();
> +        types.add(type);
> +        rawType = getRawType(type);
>      }
>
>      private Class getRawType(Type type) {
> @@ -76,7 +86,7 @@ public abstract class ConfigInjectionBea
>
>      @Override
>      public Set<InjectionPoint> getInjectionPoints() {
> -        return Collections.emptySet();
> +        return Collections.EMPTY_SET;
>      }
>
>      @Override
> @@ -90,8 +100,90 @@ public abstract class ConfigInjectionBea
>      }
>
>      @Override
> +    public T create(CreationalContext<T> context) {
> +        Set<Bean<?>> beans = bm.getBeans(InjectionPoint.class);
> +        Bean<?> bean = bm.resolve(beans);
> +        InjectionPoint ip = (InjectionPoint) bm.getReference(bean,
> InjectionPoint.class,  context);
> +        if (ip == null) {
> +            throw new IllegalStateException("Could not retrieve
> InjectionPoint");
> +        }
> +        Annotated annotated = ip.getAnnotated();
> +        ConfigProperty configProperty =
> annotated.getAnnotation(ConfigProperty.class);
> +        String key = getConfigKey(ip, configProperty);
> +        String defaultValue = configProperty.defaultValue();
> +
> +        if (annotated.getBaseType() instanceof ParameterizedType) {
> +            ParameterizedType paramType = (ParameterizedType)
> annotated.getBaseType();
> +            Type rawType = paramType.getRawType();
> +
> +            // handle Provider<T>
> +            if (rawType instanceof Class && ((Class)
> rawType).isAssignableFrom(Provider.class) &&
> paramType.getActualTypeArguments().length == 1) {
> +                Class clazz = (Class)
> paramType.getActualTypeArguments()[0]; //X TODO check type again, etc
> +                return (T) new ConfigValueProvider(getConfig(), key,
> clazz);
> +            }
> +
> +            // handle Optional<T>
> +            if (rawType instanceof Class && ((Class)
> rawType).isAssignableFrom(Optional.class) &&
> paramType.getActualTypeArguments().length == 1) {
> +                Class clazz = (Class)
> paramType.getActualTypeArguments()[0]; //X TODO check type again, etc
> +                return (T) getConfig().getOptionalValue(key, clazz);
> +            }
> +        }
> +        else {
> +            Class clazz = (Class) annotated.getBaseType();
> +            if (ConfigExtension.isDefaultUnset(defaultValue)) {
> +                return (T) getConfig().getValue(key, clazz);
> +            }
> +            else {
> +                Config config = getConfig();
> +                return (T) config.getOptionalValue(key, clazz)
> +                        .orElse(((ConfigImpl)
> config).convert(defaultValue, clazz));
> +            }
> +        }
> +
> +        throw new IllegalStateException("unhandled ConfigProperty");
> +    }
> +
> +
> +    /**
> +     * Get the property key to use.
> +     * In case the {@link ConfigProperty#name()} is empty we will try to
> determine the key name from the InjectionPoint.
> +     */
> +    public static String getConfigKey(InjectionPoint ip, ConfigProperty
> configProperty) {
> +        String key = configProperty.name();
> +        if (key.length() > 0) {
> +            return key;
> +        }
> +        if (ip.getAnnotated() instanceof AnnotatedMember) {
> +            AnnotatedMember member = (AnnotatedMember) ip.getAnnotated();
> +            AnnotatedType declaringType = member.getDeclaringType();
> +            if (declaringType != null) {
> +                String[] parts =
> declaringType.getJavaClass().getCanonicalName().split("\\.");
> +                String cn = parts[parts.length-1];
> +                parts[parts.length-1] =
> Character.toLowerCase(cn.charAt(0)) + (cn.length() > 1 ? cn.substring(1) :
> "");
> +                StringBuilder sb = new StringBuilder(parts[0]);
> +                for (int i = 1; i < parts.length; i++) {
> +                    sb.append(".").append(parts[i]);
> +                }
> +
> +                // now add the field name
> +                sb.append(".").append(member.getJavaMember().getName());
> +                return sb.toString();
> +            }
> +        }
> +
> +        throw new IllegalStateException("Could not find default name for
> @ConfigProperty InjectionPoint " + ip);
> +    }
> +
> +    public Config getConfig() {
> +        if (_config == null) {
> +            _config = ConfigProvider.getConfig();
> +        }
> +        return _config;
> +    }
> +
> +    @Override
>      public void destroy(T instance, CreationalContext<T> context) {
> -        // no-op
> +
>      }
>
>      @Override
> @@ -116,21 +208,17 @@ public abstract class ConfigInjectionBea
>
>      @Override
>      public Set<Class<? extends Annotation>> getStereotypes() {
> -        return Collections.emptySet();
> +        return Collections.EMPTY_SET;
>      }
>
>      @Override
>      public boolean isAlternative() {
> -        return alternative;
> +        return true;
>      }
>
>      @Override
>      public String getId() {
> -        return id;
> -    }
> -
> -    InjectionPoint getSimpleInjectionPoint() {
> -        return simpleInjectionPoint;
> +        return "ConfigInjectionBean_" + rawType.getName();
>      }
>
>      private static class ConfigPropertyLiteral extends
> AnnotationLiteral<ConfigProperty> implements ConfigProperty {
> @@ -145,41 +233,31 @@ public abstract class ConfigInjectionBea
>          }
>      }
>
> -    private final InjectionPoint simpleInjectionPoint = new
> InjectionPoint() {
> -
> -        @Override
> -        public boolean isTransient() {
> -            return false;
> -        }
> -
> -        @Override
> -        public boolean isDelegate() {
> -            return false;
> -        }
> -
> -        @Override
> -        public Type getType() {
> -            return InjectionPoint.class;
> -        }
> -
> -        @Override
> -        public Set<Annotation> getQualifiers() {
> -            return Collections.singleton(new AnnotationLiteral<Default>()
> {});
> -        }
> -
> -        @Override
> -        public Member getMember() {
> -            return null;
> +    /**
> +     * A special Provider&lt;T&gt;
> +     * This concrete class is needed because we need the injected
> Provider for the ConfigProperty
> +     * to be Serializable. A Lambda would not work in this case
> +     */
> +    public static class ConfigValueProvider<T> implements Provider<T>,
> Serializable {
> +        private transient Config config;
> +        private final String key;
> +        private final Class<T> type;
> +
> +        ConfigValueProvider(Config config, String key, Class<T> type) {
> +            this.config = config;
> +            this.key = key;
> +            this.type = type;
>          }
>
>          @Override
> -        public Bean<?> getBean() {
> -            return ConfigInjectionBean.this;
> +        public T get() {
> +            return (T) config.getValue(key, type);
> +        }
> +
> +        private void readObject(java.io.ObjectInputStream in) throws
> IOException, ClassNotFoundException {
> +            in.defaultReadObject();
> +            config = ConfigProviderResolver.instance().getConfig();
>          }
>
> -        @Override
> -        public Annotated getAnnotated() {
> -            return null;
> -        }
> -    };
> +    }
>  }
>
> Modified:
> geronimo/components/config/trunk/impl/src/test/java/org/apache/geronimo/config/test/internal/ProviderTest.java
> URL:
> http://svn.apache.org/viewvc/geronimo/components/config/trunk/impl/src/test/java/org/apache/geronimo/config/test/internal/ProviderTest.java?rev=1804397&r1=1804396&r2=1804397&view=diff
>
> ==============================================================================
> ---
> geronimo/components/config/trunk/impl/src/test/java/org/apache/geronimo/config/test/internal/ProviderTest.java
> (original)
> +++
> geronimo/components/config/trunk/impl/src/test/java/org/apache/geronimo/config/test/internal/ProviderTest.java
> Tue Aug  8 10:55:56 2017
> @@ -33,9 +33,12 @@ import org.testng.annotations.Test;
>
>  public class ProviderTest extends Arquillian {
>      private static final String SOME_KEY =
> "org.apache.geronimo.config.test.internal.somekey";
> +    private static final String ANOTHER_KEY =
> "org.apache.geronimo.config.test.internal.anotherkey";
>
>      @Deployment
>      public static WebArchive deploy() {
> +        System.setProperty(SOME_KEY, "someval");
> +        System.setProperty(ANOTHER_KEY, "someval");
>          JavaArchive testJar = ShrinkWrap
>                  .create(JavaArchive.class, "configProviderTest.jar")
>                  .addClasses(ProviderTest.class, SomeBean.class)
> @@ -70,8 +73,16 @@ public class ProviderTest extends Arquil
>          @ConfigProperty(name=SOME_KEY)
>          private Provider<String> myconfig;
>
> +        @Inject
> +        @ConfigProperty(name=ANOTHER_KEY)
> +        private Provider<String> anotherconfig;
> +
>          public String getMyconfig() {
>              return myconfig.get();
>          }
> +
> +        public Provider<String> getAnotherconfig() {
> +            return anotherconfig;
> +        }
>      }
>  }
>
> Modified: geronimo/components/config/trunk/pom.xml
> URL:
> http://svn.apache.org/viewvc/geronimo/components/config/trunk/pom.xml?rev=1804397&r1=1804396&r2=1804397&view=diff
>
> ==============================================================================
> --- geronimo/components/config/trunk/pom.xml (original)
> +++ geronimo/components/config/trunk/pom.xml Tue Aug  8 10:55:56 2017
> @@ -27,7 +27,7 @@
>      </parent>
>
>      <groupId>org.apache.geronimo.config</groupId>
> -    <artifactId>config-parent</artifactId>
> +    <artifactId>geronimo-config</artifactId>
>      <version>1.1-SNAPSHOT</version>
>      <packaging>pom</packaging>
>      <name>Geronimo Microprofile Configuration</name>
> @@ -50,7 +50,7 @@
>      <properties>
>          <maven.compiler.source>1.8</maven.compiler.source>
>          <maven.compiler.target>1.8</maven.compiler.target>
> -
> <microprofile-config.version>1.1-SNAPSHOT</microprofile-config.version>
> +        <microprofile-config.version>1.0</microprofile-config.version>
>          <owb.version>1.7.3</owb.version>
>          <owb2.version>2.0.1-SNAPSHOT</owb2.version>
>          <arquillian.version>1.1.13.Final</arquillian.version>
>
>
>

Reply via email to