I can get to some of it. We have a couple of issues now though:
https://issues.jboss.org/browse/WELD-2411 https://issues.jboss.org/browse/CDI-712 Martin doesn't feel the spec allows you to override Provider impl's. Please feel free to weigh in :-) John On Tue, Aug 8, 2017 at 7:33 AM Mark Struberg <strub...@yahoo.de> wrote: > Oh I see what you mean. > Do you mind to re-apply your fix or should I? > > Btw, I also tested with the -PWeld3 but I was not able to resolve > arquillian-weld-embedded:jar:2.0.0-SNAPSHOT > We might need to add a <repository> for it in the Weld3 profile. > > I also would love to add a Weld profile. I thought we have this already > but seems we missed it? > > txs and LieGrue, > strub > > > Am 08.08.2017 um 12:58 schrieb John D. Ament <johndam...@apache.org>: > > > > 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<T> > > + * 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> > > > > > > >