Ok, I got tests passing on all three. It actually looks like its simpler (and more correct) to not use a custom provider. The provider approach wasn't supporting default values. I've committed changes, please take a look and hopefully we can plan to reroll 1.0.
John On Tue, Aug 8, 2017 at 10:02 PM John D. Ament <[email protected]> wrote: > Ok, I've readded some of the Weld3 support, 3 tests are failing. > > Some interesting notes: > > - If I remove Provider support, it generally works. However, I suddenly > get duplicate beans of type Provider, which is confusing (but probably > because of the alternative flag). > - I can get everything to pass in Weld, and 1 test failure in in OWB with > the following: > > - Set alternative = false > - Remove Provider from the types > - Remove the filter on types to check if class. > - Change getId to use all of the types (makes a better toString) > > > If we can figure out the alternative issue with OWB, we'll be good to go > again. > > John > > On Tue, Aug 8, 2017 at 8:44 AM John D. Ament <[email protected]> > wrote: > >> 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 <[email protected]> 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 <[email protected]>: >>> > >>> > 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 <[email protected]> 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:[email protected]">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:[email protected]">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> >>> > >>> > >>> >>> >>>
