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 <johndam...@apache.org> 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 <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> >> > >> > >> >> >>