Repository: incubator-tamaya-extensions Updated Branches: refs/heads/master 7483ab3d0 -> fe5eac609
TAMAYA-260 Aligned functionality with MP, added support for Provider,Instance and Optional method injection. Project: http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/commit/fe5eac60 Tree: http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/tree/fe5eac60 Diff: http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/diff/fe5eac60 Branch: refs/heads/master Commit: fe5eac609a95477073fc86a908760b8d71775809 Parents: 7483ab3 Author: Anatole Tresch <[email protected]> Authored: Mon Oct 16 00:26:32 2017 +0200 Committer: Anatole Tresch <[email protected]> Committed: Mon Oct 16 00:26:32 2017 +0200 ---------------------------------------------------------------------- modules/injection/cdi/pom.xml | 94 +++--- .../tamaya/cdi/ConfigurationExtension.java | 290 ------------------- .../tamaya/cdi/ConfigurationProducer.java | 133 +++++---- .../tamaya/cdi/TamayaCDIInjectionExtension.java | 66 ++--- ...onfigurationProducerFailedInjectionTest.java | 33 --- .../tamaya/cdi/ConfigurationProducerTest.java | 123 +++++++- .../org/apache/tamaya/cdi/ConfiguredTest.java | 29 +- .../apache/tamaya/cdi/NotFoundNoDefault.java | 2 +- .../org/apache/tamaya/inject/api/Config.java | 5 +- .../tamaya/inject/internal/InjectionHelper.java | 5 +- 10 files changed, 281 insertions(+), 499 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/fe5eac60/modules/injection/cdi/pom.xml ---------------------------------------------------------------------- diff --git a/modules/injection/cdi/pom.xml b/modules/injection/cdi/pom.xml index 4f05d7d..c7ecc15 100644 --- a/modules/injection/cdi/pom.xml +++ b/modules/injection/cdi/pom.xml @@ -31,24 +31,41 @@ under the License. <packaging>jar</packaging> <properties> - <owb.version>1.6.2</owb.version> - <weld.version>2.2.7.Final</weld.version> + <deltaspike.version>1.1.0</deltaspike.version> + <openejb.version>4.7.1</openejb.version> + <weld.version>3.0.1.Final</weld.version> <geronimo-jcdi-1.1-spec.version>1.0</geronimo-jcdi-1.1-spec.version> <geronimo-interceptor-1.2-spec.version>1.0</geronimo-interceptor-1.2-spec.version> <geronimo-atinject-1.0-spec.version>1.0</geronimo-atinject-1.0-spec.version> - <bval.version>0.5</bval.version> - <ds.version>1.1.0</ds.version> + <arquillian.version>1.1.13.Final</arquillian.version> + <arquillian-weld-embedded.version>2.0.0.Beta5</arquillian-weld-embedded.version> + <version.shrinkwrap.resolvers>2.2.6</version.shrinkwrap.resolvers> + <cdi-api.version>2.0</cdi-api.version> <javaee-api.version>6.0-6</javaee-api.version> - <openejb.version>4.7.1</openejb.version> <tomee.version>1.7.1</tomee.version> </properties> + <dependencyManagement> + <dependencies> + <dependency> + <groupId>org.jboss.arquillian</groupId> + <artifactId>arquillian-bom</artifactId> + <version>${arquillian.version}</version> + <type>pom</type> + <scope>import</scope> + </dependency> + <dependency> + <groupId>javax.enterprise</groupId> + <artifactId>cdi-api</artifactId> + <version>${cdi-api.version}</version> + </dependency> + </dependencies> + </dependencyManagement> + <dependencies> <dependency> <groupId>javax.enterprise</groupId> <artifactId>cdi-api</artifactId> - <version>1.2</version> - <scope>provided</scope> </dependency> <dependency> <groupId>org.apache.tamaya.ext</groupId> @@ -89,66 +106,33 @@ under the License. <version>${project.version}</version> </dependency> <dependency> - <groupId>org.apache.openejb</groupId> - <artifactId>javaee-api</artifactId> - <version>${javaee-api.version}</version> - <scope>provided</scope> - </dependency> - <dependency> - <groupId>org.tomitribe</groupId> - <artifactId>tomitribe-util</artifactId> - <version>1.1.0</version> - <scope>provided</scope> - </dependency> - <dependency> - <groupId>org.apache.openejb</groupId> - <artifactId>openejb-core</artifactId> - <version>${openejb.version}</version> - <scope>provided</scope> + <groupId>org.jboss.arquillian.junit</groupId> + <artifactId>arquillian-junit-container</artifactId> + <version>${arquillian.version}</version> + <scope>test</scope> </dependency> <dependency> - <groupId>org.apache.geronimo.specs</groupId> - <artifactId>geronimo-jcdi_1.1_spec</artifactId> - <version>${geronimo-jcdi-1.1-spec.version}</version> - <scope>provided</scope> + <groupId>org.jboss.arquillian.container</groupId> + <artifactId>arquillian-weld-embedded</artifactId> + <version>${arquillian-weld-embedded.version}</version> + <scope>test</scope> </dependency> <dependency> - <groupId>org.apache.deltaspike.modules</groupId> - <artifactId>deltaspike-test-control-module-api</artifactId> - <version>${ds.version}</version> + <groupId>org.jboss.weld.se</groupId> + <artifactId>weld-se-shaded</artifactId> + <version>${weld.version}</version> <scope>test</scope> </dependency> <dependency> - <groupId>org.apache.deltaspike.modules</groupId> - <artifactId>deltaspike-test-control-module-impl</artifactId> - <version>${ds.version}</version> + <groupId>org.jboss.shrinkwrap.resolver</groupId> + <artifactId>shrinkwrap-resolver-depchain</artifactId> + <version>${version.shrinkwrap.resolvers}</version> <scope>test</scope> + <type>pom</type> </dependency> <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-core</artifactId> </dependency> </dependencies> - <profiles> - <profile> - <id>Weld</id> - <activation> - <activeByDefault>true</activeByDefault> - </activation> - <dependencies> - <dependency> - <groupId>org.jboss.weld.se</groupId> - <artifactId>weld-se</artifactId> - <version>${weld.version}</version> - <scope>test</scope> - </dependency> - <dependency> - <groupId>org.apache.deltaspike.cdictrl</groupId> - <artifactId>deltaspike-cdictrl-weld</artifactId> - <version>${ds.version}</version> - <scope>test</scope> - </dependency> - </dependencies> - </profile> - </profiles> </project> http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/fe5eac60/modules/injection/cdi/src/main/java/org/apache/tamaya/cdi/ConfigurationExtension.java ---------------------------------------------------------------------- diff --git a/modules/injection/cdi/src/main/java/org/apache/tamaya/cdi/ConfigurationExtension.java b/modules/injection/cdi/src/main/java/org/apache/tamaya/cdi/ConfigurationExtension.java deleted file mode 100644 index b715b78..0000000 --- a/modules/injection/cdi/src/main/java/org/apache/tamaya/cdi/ConfigurationExtension.java +++ /dev/null @@ -1,290 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.tamaya.cdi; - -import org.apache.tamaya.ConfigException; -import org.apache.tamaya.ConfigOperator; -import org.apache.tamaya.Configuration; -import org.apache.tamaya.ConfigurationProvider; -import org.apache.tamaya.inject.api.Config; -import org.apache.tamaya.inject.api.ConfigDefaultSections; -import org.apache.tamaya.inject.api.WithConfigOperator; -import org.apache.tamaya.inject.api.WithPropertyConverter; -import org.apache.tamaya.spi.PropertyConverter; - -import javax.enterprise.context.spi.CreationalContext; -import javax.enterprise.event.Observes; -import javax.enterprise.inject.spi.AfterBeanDiscovery; -import javax.enterprise.inject.spi.Bean; -import javax.enterprise.inject.spi.BeanManager; -import javax.enterprise.inject.spi.Extension; -import javax.enterprise.inject.spi.InjectionPoint; -import javax.enterprise.inject.spi.ProcessBean; -import javax.enterprise.inject.spi.ProcessProducerMethod; -import java.lang.annotation.Annotation; -import java.lang.reflect.Type; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashSet; -import java.util.List; -import java.util.ListIterator; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.logging.Logger; - - -/** - * CDI Extension module that adds injection mechanism for configuration. - * - * @see org.apache.tamaya.inject.api.Config - * @see org.apache.tamaya.inject.api.ConfigDefaultSections - * @see ConfigException - */ -public class ConfigurationExtension implements Extension { - - private static final Logger LOG = Logger.getLogger(ConfigurationExtension.class.getName()); - - static final Map<Class, ConfigOperator> CUSTOM_OPERATORS = new ConcurrentHashMap<>(); - static final Map<Class, PropertyConverter> CUSTOM_CONVERTERS = new ConcurrentHashMap<>(); - - private final Set<Type> types = new HashSet<>(); - private Bean<?> convBean; - - /** - * Constructor for loading logging its load. - */ - public ConfigurationExtension(){ - LOG.finest("Loading Tamaya CDI Support..."); - } - - /** - * Method that checks the configuration injection points during deployment for available configuration. - * @param pb the bean to process. - * @param beanManager the bean manager to notify about new injections. - */ - public void retrieveTypes(@Observes final ProcessBean<?> pb, BeanManager beanManager) { - - final Set<InjectionPoint> ips = pb.getBean().getInjectionPoints(); - CDIConfiguredType configuredType = new CDIConfiguredType(pb.getBean().getBeanClass()); - - boolean configured = false; - boolean logged = false; - for (InjectionPoint injectionPoint : ips) { - if (injectionPoint.getAnnotated().isAnnotationPresent(Config.class)) { - final Config annotation = injectionPoint.getAnnotated().getAnnotation(Config.class); - final ConfigDefaultSections typeAnnot = injectionPoint.getAnnotated().getAnnotation(ConfigDefaultSections.class); - final List<String> keys = evaluateKeys(injectionPoint.getMember().getName(), - annotation!=null?annotation.value():null, - typeAnnot!=null?typeAnnot.value():null); - - final WithConfigOperator withOperatorAnnot = injectionPoint.getAnnotated().getAnnotation(WithConfigOperator.class); - if(withOperatorAnnot!=null){ - tryLoadOpererator(withOperatorAnnot.value()); - } - final WithPropertyConverter withConverterAnnot = injectionPoint.getAnnotated().getAnnotation(WithPropertyConverter.class); - if(withConverterAnnot!=null){ - tryLoadConverter(withConverterAnnot.value()); - } - - // We don't want to wait until the injection really fails at runtime. - // If there is a non resolvable configuration, we want to know at startup. - Configuration config = ConfigurationProvider.getConfiguration(); - String value = null; - for(String key:keys) { - value = config.get(key); - if(value!=null){ - break; - } - } - if(value==null && !annotation.defaultValue().isEmpty()){ - value = annotation.defaultValue(); - } - if(value==null){ - throw new ConfigException(String.format( - "Cannot resolve any of the possible configuration keys: %s. Please provide one of the given keys " + - "with a value in your configuration sources.", - keys.toString())); - } - types.add(injectionPoint.getType()); - if(annotation!=null){ - configured = true; - if(!logged) { - LOG.finest("Enabling Tamaya CDI Configuration on bean: " + configuredType.getName()); - } - configuredType.addConfiguredMember(injectionPoint, keys); - } - } - } - if(configured) { - beanManager.fireEvent(configuredType); - } - } - - - public void captureConvertBean(@Observes final ProcessProducerMethod<?, ?> ppm) { - if (ppm.getAnnotated().isAnnotationPresent(Config.class)) { - convBean = ppm.getBean(); - } - - } - - public void addConverter(@Observes final AfterBeanDiscovery abd, final BeanManager bm) { - if(!types.isEmpty()) { - abd.addBean(new ConverterBean(convBean, types)); - } - } - - private void tryLoadOpererator(Class<? extends ConfigOperator> operatorClass) { - Objects.requireNonNull(operatorClass); - if(ConfigOperator.class == operatorClass){ - return; - } - try{ - if(!CUSTOM_OPERATORS.containsKey(operatorClass)) { - CUSTOM_OPERATORS.put(operatorClass, operatorClass.newInstance()); - } - } catch(Exception e){ - throw new ConfigException("Custom ConfigOperator could not be loaded: " + operatorClass.getName(), e); - } - } - - private void tryLoadConverter(Class<? extends PropertyConverter> converterClass) { - Objects.requireNonNull(converterClass); - if(PropertyConverter.class == converterClass){ - return; - } - try{ - if(!CUSTOM_CONVERTERS.containsKey(converterClass)) { - CUSTOM_CONVERTERS.put(converterClass, converterClass.newInstance()); - } - } catch(Exception e){ - throw new ConfigException("Custom PropertyConverter could not be loaded: " + converterClass.getName(), e); - } - } - - /** - * Evaluates the effective keys to be used. if no {@code keys} are defined, {@code memberName} is used. - * The effective keys are then combined with the sections given (if any) and only, if the given keys are not - * absolute keys (surrounded by brackets). - * @param memberName the default member name, not null. - * @param keys the keys, may be empty, or null. - * @param sections the default sections, may be empty. May also be null. - * @return the list of keys to be finally used for configuration resolution in order of - * precedence. The first keys in the list that could be successfully resolved define the final - * configuration value. - */ - public static List<String> evaluateKeys(String memberName, String[] keys, String[] sections) { - List<String> effKeys = new ArrayList<>(); - if(keys!=null){ - effKeys.addAll(Arrays.asList(keys)); - } - if (effKeys.isEmpty()) { - effKeys.add(memberName); - } - ListIterator<String> iterator = effKeys.listIterator(); - while (iterator.hasNext()) { - String next = iterator.next(); - if (next.startsWith("[") && next.endsWith("]")) { - // absolute key, strip away brackets, take key as is - iterator.set(next.substring(1, next.length() - 1)); - } else { - if (sections != null && sections.length>0) { - // Remove original entry, since it will be replaced with prefixed entries - iterator.remove(); - // Add prefixed entries, including absolute (root) entry for "" area keys. - for (String area : sections) { - iterator.add(area.isEmpty() ? next : area + '.' + next); - } - } - } - } - return effKeys; - } - - - /** - * Internally used conversion bean. - */ - private static class ConverterBean implements Bean<Object> { - - private final Bean<Object> delegate; - private final Set<Type> types; - - public ConverterBean(final Bean convBean, final Set<Type> types) { - this.types = types; - this.delegate = convBean; - } - - @Override - public Set<Type> getTypes() { - return types; - } - - @Override - public Class<?> getBeanClass() { - return delegate.getBeanClass(); - } - - @Override - public Set<InjectionPoint> getInjectionPoints() { - return delegate.getInjectionPoints(); - } - - @Override - public String getName() { - return delegate.getName(); - } - - @Override - public Set<Annotation> getQualifiers() { - return delegate.getQualifiers(); - } - - @Override - public Class<? extends Annotation> getScope() { - return delegate.getScope(); - } - - @Override - public Set<Class<? extends Annotation>> getStereotypes() { - return delegate.getStereotypes(); - } - - @Override - public boolean isAlternative() { - return delegate.isAlternative(); - } - - @Override - public boolean isNullable() { - return delegate.isNullable(); - } - - @Override - public Object create(CreationalContext<Object> creationalContext) { - return delegate.create(creationalContext); - } - - @Override - public void destroy(Object instance, CreationalContext<Object> creationalContext) { - delegate.destroy(instance, creationalContext); - } - } - -} http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/fe5eac60/modules/injection/cdi/src/main/java/org/apache/tamaya/cdi/ConfigurationProducer.java ---------------------------------------------------------------------- diff --git a/modules/injection/cdi/src/main/java/org/apache/tamaya/cdi/ConfigurationProducer.java b/modules/injection/cdi/src/main/java/org/apache/tamaya/cdi/ConfigurationProducer.java index 1d07c98..ac6a4f9 100644 --- a/modules/injection/cdi/src/main/java/org/apache/tamaya/cdi/ConfigurationProducer.java +++ b/modules/injection/cdi/src/main/java/org/apache/tamaya/cdi/ConfigurationProducer.java @@ -24,18 +24,11 @@ import org.apache.tamaya.spi.ConversionContext; import org.apache.tamaya.spi.PropertyConverter; import javax.enterprise.context.ApplicationScoped; +import javax.enterprise.inject.Instance; import javax.enterprise.inject.Produces; import javax.enterprise.inject.spi.InjectionPoint; -import java.io.File; -import java.lang.reflect.AnnotatedElement; -import java.lang.reflect.Field; -import java.lang.reflect.Member; -import java.lang.reflect.Method; -import java.math.BigDecimal; -import java.math.BigInteger; -import java.util.Calendar; -import java.util.Date; -import java.util.GregorianCalendar; +import javax.inject.Provider; +import java.lang.reflect.*; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; @@ -65,7 +58,7 @@ public class ConfigurationProducer { return createDynamicValue(injectionPoint); } final Config annotation = injectionPoint.getAnnotated().getAnnotation(Config.class); - final ConfigDefaultSections typeAnnot = injectionPoint.getAnnotated().getAnnotation(ConfigDefaultSections.class); + final ConfigDefaultSections typeAnnot = injectionPoint.getMember().getDeclaringClass().getAnnotation(ConfigDefaultSections.class); final List<String> keys = TamayaCDIInjectionExtension.evaluateKeys(injectionPoint.getMember().getName(), annotation != null ? annotation.value() : null, typeAnnot != null ? typeAnnot.value() : null); @@ -83,64 +76,98 @@ public class ConfigurationProducer { // unless the extension is not installed, this should never happen because the extension // enforces the resolvability of the config + + String defaultTextValue = annotation.defaultValue().equals(Config.UNCONFIGURED_VALUE) ? null : annotation.defaultValue(); + String textValue = null; Configuration config = ConfigurationProvider.getConfiguration(); - if (operator != null) { - config = operator.operate(config); + if(operator!=null) { + config = config.with(operator); } - final Class<?> toType = (Class<?>) injectionPoint.getAnnotated().getBaseType(); - String textValue = null; - String defaultTextValue = annotation.defaultValue().isEmpty() ? "" : annotation.defaultValue(); String keyFound = null; - for (String key : keys) { + for(String key:keys) { textValue = config.get(key); - if (textValue != null) { + if(textValue!=null) { keyFound = key; break; } } - ConversionContext.Builder builder = new ConversionContext.Builder(config, - ConfigurationProvider.getConfiguration().getContext(), keyFound, TypeLiteral.of(toType)); - if (injectionPoint.getMember() instanceof AnnotatedElement) { - builder.setAnnotatedElement((AnnotatedElement) injectionPoint.getMember()); + if(textValue==null) { + textValue = defaultTextValue; } - ConversionContext conversionContext = builder.build(); - Object value = null; - if (keyFound != null) { - if (customConverter != null) { - value = customConverter.convert(textValue, conversionContext); - } - if (value == null) { - value = config.get(keyFound, toType); + ConversionContext conversionContext = createConversionContext(keyFound, keys, injectionPoint); + Object value = convertValue(textValue, conversionContext, injectionPoint, customConverter); + if (value == null) { + throw new ConfigException(String.format( + "Can't resolve any of the possible config keys: %s to the required target type: %s, supported formats: %s", + keys, conversionContext.getTargetType(), conversionContext.getSupportedFormats().toString())); + } + LOGGER.finest(String.format("Injecting %s for key %s in class %s", keyFound, value.toString(), injectionPoint.toString())); + return value; + } + + static ConversionContext createConversionContext(String key, List<String> keys, InjectionPoint injectionPoint) { + final Type targetType = injectionPoint.getAnnotated().getBaseType(); + Configuration config = ConfigurationProvider.getConfiguration(); + ConversionContext.Builder builder = new ConversionContext.Builder(config, + ConfigurationProvider.getConfiguration().getContext(), key, TypeLiteral.of(targetType)); + // builder.setKeys(keys); + if(targetType instanceof ParameterizedType){ + ParameterizedType pt = (ParameterizedType)targetType; + if(pt.getRawType().equals(Provider.class)) { + builder.setTargetType( + TypeLiteral.of(pt.getActualTypeArguments()[0])); } - } else if (defaultTextValue != null) { - value = defaultTextValue; - if (customConverter != null) { - value = customConverter.convert((String)value, conversionContext); + } + if (injectionPoint.getMember() instanceof Field) { + Field annotated = (Field)injectionPoint.getMember(); + if(annotated.isAnnotationPresent(Config.class)) { + builder.setAnnotatedElement(annotated); } - if (value != null) { - List<PropertyConverter<Object>> converters = ConfigurationProvider.getConfiguration().getContext() - .getPropertyConverters(TypeLiteral.of(toType)); - for (PropertyConverter<Object> converter : converters) { - try { - value = converter.convert(defaultTextValue, conversionContext); - if (value != null) { - LOGGER.log(Level.FINEST, "Parsed default value from '" + defaultTextValue + "' into " + - injectionPoint); - break; - } - } catch (Exception e) { - LOGGER.log(Level.FINEST, "Failed to convert default value '" + defaultTextValue + "' for " + - injectionPoint, e); + }else if(injectionPoint.getMember() instanceof Method){ + Method method = (Method)injectionPoint.getMember(); + for(Type type:method.getParameterTypes()){ + if(type instanceof AnnotatedElement){ + AnnotatedElement annotated = (AnnotatedElement)type; + if(annotated.isAnnotationPresent(Config.class)) { + builder.setAnnotatedElement(annotated); } } } } - if (value == null) { - throw new ConfigException(String.format( - "Can't resolve any of the possible config keys: %s to the required target type: %s, supported formats: %s", - keys.toString(), toType.getName(), conversionContext.getSupportedFormats().toString())); + return builder.build(); + } + + static Object convertValue(String textValue, ConversionContext conversionContext, InjectionPoint injectionPoint, + PropertyConverter customConverter) { + if (customConverter != null) { + return customConverter.convert(textValue, conversionContext); + } + if(String.class.equals(conversionContext.getTargetType().getRawType())){ + return textValue; + } + Object value = null; + Type toType = injectionPoint.getAnnotated().getBaseType(); + if(toType instanceof ParameterizedType){ + ParameterizedType pt = (ParameterizedType)toType; + if(Provider.class.equals(pt.getRawType()) || Instance.class.equals(pt.getRawType())){ + toType = pt.getActualTypeArguments()[0]; + } + } + List<PropertyConverter<Object>> converters = ConfigurationProvider.getConfiguration().getContext() + .getPropertyConverters(TypeLiteral.of(toType)); + for (PropertyConverter<Object> converter : converters) { + try { + value = converter.convert(textValue, conversionContext); + if (value != null) { + LOGGER.log(Level.FINEST, "Parsed value from '" + textValue + "' into " + + injectionPoint); + break; + } + } catch (Exception e) { + LOGGER.log(Level.FINEST, "Failed to convert value '" + textValue + "' for " + + injectionPoint, e); + } } - LOGGER.finest(String.format("Injecting %s for key %s in class %s", keyFound, value.toString(), injectionPoint.toString())); return value; } http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/fe5eac60/modules/injection/cdi/src/main/java/org/apache/tamaya/cdi/TamayaCDIInjectionExtension.java ---------------------------------------------------------------------- diff --git a/modules/injection/cdi/src/main/java/org/apache/tamaya/cdi/TamayaCDIInjectionExtension.java b/modules/injection/cdi/src/main/java/org/apache/tamaya/cdi/TamayaCDIInjectionExtension.java index 749c9b0..2485f05 100644 --- a/modules/injection/cdi/src/main/java/org/apache/tamaya/cdi/TamayaCDIInjectionExtension.java +++ b/modules/injection/cdi/src/main/java/org/apache/tamaya/cdi/TamayaCDIInjectionExtension.java @@ -18,8 +18,6 @@ package org.apache.tamaya.cdi; import org.apache.tamaya.ConfigException; import org.apache.tamaya.ConfigOperator; -import org.apache.tamaya.Configuration; -import org.apache.tamaya.ConfigurationProvider; import org.apache.tamaya.inject.api.Config; import org.apache.tamaya.inject.api.ConfigDefaultSections; import org.apache.tamaya.inject.api.WithConfigOperator; @@ -28,9 +26,11 @@ import org.apache.tamaya.spi.PropertyConverter; import javax.enterprise.context.spi.CreationalContext; import javax.enterprise.event.Observes; +import javax.enterprise.inject.Instance; import javax.enterprise.inject.spi.*; +import javax.inject.Provider; import java.lang.annotation.Annotation; -import java.lang.reflect.Type; +import java.lang.reflect.*; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.logging.Logger; @@ -51,7 +51,7 @@ public class TamayaCDIInjectionExtension implements Extension { static final Map<Class, PropertyConverter> CUSTOM_CONVERTERS = new ConcurrentHashMap<>(); private final Set<Type> types = new HashSet<>(); - private Bean<?> convBean; + private Bean<?> tamayaProducerBean; /** * Constructor for loading logging its load. @@ -71,15 +71,14 @@ public class TamayaCDIInjectionExtension implements Extension { CDIConfiguredType configuredType = new CDIConfiguredType(pb.getBean().getBeanClass()); boolean configured = false; - boolean logged = false; for (InjectionPoint injectionPoint : ips) { if (injectionPoint.getAnnotated().isAnnotationPresent(Config.class)) { + LOG.fine("Configuring: " + injectionPoint); final Config annotation = injectionPoint.getAnnotated().getAnnotation(Config.class); - final ConfigDefaultSections typeAnnot = injectionPoint.getAnnotated().getAnnotation(ConfigDefaultSections.class); + final ConfigDefaultSections typeAnnot = injectionPoint.getMember().getDeclaringClass().getAnnotation(ConfigDefaultSections.class); final List<String> keys = evaluateKeys(injectionPoint.getMember().getName(), annotation!=null?annotation.value():null, typeAnnot!=null?typeAnnot.value():null); - final WithConfigOperator withOperatorAnnot = injectionPoint.getAnnotated().getAnnotation(WithConfigOperator.class); if(withOperatorAnnot!=null){ tryLoadOpererator(withOperatorAnnot.value()); @@ -88,34 +87,12 @@ public class TamayaCDIInjectionExtension implements Extension { if(withConverterAnnot!=null){ tryLoadConverter(withConverterAnnot.value()); } - - // We don't want to wait until the injection really fails at runtime. - // If there is a non resolvable configuration, we want to know at startup. - Configuration config = ConfigurationProvider.getConfiguration(); - String value = null; - for(String key:keys) { - value = config.get(key); - if(value!=null){ - break; - } - } - if(value==null && !annotation.defaultValue().isEmpty()){ - value = annotation.defaultValue(); - } - if(value==null){ - throw new ConfigException(String.format( - "Cannot resolve any of the possible configuration keys: %s. Please provide one of the given keys " + - "with a value in your configuration sources.", - keys.toString())); - } - types.add(injectionPoint.getType()); - if(annotation!=null){ - configured = true; - if(!logged) { - LOG.finest("Enabling Tamaya CDI Configuration on bean: " + configuredType.getName()); - } - configuredType.addConfiguredMember(injectionPoint, keys); - } + Type originalType = injectionPoint.getAnnotated().getBaseType(); + Type convertedType = unwrapType(originalType); + types.add(convertedType); + configured = true; + LOG.finest("Enabling Tamaya CDI Configuration on bean: " + configuredType.getName()); + configuredType.addConfiguredMember(injectionPoint, keys); } } if(configured) { @@ -126,15 +103,24 @@ public class TamayaCDIInjectionExtension implements Extension { public void captureConvertBean(@Observes final ProcessProducerMethod<?, ?> ppm) { if (ppm.getAnnotated().isAnnotationPresent(Config.class)) { - convBean = ppm.getBean(); + tamayaProducerBean = ppm.getBean(); } - } public void addConverter(@Observes final AfterBeanDiscovery abd, final BeanManager bm) { - if(!types.isEmpty()) { - abd.addBean(new ConverterBean(convBean, types)); + if(!types.isEmpty()&& tamayaProducerBean!=null) { + abd.addBean(new ConverterBean(tamayaProducerBean, types)); + } + } + + private Type unwrapType(Type type) { + if(type instanceof ParameterizedType) { + Type rawType = ((ParameterizedType) type).getRawType(); + if(rawType == Provider.class || rawType == Instance.class) { + return ((ParameterizedType) type).getActualTypeArguments()[0]; + } } + return type; } private void tryLoadOpererator(Class<? extends ConfigOperator> operatorClass) { @@ -215,7 +201,7 @@ public class TamayaCDIInjectionExtension implements Extension { public ConverterBean(final Bean convBean, final Set<Type> types) { this.types = types; - this.delegate = convBean; + this.delegate = Objects.requireNonNull(convBean); } @Override http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/fe5eac60/modules/injection/cdi/src/test/java/org/apache/tamaya/cdi/ConfigurationProducerFailedInjectionTest.java ---------------------------------------------------------------------- diff --git a/modules/injection/cdi/src/test/java/org/apache/tamaya/cdi/ConfigurationProducerFailedInjectionTest.java b/modules/injection/cdi/src/test/java/org/apache/tamaya/cdi/ConfigurationProducerFailedInjectionTest.java deleted file mode 100644 index a590c0d..0000000 --- a/modules/injection/cdi/src/test/java/org/apache/tamaya/cdi/ConfigurationProducerFailedInjectionTest.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.tamaya.cdi; - -import org.apache.openejb.OpenEjbContainer; -import org.junit.Test; - -import javax.ejb.embeddable.EJBContainer; - -public class ConfigurationProducerFailedInjectionTest { - - @Test(expected = OpenEjbContainer.AssembleApplicationException.class) - public void notFoundShouldNotDeploy() { - // this explicitly tests that a non resolvable config makes - // the deployment fail and we won't have any failure at runtime - EJBContainer.createEJBContainer(); - } - -} http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/fe5eac60/modules/injection/cdi/src/test/java/org/apache/tamaya/cdi/ConfigurationProducerTest.java ---------------------------------------------------------------------- diff --git a/modules/injection/cdi/src/test/java/org/apache/tamaya/cdi/ConfigurationProducerTest.java b/modules/injection/cdi/src/test/java/org/apache/tamaya/cdi/ConfigurationProducerTest.java index b62eb66..138a83d 100644 --- a/modules/injection/cdi/src/test/java/org/apache/tamaya/cdi/ConfigurationProducerTest.java +++ b/modules/injection/cdi/src/test/java/org/apache/tamaya/cdi/ConfigurationProducerTest.java @@ -16,34 +16,39 @@ */ package org.apache.tamaya.cdi; -import org.apache.openejb.jee.EjbJar; -import org.apache.openejb.junit.ApplicationComposer; -import org.apache.openejb.testing.Classes; -import org.apache.openejb.testing.Module; -import org.apache.tamaya.cdi.ConfigurationProducer; -import org.apache.tamaya.cdi.TamayaCDIAccessor; -import org.apache.tamaya.cdi.TamayaCDIInjectionExtension; import org.apache.tamaya.inject.api.Config; +import org.jboss.arquillian.container.test.api.Deployment; +import org.jboss.arquillian.junit.Arquillian; +import org.jboss.shrinkwrap.api.Archive; +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.asset.EmptyAsset; +import org.jboss.shrinkwrap.api.spec.WebArchive; import org.junit.Test; import org.junit.runner.RunWith; +import org.junit.runners.model.InitializationError; +import javax.enterprise.inject.spi.Extension; import javax.inject.Inject; +import javax.inject.Provider; import java.io.File; +import java.util.Optional; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; -@RunWith(ApplicationComposer.class) +@RunWith(Arquillian.class) public class ConfigurationProducerTest { - @Module - @Classes(cdi = true, value = { - AllTypes.class, - TamayaCDIInjectionExtension.class, TamayaCDIAccessor.class, - ConfigurationProducer.class - }) - public EjbJar jar() { - return new EjbJar("config"); + @Deployment + public static Archive deployment() { + return ShrinkWrap.create(WebArchive.class) + .addClasses(ConfiguredClass.class, InjectedClass.class, + TamayaCDIInjectionExtension.class, TamayaCDIAccessor.class, + ConfigurationProducer.class) + .addAsServiceProvider(Extension.class, TamayaCDIInjectionExtension.class) + .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml") + .addAsWebInfResource("META-INF/javaconfiguration.properties", "META-INF/javaconfiguration.properties"); } @Inject @@ -69,13 +74,60 @@ public class ConfigurationProducerTest { assertEquals(123, (int) allTypes.getInteger()); } + @Test + public void optionalStringFieldIsSet() { + assertNotNull(allTypes); + assertNotNull(allTypes.optionalString); + assertTrue(allTypes.optionalString.isPresent()); + assertEquals("hello", allTypes.optionalString.get()); + } + + @Test + public void optionalIntegerFieldIsSet() { + assertNotNull(allTypes); + assertNotNull(allTypes.optionalInteger); + assertTrue(allTypes.optionalInteger.isPresent()); + assertEquals(123, allTypes.optionalInteger.get().longValue()); + } + + @Test + public void providerStringFieldIsSet() { + assertNotNull(allTypes); + assertNotNull(allTypes.providerString); + assertEquals("hello", allTypes.providerString.get()); + assertEquals("hello", allTypes.providerString.get()); + } + + @Test + public void providerIntegerFieldIsSet() { + assertNotNull(allTypes); + assertNotNull(allTypes.providerInteger); + assertEquals(123, allTypes.providerInteger.get().longValue()); + assertEquals(123, allTypes.providerInteger.get().longValue()); + } + static class AllTypes { + private String stringAsMethodParam; + private Integer integerAsMethodParam; + private Optional<String> optionalStringAsMethodParam; + private Optional<Integer> optionalIntegerAsMethodParam; + private Provider<String> providerStringAsMethodParam; + private Provider<Integer> providerIntegerAsMethodParam; + @Inject @Config(value = "string.value", defaultValue = "defaultString") private String string; @Inject + @Config(value = "string.value", defaultValue = "defaultString") + private Optional<String> optionalString; + + @Inject + @Config(value = "string.value", defaultValue = "defaultString") + private Provider<String> providerString; + + @Inject @Config(value = "defaultString.value", defaultValue = "defaultString") private String defaultString; @@ -103,6 +155,14 @@ public class ConfigurationProducerTest { @Config(value = "defaultInteger.value", defaultValue = "45") private Integer defaultInteger; + @Inject + @Config(value = "integer.value", defaultValue = "45") + private Optional<Integer> optionalInteger; + + @Inject + @Config(value = "integer.value", defaultValue = "45") + private Provider<Integer> providerInteger; + public String getString() { return string; } @@ -135,6 +195,37 @@ public class ConfigurationProducerTest { return defaultInteger; } + + @Inject + public void setStringAsMethodParam(@Config(value = "string.value", defaultValue = "defaultString") String stringAsMethodParam) { + this.stringAsMethodParam = stringAsMethodParam; + } + + @Inject + public void setIntegerAsMethodParam(@Config(value = "integer.value", defaultValue = "45")Integer integerAsMethodParam) { + this.integerAsMethodParam = integerAsMethodParam; + } + + @Inject + public void setOptionalStringAsMethodParam(@Config(value = "string.value", defaultValue = "defaultString") Optional<String> optionalStringAsMethodParam) { + this.optionalStringAsMethodParam = optionalStringAsMethodParam; + } + + @Inject + public void setOptionalIntegerAsMethodParam(@Config(value = "integer.value", defaultValue = "45") Optional<Integer> optionalIntegerAsMethodParam) { + this.optionalIntegerAsMethodParam = optionalIntegerAsMethodParam; + } + + @Inject + public void setProviderStringAsMethodParam(@Config(value = "string.value", defaultValue = "defaultString") Provider<String> providerStringAsMethodParam) { + this.providerStringAsMethodParam = providerStringAsMethodParam; + } + + @Inject + public void setProviderIntegerAsMethodParam(@Config(value = "integer.value", defaultValue = "45") Provider<Integer> providerIntegerAsMethodParam) { + this.providerIntegerAsMethodParam = providerIntegerAsMethodParam; + } + @Override public String toString() { return "AllTypes{" + http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/fe5eac60/modules/injection/cdi/src/test/java/org/apache/tamaya/cdi/ConfiguredTest.java ---------------------------------------------------------------------- diff --git a/modules/injection/cdi/src/test/java/org/apache/tamaya/cdi/ConfiguredTest.java b/modules/injection/cdi/src/test/java/org/apache/tamaya/cdi/ConfiguredTest.java index f45f445..f50a9c6 100644 --- a/modules/injection/cdi/src/test/java/org/apache/tamaya/cdi/ConfiguredTest.java +++ b/modules/injection/cdi/src/test/java/org/apache/tamaya/cdi/ConfiguredTest.java @@ -19,15 +19,20 @@ */ package org.apache.tamaya.cdi; -import org.apache.deltaspike.testcontrol.api.TestControl; -import org.apache.deltaspike.testcontrol.api.junit.CdiTestRunner; import org.hamcrest.MatcherAssert; +import org.jboss.arquillian.container.test.api.Deployment; +import org.jboss.arquillian.junit.Arquillian; +import org.jboss.shrinkwrap.api.Archive; +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.asset.EmptyAsset; +import org.jboss.shrinkwrap.api.spec.WebArchive; import org.junit.Test; import org.junit.runner.RunWith; +import org.junit.runners.model.InitializationError; +import org.mockito.AdditionalMatchers; -import javax.enterprise.context.ApplicationScoped; import javax.enterprise.inject.spi.CDI; -import javax.inject.Singleton; +import javax.enterprise.inject.spi.Extension; import static org.hamcrest.core.Is.is; import static org.junit.Assert.assertNotNull; @@ -36,9 +41,19 @@ import static org.junit.Assert.assertTrue; /** * Tests for CDI integration. */ -@RunWith(CdiTestRunner.class) -@TestControl(startScopes = {ApplicationScoped.class, Singleton.class}) -public class ConfiguredTest{ +@RunWith(Arquillian.class) +public class ConfiguredTest { + + @Deployment + public static Archive deployment() { + return ShrinkWrap.create(WebArchive.class) + .addClasses(ConfiguredTest.class, ConfiguredClass.class, InjectedClass.class, + AdditionalMatchers.class, NotFoundNoDefault.class, + ConfigurationProducer.class) + .addAsServiceProvider(Extension.class, TamayaCDIInjectionExtension.class) + .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml") + .addAsWebInfResource("META-INF/javaconfiguration.properties", "META-INF/javaconfiguration.properties"); + } @Test public void test_Configuration_is_injected_correctly(){ http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/fe5eac60/modules/injection/cdi/src/test/java/org/apache/tamaya/cdi/NotFoundNoDefault.java ---------------------------------------------------------------------- diff --git a/modules/injection/cdi/src/test/java/org/apache/tamaya/cdi/NotFoundNoDefault.java b/modules/injection/cdi/src/test/java/org/apache/tamaya/cdi/NotFoundNoDefault.java index e08dac3..6e4e50e 100644 --- a/modules/injection/cdi/src/test/java/org/apache/tamaya/cdi/NotFoundNoDefault.java +++ b/modules/injection/cdi/src/test/java/org/apache/tamaya/cdi/NotFoundNoDefault.java @@ -17,11 +17,11 @@ package org.apache.tamaya.cdi; import org.apache.tamaya.inject.api.Config; -import org.tomitribe.util.Duration; import javax.enterprise.inject.Alternative; import javax.inject.Inject; import java.io.File; +import java.time.Duration; @Alternative http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/fe5eac60/modules/injection/injection-api/src/main/java/org/apache/tamaya/inject/api/Config.java ---------------------------------------------------------------------- diff --git a/modules/injection/injection-api/src/main/java/org/apache/tamaya/inject/api/Config.java b/modules/injection/injection-api/src/main/java/org/apache/tamaya/inject/api/Config.java index 67a3bfc..10ba0c8 100644 --- a/modules/injection/injection-api/src/main/java/org/apache/tamaya/inject/api/Config.java +++ b/modules/injection/injection-api/src/main/java/org/apache/tamaya/inject/api/Config.java @@ -89,6 +89,9 @@ import java.lang.annotation.Target; @Target(value = { ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER }) public @interface Config { + /** Value that is set by default as default, so it is possible to use empty Strings as default values. */ + String UNCONFIGURED_VALUE = "org.apache.tamaya.config.configproperty.unconfigureddvalue"; + /** * Defines the configuration property keys to be used. Hereby the first non null value evaluated is injected as * property value. @@ -109,7 +112,7 @@ public @interface Config { * @return default value used in case resolution fails. */ @Nonbinding - String defaultValue() default ""; + String defaultValue() default UNCONFIGURED_VALUE; /** * Flag that defines if a configuration property is required. If a required http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/fe5eac60/modules/injection/standalone/src/main/java/org/apache/tamaya/inject/internal/InjectionHelper.java ---------------------------------------------------------------------- diff --git a/modules/injection/standalone/src/main/java/org/apache/tamaya/inject/internal/InjectionHelper.java b/modules/injection/standalone/src/main/java/org/apache/tamaya/inject/internal/InjectionHelper.java index f34393d..07a0431 100644 --- a/modules/injection/standalone/src/main/java/org/apache/tamaya/inject/internal/InjectionHelper.java +++ b/modules/injection/standalone/src/main/java/org/apache/tamaya/inject/internal/InjectionHelper.java @@ -134,10 +134,9 @@ final class InjectionHelper { } String configValue = evaluteConfigValue(keys, retKey, config); if (configValue == null) { - if(prop==null || prop.defaultValue().isEmpty()){ - return null; + if(prop!=null && !prop.defaultValue().equals(Config.UNCONFIGURED_VALUE)){ + return prop.defaultValue(); } - return prop.defaultValue(); } return configValue; }
