You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tamaya.apache.org by an...@apache.org on 2015/06/14 00:18:39 UTC
[1/2] incubator-tamaya git commit: Moved extension into internal
package, since extension is not meant for user access.
Repository: incubator-tamaya
Updated Branches:
refs/heads/master fc155997c -> 4d5609848
Moved extension into internal package, since extension is not meant for user access.
Project: http://git-wip-us.apache.org/repos/asf/incubator-tamaya/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-tamaya/commit/eef4efe6
Tree: http://git-wip-us.apache.org/repos/asf/incubator-tamaya/tree/eef4efe6
Diff: http://git-wip-us.apache.org/repos/asf/incubator-tamaya/diff/eef4efe6
Branch: refs/heads/master
Commit: eef4efe63668372a3583eab5dcc103a1e20b71a2
Parents: fc15599
Author: Anatole Tresch <at...@java.net>
Authored: Sun Jun 14 00:00:36 2015 +0200
Committer: Anatole Tresch <at...@java.net>
Committed: Sun Jun 14 00:00:36 2015 +0200
----------------------------------------------------------------------
.../integration/cdi/ConfigurationExtension.java | 79 --------------------
.../cdi/internal/ConfigurationExtension.java | 79 ++++++++++++++++++++
.../javax.enterprise.inject.spi.Extension | 2 +-
3 files changed, 80 insertions(+), 80 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/eef4efe6/sandbox/integration/cdi/src/main/java/org/apache/tamaya/integration/cdi/ConfigurationExtension.java
----------------------------------------------------------------------
diff --git a/sandbox/integration/cdi/src/main/java/org/apache/tamaya/integration/cdi/ConfigurationExtension.java b/sandbox/integration/cdi/src/main/java/org/apache/tamaya/integration/cdi/ConfigurationExtension.java
deleted file mode 100644
index 2e1473a..0000000
--- a/sandbox/integration/cdi/src/main/java/org/apache/tamaya/integration/cdi/ConfigurationExtension.java
+++ /dev/null
@@ -1,79 +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.integration.cdi;
-
-import org.apache.tamaya.core.internal.inject.ConfigurationInjector;
-import org.apache.tamaya.core.internal.inject.ConfiguredType;
-
-import javax.enterprise.context.spi.CreationalContext;
-import javax.enterprise.event.Observes;
-import javax.enterprise.inject.Vetoed;
-import javax.enterprise.inject.spi.*;
-import java.util.*;
-
-/**
- * CDI portable extension that integrates {@link org.apache.tamaya.core.internal.inject.ConfigurationInjector}
- * with CDI by adding configuration features to CDI (config enable CDI beans).
- */
-@Vetoed
-public final class ConfigurationExtension implements Extension {
-
- public <T> void initializeConfiguredFields(final @Observes ProcessInjectionTarget<T> pit) {
- final AnnotatedType<T> at = pit.getAnnotatedType();
- if (!ConfiguredType.isConfigured(at.getJavaClass())) {
- return;
- }
- final InjectionTarget<T> it = pit.getInjectionTarget();
- InjectionTarget<T> wrapped = new InjectionTarget<T>() {
- @Override
- public void inject(T instance, CreationalContext<T> ctx) {
- it.inject(instance, ctx);
- ConfigurationInjector.configure(instance);
- }
-
- @Override
- public void postConstruct(T instance) {
- it.postConstruct(instance);
- }
-
- @Override
- public void preDestroy(T instance) {
- it.dispose(instance);
- }
-
- @Override
- public void dispose(T instance) {
- it.dispose(instance);
- }
-
- @Override
- public Set<InjectionPoint> getInjectionPoints() {
- return it.getInjectionPoints();
- }
-
- @Override
- public T produce(CreationalContext<T> ctx) {
- return it.produce(ctx);
- }
- };
- pit.setInjectionTarget(wrapped);
- }
-
-
-}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/eef4efe6/sandbox/integration/cdi/src/main/java/org/apache/tamaya/integration/cdi/internal/ConfigurationExtension.java
----------------------------------------------------------------------
diff --git a/sandbox/integration/cdi/src/main/java/org/apache/tamaya/integration/cdi/internal/ConfigurationExtension.java b/sandbox/integration/cdi/src/main/java/org/apache/tamaya/integration/cdi/internal/ConfigurationExtension.java
new file mode 100644
index 0000000..cdc98a6
--- /dev/null
+++ b/sandbox/integration/cdi/src/main/java/org/apache/tamaya/integration/cdi/internal/ConfigurationExtension.java
@@ -0,0 +1,79 @@
+/*
+ * 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.integration.cdi.internal;
+
+import org.apache.tamaya.core.internal.inject.ConfigurationInjector;
+import org.apache.tamaya.core.internal.inject.ConfiguredType;
+
+import javax.enterprise.context.spi.CreationalContext;
+import javax.enterprise.event.Observes;
+import javax.enterprise.inject.Vetoed;
+import javax.enterprise.inject.spi.*;
+import java.util.*;
+
+/**
+ * CDI portable extension that integrates {@link org.apache.tamaya.core.internal.inject.ConfigurationInjector}
+ * with CDI by adding configuration features to CDI (config enable CDI beans).
+ */
+@Vetoed
+public final class ConfigurationExtension implements Extension {
+
+ public <T> void initializeConfiguredFields(final @Observes ProcessInjectionTarget<T> pit) {
+ final AnnotatedType<T> at = pit.getAnnotatedType();
+ if (!ConfiguredType.isConfigured(at.getJavaClass())) {
+ return;
+ }
+ final InjectionTarget<T> it = pit.getInjectionTarget();
+ InjectionTarget<T> wrapped = new InjectionTarget<T>() {
+ @Override
+ public void inject(T instance, CreationalContext<T> ctx) {
+ it.inject(instance, ctx);
+ ConfigurationInjector.configure(instance);
+ }
+
+ @Override
+ public void postConstruct(T instance) {
+ it.postConstruct(instance);
+ }
+
+ @Override
+ public void preDestroy(T instance) {
+ it.dispose(instance);
+ }
+
+ @Override
+ public void dispose(T instance) {
+ it.dispose(instance);
+ }
+
+ @Override
+ public Set<InjectionPoint> getInjectionPoints() {
+ return it.getInjectionPoints();
+ }
+
+ @Override
+ public T produce(CreationalContext<T> ctx) {
+ return it.produce(ctx);
+ }
+ };
+ pit.setInjectionTarget(wrapped);
+ }
+
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/eef4efe6/sandbox/integration/cdi/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension
----------------------------------------------------------------------
diff --git a/sandbox/integration/cdi/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension b/sandbox/integration/cdi/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension
index 2249aca..3b909e7 100644
--- a/sandbox/integration/cdi/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension
+++ b/sandbox/integration/cdi/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension
@@ -16,4 +16,4 @@
# specific language governing permissions and limitations
# under the License.
#
-org.apache.tamaya.integration.cdi.ConfigurationExtension
+org.apache.tamaya.integration.cdi.internal.ConfigurationExtension
[2/2] incubator-tamaya git commit: TAMAYA-74 Added support for type
narowwing on property conversion.
Posted by an...@apache.org.
TAMAYA-74 Added support for type narowwing on property conversion.
Project: http://git-wip-us.apache.org/repos/asf/incubator-tamaya/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-tamaya/commit/4d560984
Tree: http://git-wip-us.apache.org/repos/asf/incubator-tamaya/tree/4d560984
Diff: http://git-wip-us.apache.org/repos/asf/incubator-tamaya/diff/4d560984
Branch: refs/heads/master
Commit: 4d560984822e4ccc0b8bae0b00a98e278518a39e
Parents: eef4efe
Author: Anatole Tresch <at...@java.net>
Authored: Sun Jun 14 00:17:03 2015 +0200
Committer: Anatole Tresch <at...@java.net>
Committed: Sun Jun 14 00:17:03 2015 +0200
----------------------------------------------------------------------
.../core/internal/DefaultServiceContext.java | 21 ++-
.../core/internal/PropertyConverterManager.java | 186 ++++++++++++++-----
.../java/org/apache/tamaya/core/internal/A.java | 29 +++
.../java/org/apache/tamaya/core/internal/B.java | 29 +++
.../java/org/apache/tamaya/core/internal/C.java | 56 ++++++
.../tamaya/core/internal/CTestConverter.java | 31 ++++
.../internal/PropertyConverterManagerTest.java | 85 +++++++++
.../org.apache.tamaya.spi.PropertyConverter | 19 ++
.../core/internal/DefaultServiceContext.java | 20 +-
.../core/internal/PropertyConverterManager.java | 131 ++++++++++---
.../java/org/apache/tamaya/core/internal/A.java | 29 +++
.../java/org/apache/tamaya/core/internal/B.java | 29 +++
.../java/org/apache/tamaya/core/internal/C.java | 56 ++++++
.../tamaya/core/internal/CTestConverter.java | 31 ++++
.../internal/PropertyConverterManagerTest.java | 85 +++++++++
.../org.apache.tamaya.spi.PropertyConverter | 19 ++
16 files changed, 778 insertions(+), 78 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/4d560984/java7/core/src/main/java/org/apache/tamaya/core/internal/DefaultServiceContext.java
----------------------------------------------------------------------
diff --git a/java7/core/src/main/java/org/apache/tamaya/core/internal/DefaultServiceContext.java b/java7/core/src/main/java/org/apache/tamaya/core/internal/DefaultServiceContext.java
index 2e59fa2..15bbcef 100644
--- a/java7/core/src/main/java/org/apache/tamaya/core/internal/DefaultServiceContext.java
+++ b/java7/core/src/main/java/org/apache/tamaya/core/internal/DefaultServiceContext.java
@@ -90,6 +90,20 @@ public final class DefaultServiceContext implements ServiceContext {
return previousServices != null ? previousServices : services;
}
+ /**
+ * Checks the given instance for a @Priority annotation. If present the annotation's value s evaluated. If no such
+ * annotation is present, a default priority is returned (1);
+ * @param o the instance, not null.
+ * @return a priority, by default 1.
+ */
+ public static int getPriority(Object o){
+ int prio = 1; //X TODO discuss default priority
+ Priority priority = o.getClass().getAnnotation(Priority.class);
+ if (priority != null) {
+ prio = priority.value();
+ }
+ return prio;
+ }
/**
* @param services to scan
@@ -111,12 +125,7 @@ public final class DefaultServiceContext implements ServiceContext {
T highestService = null;
for (T service : services) {
- int prio = 1; //X TODO discuss default priority
- Priority priority = service.getClass().getAnnotation(Priority.class);
- if (priority != null) {
- prio = priority.value();
- }
-
+ int prio = getPriority(service);
if (highestPriority == null || highestPriority < prio) {
highestService = service;
highestPriorityServiceCount = 1;
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/4d560984/java7/core/src/main/java/org/apache/tamaya/core/internal/PropertyConverterManager.java
----------------------------------------------------------------------
diff --git a/java7/core/src/main/java/org/apache/tamaya/core/internal/PropertyConverterManager.java b/java7/core/src/main/java/org/apache/tamaya/core/internal/PropertyConverterManager.java
index 31a05b2..7fe6b11 100644
--- a/java7/core/src/main/java/org/apache/tamaya/core/internal/PropertyConverterManager.java
+++ b/java7/core/src/main/java/org/apache/tamaya/core/internal/PropertyConverterManager.java
@@ -24,6 +24,7 @@ import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -45,12 +46,38 @@ import org.apache.tamaya.spi.ServiceContextManager;
* This class is thread-safe.
*/
public class PropertyConverterManager {
- /** The logger used. */
+ /**
+ * The logger used.
+ */
private static final Logger LOG = Logger.getLogger(PropertyConverterManager.class.getName());
- /** The registered converters. */
+ /**
+ * The registered converters.
+ */
private Map<TypeLiteral<?>, List<PropertyConverter<?>>> converters = new ConcurrentHashMap<>();
- /** The lock used. */
+ /**
+ * The transitive converters.
+ */
+ private Map<TypeLiteral<?>, List<PropertyConverter<?>>> transitiveConverters = new ConcurrentHashMap<>();
+ /**
+ * The lock used.
+ */
private ReadWriteLock lock = new ReentrantReadWriteLock();
+
+ private static final Comparator<Object> PRIORITY_COMPARATOR = new Comparator<Object>() {
+
+ @Override
+ public int compare(Object o1, Object o2) {
+ int prio = DefaultServiceContext.getPriority(o1) - DefaultServiceContext.getPriority(o2);
+ if (prio < 0) {
+ return 1;
+ } else if (prio > 0) {
+ return -1;
+ } else {
+ return o1.getClass().getSimpleName().compareTo(o2.getClass().getSimpleName());
+ }
+ }
+ };
+
/**
* Constructor.
*/
@@ -68,7 +95,7 @@ public class PropertyConverterManager {
* Registers the default converters provided out of the box.
*/
protected void initConverters() {
- for(PropertyConverter conv: ServiceContextManager.getServiceContext().getServices(PropertyConverter.class)){
+ for (PropertyConverter conv : ServiceContextManager.getServiceContext().getServices(PropertyConverter.class)) {
Type type = TypeLiteral.getGenericInterfaceTypeParameters(conv.getClass(), PropertyConverter.class)[0];
register(TypeLiteral.of(type), conv);
}
@@ -86,13 +113,48 @@ public class PropertyConverterManager {
Lock writeLock = lock.writeLock();
try {
writeLock.lock();
- List<PropertyConverter<T>> converters = List.class.cast(this.converters.get(targetType));
+ List converters = List.class.cast(this.converters.get(targetType));
List<PropertyConverter<?>> newConverters = new ArrayList<>();
if (converters != null) {
newConverters.addAll(converters);
}
newConverters.add(converter);
+ Collections.sort(newConverters, PRIORITY_COMPARATOR);
this.converters.put(targetType, Collections.unmodifiableList(newConverters));
+ // evaluate transitive closure for all inherited supertypes and implemented interfaces
+ // direct implemented interfaces
+ for (Class<?> ifaceType : targetType.getRawType().getInterfaces()) {
+ converters = List.class.cast(this.transitiveConverters.get(ifaceType));
+ newConverters = new ArrayList<>();
+ if (converters != null) {
+ newConverters.addAll(converters);
+ }
+ newConverters.add(converter);
+ Collections.sort(newConverters, PRIORITY_COMPARATOR);
+ this.transitiveConverters.put(TypeLiteral.of(ifaceType), Collections.unmodifiableList(newConverters));
+ }
+ Class<?> superClass = targetType.getRawType().getSuperclass();
+ while (superClass != null && !superClass.equals(Object.class)) {
+ converters = List.class.cast(this.transitiveConverters.get(superClass));
+ newConverters = new ArrayList<>();
+ if (converters != null) {
+ newConverters.addAll(converters);
+ }
+ newConverters.add(converter);
+ Collections.sort(newConverters, PRIORITY_COMPARATOR);
+ this.transitiveConverters.put(TypeLiteral.of(superClass), Collections.unmodifiableList(newConverters));
+ for (Class<?> ifaceType : superClass.getInterfaces()) {
+ converters = List.class.cast(this.transitiveConverters.get(ifaceType));
+ newConverters = new ArrayList<>();
+ if (converters != null) {
+ newConverters.addAll(converters);
+ }
+ newConverters.add(converter);
+ Collections.sort(newConverters, PRIORITY_COMPARATOR);
+ this.transitiveConverters.put(TypeLiteral.of(ifaceType), Collections.unmodifiableList(newConverters));
+ }
+ superClass = superClass.getSuperclass();
+ }
} finally {
writeLock.unlock();
}
@@ -105,8 +167,10 @@ public class PropertyConverterManager {
* @return true, if a converter for the given type is registered, or a default one can be created.
*/
public boolean isTargetTypeSupported(TypeLiteral<?> targetType) {
- return converters.containsKey(targetType)
- || createDefaultPropertyConverter(targetType) != null;
+ if (converters.containsKey(targetType) || transitiveConverters.containsKey(targetType)) {
+ return true;
+ }
+ return createDefaultPropertyConverter(targetType) != null;
}
/**
@@ -130,7 +194,26 @@ public class PropertyConverterManager {
/**
* Get the list of all current registered converters for the given target type.
* If not converters are registered, they component tries to create and register a dynamic
- * converter based on String costructor or static factory methods available.
+ * converter based on String costructor or static factory methods available.<br/>
+ * The converters provided are of the following type and returned in the following order:
+ * <ul>
+ * <li>Converters mapped explicitly to the required target type are returned first, ordered
+ * by decreasing priority. This means, if explicit converters are registered these are used
+ * primarly for converting a value.</li>
+ * <li>The target type of each explicitly registered converter also can be transitively mapped to
+ * 1) all directly implemented interfaces, 2) all its superclasses (except Object), 3) all the interfaces
+ * implemented by its superclasses. These groups of transitive converters is returned similarly in the
+ * order as mentioned, whereas also here a priority based decreasing ordering is applied.</li>
+ * <li>java.lang wrapper classes and native types are automatically mapped.</li>
+ * <li>If no explicit converters are registered, for Enum types a default implementation is provided that
+ * compares the configuration values with the different enum members defined (cases sensitive mapping).</li>
+ * </ul>
+ *
+ * So given that list above directly registered mappings always are tried first, before any transitive mapping
+ * should be used. Also in all cases @Priority annotations are honored for ordering of the converters in place.
+ * Transitive conversion is supported for all directly implemented interfaces (including inherited ones) and
+ * the inheritance hierarchy (exception Object). Superinterfaces of implemented interfaces are ignored.
+ *
*
* @param targetType the target type, not null.
* @param <T> the type class
@@ -139,7 +222,9 @@ public class PropertyConverterManager {
*/
public <T> List<PropertyConverter<T>> getPropertyConverters(TypeLiteral<T> targetType) {
Lock readLock = lock.readLock();
+ List<PropertyConverter<T>> converterList = new ArrayList<>();
List<PropertyConverter<T>> converters;
+ // direct mapped converters
try {
readLock.lock();
converters = List.class.cast(this.converters.get(targetType));
@@ -147,10 +232,21 @@ public class PropertyConverterManager {
readLock.unlock();
}
if (converters != null) {
- return converters;
+ converterList.addAll(converters);
+ }
+ // transitive converter
+ try {
+ readLock.lock();
+ converters = List.class.cast(this.transitiveConverters.get(targetType));
+ } finally {
+ readLock.unlock();
+ }
+ if (converters != null) {
+ converterList.addAll(converters);
}
+ // handling of java.lang wrapper classes
TypeLiteral<T> boxedType = mapBoxedType(targetType);
- if(boxedType!=null){
+ if (boxedType != null) {
try {
readLock.lock();
converters = List.class.cast(this.converters.get(boxedType));
@@ -158,79 +254,83 @@ public class PropertyConverterManager {
readLock.unlock();
}
if (converters != null) {
- return converters;
+ converterList.addAll(converters);
}
}
- PropertyConverter<T> defaultConverter = createDefaultPropertyConverter(targetType);
- if (defaultConverter != null) {
- register(targetType, defaultConverter);
- try {
- readLock.lock();
- converters = List.class.cast(this.converters.get(targetType));
- } finally {
- readLock.unlock();
+ if (converterList.isEmpty()) {
+ // adding any converters created on the fly, e.g. for enum types.
+ PropertyConverter<T> defaultConverter = createDefaultPropertyConverter(targetType);
+ if (defaultConverter != null) {
+ register(targetType, defaultConverter);
+ try {
+ readLock.lock();
+ converters = List.class.cast(this.converters.get(targetType));
+ } finally {
+ readLock.unlock();
+ }
+ }
+ if (converters != null) {
+ converterList.addAll(converters);
}
}
- if (converters != null) {
- return converters;
- }
- return Collections.emptyList();
+ return converterList;
}
/**
* Maps native types to the corresponding boxed types.
+ *
* @param targetType the native type.
- * @param <T> the type
+ * @param <T> the type
* @return the boxed type, or null.
*/
private <T> TypeLiteral<T> mapBoxedType(TypeLiteral<T> targetType) {
Type parameterType = targetType.getType();
- if(parameterType == int.class){
+ if (parameterType == int.class) {
return TypeLiteral.class.cast(TypeLiteral.of(Integer.class));
}
- if(parameterType == short.class){
+ if (parameterType == short.class) {
return TypeLiteral.class.cast(TypeLiteral.of(Short.class));
}
- if(parameterType == byte.class){
+ if (parameterType == byte.class) {
return TypeLiteral.class.cast(TypeLiteral.of(Byte.class));
}
- if(parameterType == long.class){
+ if (parameterType == long.class) {
return TypeLiteral.class.cast(TypeLiteral.of(Long.class));
}
- if(parameterType == boolean.class){
+ if (parameterType == boolean.class) {
return TypeLiteral.class.cast(TypeLiteral.of(Boolean.class));
}
- if(parameterType == char.class){
+ if (parameterType == char.class) {
return TypeLiteral.class.cast(TypeLiteral.of(Character.class));
}
- if(parameterType == float.class){
+ if (parameterType == float.class) {
return TypeLiteral.class.cast(TypeLiteral.of(Float.class));
}
- if(parameterType == double.class){
+ if (parameterType == double.class) {
return TypeLiteral.class.cast(TypeLiteral.of(Double.class));
}
- if(parameterType == int[].class){
+ if (parameterType == int[].class) {
return TypeLiteral.class.cast(TypeLiteral.of(Integer[].class));
}
- if(parameterType == short[].class){
+ if (parameterType == short[].class) {
return TypeLiteral.class.cast(TypeLiteral.of(Short[].class));
}
- if(parameterType == byte[].class){
+ if (parameterType == byte[].class) {
return TypeLiteral.class.cast(TypeLiteral.of(Byte[].class));
}
- if(parameterType == long[].class){
+ if (parameterType == long[].class) {
return TypeLiteral.class.cast(TypeLiteral.of(Long[].class));
}
- if(parameterType == boolean.class){
+ if (parameterType == boolean.class) {
return TypeLiteral.class.cast(TypeLiteral.of(Boolean.class));
}
- if(parameterType == char[].class){
+ if (parameterType == char[].class) {
return TypeLiteral.class.cast(TypeLiteral.of(Character[].class));
}
- if(parameterType == float[].class){
+ if (parameterType == float[].class) {
return TypeLiteral.class.cast(TypeLiteral.of(Float[].class));
}
- if(parameterType == double[].class){
+ if (parameterType == double[].class) {
return TypeLiteral.class.cast(TypeLiteral.of(Double[].class));
}
return null;
@@ -244,7 +344,7 @@ public class PropertyConverterManager {
* @return a new converter, or null.
*/
protected <T> PropertyConverter<T> createDefaultPropertyConverter(final TypeLiteral<T> targetType) {
- if(Enum.class.isAssignableFrom(targetType.getRawType())){
+ if (Enum.class.isAssignableFrom(targetType.getRawType())) {
return new EnumConverter<T>(targetType.getRawType());
}
PropertyConverter<T> converter = null;
@@ -285,7 +385,7 @@ public class PropertyConverterManager {
}
};
} catch (Exception e) {
- LOG.finest("Failed to construct instance of type: " + targetType.getRawType().getName()+": " + e);
+ LOG.finest("Failed to construct instance of type: " + targetType.getRawType().getName() + ": " + e);
}
}
return converter;
@@ -305,7 +405,7 @@ public class PropertyConverterManager {
m = type.getDeclaredMethod(name, String.class);
return m;
} catch (NoSuchMethodException | RuntimeException e) {
- LOG.finest("No such factory method found on type: " + type.getName()+", methodName: " + name);
+ LOG.finest("No such factory method found on type: " + type.getName() + ", methodName: " + name);
}
}
return null;
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/4d560984/java7/core/src/test/java/org/apache/tamaya/core/internal/A.java
----------------------------------------------------------------------
diff --git a/java7/core/src/test/java/org/apache/tamaya/core/internal/A.java b/java7/core/src/test/java/org/apache/tamaya/core/internal/A.java
new file mode 100644
index 0000000..aa77a5d
--- /dev/null
+++ b/java7/core/src/test/java/org/apache/tamaya/core/internal/A.java
@@ -0,0 +1,29 @@
+/*
+ * 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.core.internal;
+
+/**
+ * Test class for testing transitively evaluated property converters.
+ */
+public class A implements AutoCloseable{
+ @Override
+ public void close() throws Exception {
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/4d560984/java7/core/src/test/java/org/apache/tamaya/core/internal/B.java
----------------------------------------------------------------------
diff --git a/java7/core/src/test/java/org/apache/tamaya/core/internal/B.java b/java7/core/src/test/java/org/apache/tamaya/core/internal/B.java
new file mode 100644
index 0000000..31bafb6
--- /dev/null
+++ b/java7/core/src/test/java/org/apache/tamaya/core/internal/B.java
@@ -0,0 +1,29 @@
+/*
+ * 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.core.internal;
+
+/**
+ * Test class for testing transitively evaluated property converters.
+ */
+public class B extends A implements Runnable{
+ @Override
+ public void run() {
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/4d560984/java7/core/src/test/java/org/apache/tamaya/core/internal/C.java
----------------------------------------------------------------------
diff --git a/java7/core/src/test/java/org/apache/tamaya/core/internal/C.java b/java7/core/src/test/java/org/apache/tamaya/core/internal/C.java
new file mode 100644
index 0000000..aad1ef9
--- /dev/null
+++ b/java7/core/src/test/java/org/apache/tamaya/core/internal/C.java
@@ -0,0 +1,56 @@
+/*
+ * 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.core.internal;
+
+import java.io.IOException;
+import java.nio.CharBuffer;
+
+/**
+ * Test class for testing transitively evaluated property converters.
+ */
+public class C extends B implements Readable{
+
+ private String inValue;
+
+ public C(String inValue){
+ this.inValue = inValue;
+ }
+
+ @Override
+ public int read(CharBuffer cb) throws IOException {
+ return 0;
+ }
+
+ /**
+ * Returns the input value, set on creation. Used for test assertion.
+ * @return the in value.
+ */
+ public String getInValue() {
+ return inValue;
+ }
+
+ @Override
+ public String toString() {
+ return "C{" +
+ "inValue='" + inValue + '\'' +
+ '}';
+ }
+
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/4d560984/java7/core/src/test/java/org/apache/tamaya/core/internal/CTestConverter.java
----------------------------------------------------------------------
diff --git a/java7/core/src/test/java/org/apache/tamaya/core/internal/CTestConverter.java b/java7/core/src/test/java/org/apache/tamaya/core/internal/CTestConverter.java
new file mode 100644
index 0000000..62b8c9d
--- /dev/null
+++ b/java7/core/src/test/java/org/apache/tamaya/core/internal/CTestConverter.java
@@ -0,0 +1,31 @@
+/*
+ * 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.core.internal;
+
+import org.apache.tamaya.spi.PropertyConverter;
+
+/**
+ * Created by Anatole on 13.06.2015.
+ */
+public class CTestConverter implements PropertyConverter<C>{
+ @Override
+ public C convert(String value) {
+ return new C(value);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/4d560984/java7/core/src/test/java/org/apache/tamaya/core/internal/PropertyConverterManagerTest.java
----------------------------------------------------------------------
diff --git a/java7/core/src/test/java/org/apache/tamaya/core/internal/PropertyConverterManagerTest.java b/java7/core/src/test/java/org/apache/tamaya/core/internal/PropertyConverterManagerTest.java
index bd9b97f..9ec6076 100644
--- a/java7/core/src/test/java/org/apache/tamaya/core/internal/PropertyConverterManagerTest.java
+++ b/java7/core/src/test/java/org/apache/tamaya/core/internal/PropertyConverterManagerTest.java
@@ -57,6 +57,90 @@ public class PropertyConverterManagerTest {
assertThat(((MyType)result).getValue(), equalTo("IN"));
}
+ @Test
+ public void testDirectConverterMapping(){
+ PropertyConverterManager manager = new PropertyConverterManager();
+ List<PropertyConverter<C>> converters = List.class.cast(manager.getPropertyConverters(TypeLiteral.of(C.class)));
+ assertThat(converters, hasSize(1));
+
+ PropertyConverter<C> converter = converters.get(0);
+ C result = converter.convert("testDirectConverterMapping");
+
+ assertThat(result, notNullValue());
+ assertThat(result, instanceOf(C.class));
+ assertThat(((C)result).getInValue(), equalTo("testDirectConverterMapping"));
+ }
+
+ @Test
+ public void testDirectSuperclassConverterMapping(){
+ PropertyConverterManager manager = new PropertyConverterManager();
+ List<PropertyConverter<B>> converters = List.class.cast(manager.getPropertyConverters(TypeLiteral.of(B.class)));
+ assertThat(converters, hasSize(1));
+
+ PropertyConverter<B> converter = converters.get(0);
+ B result = converter.convert("testDirectSuperclassConverterMapping");
+
+ assertThat(result, notNullValue());
+ assertThat(result, instanceOf(C.class));
+ assertThat(((C)result).getInValue(), equalTo("testDirectSuperclassConverterMapping"));
+ }
+
+ @Test
+ public void testTransitiveSuperclassConverterMapping(){
+ PropertyConverterManager manager = new PropertyConverterManager();
+ List<PropertyConverter<A>> converters = List.class.cast(manager.getPropertyConverters(TypeLiteral.of(A.class)));
+ assertThat(converters, hasSize(1));
+
+ PropertyConverter<A> converter = converters.get(0);
+ A result = converter.convert("testTransitiveSuperclassConverterMapping");
+
+ assertThat(result, notNullValue());
+ assertThat(result, instanceOf(C.class));
+ assertThat(((C)result).getInValue(), equalTo("testTransitiveSuperclassConverterMapping"));
+ }
+
+ @Test
+ public void testDirectInterfaceMapping(){
+ PropertyConverterManager manager = new PropertyConverterManager();
+ List<PropertyConverter<Readable>> converters = List.class.cast(manager.getPropertyConverters(TypeLiteral.of(Readable.class)));
+ assertThat(converters, hasSize(1));
+
+ PropertyConverter<Readable> converter = converters.get(0);
+ Readable result = converter.convert("testDirectInterfaceMapping");
+
+ assertThat(result, notNullValue());
+ assertThat(result, instanceOf(C.class));
+ assertThat(((C)result).getInValue(), equalTo("testDirectInterfaceMapping"));
+ }
+
+ @Test
+ public void testTransitiveInterfaceMapping1(){
+ PropertyConverterManager manager = new PropertyConverterManager();
+ List<PropertyConverter<Runnable>> converters = List.class.cast(manager.getPropertyConverters(TypeLiteral.of(Runnable.class)));
+ assertThat(converters, hasSize(1));
+
+ PropertyConverter<Runnable> converter = converters.get(0);
+ Runnable result = converter.convert("testTransitiveInterfaceMapping1");
+
+ assertThat(result, notNullValue());
+ assertThat(result, instanceOf(C.class));
+ assertThat(((C)result).getInValue(), equalTo("testTransitiveInterfaceMapping1"));
+ }
+
+ @Test
+ public void testTransitiveInterfaceMapping2(){
+ PropertyConverterManager manager = new PropertyConverterManager();
+ List<PropertyConverter<AutoCloseable>> converters = List.class.cast(manager.getPropertyConverters(TypeLiteral.of(AutoCloseable.class)));
+ assertThat(converters, hasSize(1));
+
+ PropertyConverter<AutoCloseable> converter = converters.get(0);
+ AutoCloseable result = converter.convert("testTransitiveInterfaceMapping2");
+
+ assertThat(result, notNullValue());
+ assertThat(result, instanceOf(C.class));
+ assertThat(((C)result).getInValue(), equalTo("testTransitiveInterfaceMapping2"));
+ }
+
public static class MyType {
private String typeValue;
@@ -73,4 +157,5 @@ public class PropertyConverterManagerTest {
}
}
+
}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/4d560984/java7/core/src/test/resources/META-INF/services/org.apache.tamaya.spi.PropertyConverter
----------------------------------------------------------------------
diff --git a/java7/core/src/test/resources/META-INF/services/org.apache.tamaya.spi.PropertyConverter b/java7/core/src/test/resources/META-INF/services/org.apache.tamaya.spi.PropertyConverter
new file mode 100644
index 0000000..d039696
--- /dev/null
+++ b/java7/core/src/test/resources/META-INF/services/org.apache.tamaya.spi.PropertyConverter
@@ -0,0 +1,19 @@
+#
+# 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 current 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.
+#
+org.apache.tamaya.core.internal.CTestConverter
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/4d560984/java8/core/src/main/java/org/apache/tamaya/core/internal/DefaultServiceContext.java
----------------------------------------------------------------------
diff --git a/java8/core/src/main/java/org/apache/tamaya/core/internal/DefaultServiceContext.java b/java8/core/src/main/java/org/apache/tamaya/core/internal/DefaultServiceContext.java
index 42c928b..7315ef1 100644
--- a/java8/core/src/main/java/org/apache/tamaya/core/internal/DefaultServiceContext.java
+++ b/java8/core/src/main/java/org/apache/tamaya/core/internal/DefaultServiceContext.java
@@ -89,6 +89,20 @@ public final class DefaultServiceContext implements ServiceContext {
return previousServices != null ? previousServices : services;
}
+ /**
+ * Checks the given instance for a @Priority annotation. If present the annotation's value s evaluated. If no such
+ * annotation is present, a default priority is returned (1);
+ * @param o the instance, not null.
+ * @return a priority, by default 1.
+ */
+ public static int getPriority(Object o){
+ int prio = 1; //X TODO discuss default priority
+ Priority priority = o.getClass().getAnnotation(Priority.class);
+ if (priority != null) {
+ prio = priority.value();
+ }
+ return prio;
+ }
/**
* @param services to scan
@@ -110,11 +124,7 @@ public final class DefaultServiceContext implements ServiceContext {
T highestService = null;
for (T service : services) {
- int prio = 1; //X TODO discuss default priority
- Priority priority = service.getClass().getAnnotation(Priority.class);
- if (priority != null) {
- prio = priority.value();
- }
+ int prio = getPriority(service);
if (highestPriority == null || highestPriority < prio) {
highestService = service;
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/4d560984/java8/core/src/main/java/org/apache/tamaya/core/internal/PropertyConverterManager.java
----------------------------------------------------------------------
diff --git a/java8/core/src/main/java/org/apache/tamaya/core/internal/PropertyConverterManager.java b/java8/core/src/main/java/org/apache/tamaya/core/internal/PropertyConverterManager.java
index 333572e..3cb0656 100644
--- a/java8/core/src/main/java/org/apache/tamaya/core/internal/PropertyConverterManager.java
+++ b/java8/core/src/main/java/org/apache/tamaya/core/internal/PropertyConverterManager.java
@@ -22,12 +22,7 @@ import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
+import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.StampedLock;
@@ -48,8 +43,23 @@ public class PropertyConverterManager {
private static final Logger LOG = Logger.getLogger(PropertyConverterManager.class.getName());
/** The registered converters. */
private Map<TypeLiteral<?>, List<PropertyConverter<?>>> converters = new ConcurrentHashMap<>();
+ /** The transitive converters as evaluated based on the registered converters. */
+ private Map<TypeLiteral<?>, List<PropertyConverter<?>>> transitiveConverters = new ConcurrentHashMap<>();
/** The lock used. */
private StampedLock lock = new StampedLock();
+
+ private static final Comparator<Object> PRIORITY_COMPARATOR =
+ (o1,o2) -> {
+ int prio = DefaultServiceContext.getPriority(o1) - DefaultServiceContext.getPriority(o2);
+ if(prio<0){
+ return 1;
+ } else if(prio>0){
+ return -1;
+ } else{
+ return o1.getClass().getSimpleName().compareTo(o2.getClass().getSimpleName());
+ }
+ };
+
/**
* Constructor.
*/
@@ -91,7 +101,42 @@ public class PropertyConverterManager {
newConverters.addAll(converters);
}
newConverters.add(converter);
+ Collections.sort(newConverters, PRIORITY_COMPARATOR);
this.converters.put(targetType, Collections.unmodifiableList(newConverters));
+ // evaluate transitive closure for all inherited supertypes and implemented interfaces
+ // direct implemented interfaces
+ for(Class<?> ifaceType: targetType.getRawType().getInterfaces()){
+ converters = List.class.cast(this.transitiveConverters.get(ifaceType));
+ newConverters = new ArrayList<>();
+ if (converters != null) {
+ newConverters.addAll(converters);
+ }
+ newConverters.add(converter);
+ Collections.sort(newConverters, PRIORITY_COMPARATOR);
+ this.transitiveConverters.put(TypeLiteral.of(ifaceType), Collections.unmodifiableList(newConverters));
+ }
+ Class<?> superClass = targetType.getRawType().getSuperclass();
+ while(superClass!=null && !superClass.equals(Object.class)){
+ converters = List.class.cast(this.transitiveConverters.get(superClass));
+ newConverters = new ArrayList<>();
+ if (converters != null) {
+ newConverters.addAll(converters);
+ }
+ newConverters.add(converter);
+ Collections.sort(newConverters, PRIORITY_COMPARATOR);
+ this.transitiveConverters.put(TypeLiteral.of(superClass), Collections.unmodifiableList(newConverters));
+ for(Class<?> ifaceType: superClass.getInterfaces()){
+ converters = List.class.cast(this.transitiveConverters.get(ifaceType));
+ newConverters = new ArrayList<>();
+ if (converters != null) {
+ newConverters.addAll(converters);
+ }
+ newConverters.add(converter);
+ Collections.sort(newConverters, PRIORITY_COMPARATOR);
+ this.transitiveConverters.put(TypeLiteral.of(ifaceType), Collections.unmodifiableList(newConverters));
+ }
+ superClass = superClass.getSuperclass();
+ }
} finally {
writeLock.unlock();
}
@@ -104,14 +149,17 @@ public class PropertyConverterManager {
* @return true, if a converter for the given type is registered, or a default one can be created.
*/
public boolean isTargetTypeSupported(TypeLiteral<?> targetType) {
- return converters.containsKey(targetType)
- || createDefaultPropertyConverter(targetType) != null;
+ if(converters.containsKey(targetType) || transitiveConverters.containsKey(targetType)){
+ return true;
+ }
+ return createDefaultPropertyConverter(targetType) != null;
}
/**
* Get a map of all property converters currently registered. This will not contain the converters that
* may be created, when an instance is adapted, which provides a String constructor or compatible
- * factory methods taking a single String instance.
+ * factory methods taking a single String instance. <br/>
+ * This will also NOT contain any transitive converter mappings as derived from the registered converters.
*
* @return the current map of instantiated and registered converters.
* @see #createDefaultPropertyConverter(org.apache.tamaya.TypeLiteral)
@@ -129,7 +177,25 @@ public class PropertyConverterManager {
/**
* Get the list of all current registered converters for the given target type.
* If not converters are registered, they component tries to create and register a dynamic
- * converter based on String costructor or static factory methods available.
+ * converter based on String costructor or static factory methods available.<br/>
+ * The converters provided are of the following type and returned in the following order:
+ * <ul>
+ * <li>Converters mapped explicitly to the required target type are returned first, ordered
+ * by decreasing priority. This means, if explicit converters are registered these are used
+ * primarly for converting a value.</li>
+ * <li>The target type of each explicitly registered converter also can be transitively mapped to
+ * 1) all directly implemented interfaces, 2) all its superclasses (except Object), 3) all the interfaces
+ * implemented by its superclasses. These groups of transitive converters is returned similarly in the
+ * order as mentioned, whereas also here a priority based decreasing ordering is applied.</li>
+ * <li>java.lang wrapper classes and native types are automatically mapped.</li>
+ * <li>If no explicit converters are registered, for Enum types a default implementation is provided that
+ * compares the configuration values with the different enum members defined (cases sensitive mapping).</li>
+ * </ul>
+ *
+ * So given that list above directly registered mappings always are tried first, before any transitive mapping
+ * should be used. Also in all cases @Priority annotations are honored for ordering of the converters in place.
+ * Transitive conversion is supported for all directly implemented interfaces (including inherited ones) and
+ * the inheritance hierarchy (exception Object). Superinterfaces of implemented interfaces are ignored.
*
* @param targetType the target type, not null.
* @param <T> the type class
@@ -137,8 +203,10 @@ public class PropertyConverterManager {
* @see #createDefaultPropertyConverter(org.apache.tamaya.TypeLiteral)
*/
public <T> List<PropertyConverter<T>> getPropertyConverters(TypeLiteral<T> targetType) {
+ List<PropertyConverter<T>> converterList = new ArrayList<>();
Lock readLock = lock.asReadLock();
List<PropertyConverter<T>> converters;
+ // direct mapped converters
try {
readLock.lock();
converters = List.class.cast(this.converters.get(targetType));
@@ -146,8 +214,19 @@ public class PropertyConverterManager {
readLock.unlock();
}
if (converters != null) {
- return converters;
+ converterList.addAll(converters);
+ }
+ // transitive converter
+ try {
+ readLock.lock();
+ converters = List.class.cast(this.transitiveConverters.get(targetType));
+ } finally {
+ readLock.unlock();
+ }
+ if (converters != null) {
+ converterList.addAll(converters);
}
+ // handling of java.lang wrapper classes
TypeLiteral<T> boxedType = mapBoxedType(targetType);
if(boxedType!=null){
try {
@@ -157,23 +236,26 @@ public class PropertyConverterManager {
readLock.unlock();
}
if (converters != null) {
- return converters;
+ converterList.addAll(converters);
}
}
- PropertyConverter<T> defaultConverter = createDefaultPropertyConverter(targetType);
- if (defaultConverter != null) {
- register(targetType, defaultConverter);
- try {
- readLock.lock();
- converters = List.class.cast(this.converters.get(targetType));
- } finally {
- readLock.unlock();
+ if(converterList.isEmpty()) {
+ // adding any converters created on the fly, e.g. for enum types.
+ PropertyConverter<T> defaultConverter = createDefaultPropertyConverter(targetType);
+ if (defaultConverter != null) {
+ register(targetType, defaultConverter);
+ try {
+ readLock.lock();
+ converters = List.class.cast(this.converters.get(targetType));
+ } finally {
+ readLock.unlock();
+ }
+ }
+ if (converters != null) {
+ converterList.addAll(converters);
}
}
- if (converters != null) {
- return converters;
- }
- return Collections.emptyList();
+ return converterList;
}
/**
@@ -304,4 +386,5 @@ public class PropertyConverterManager {
return null;
}
+
}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/4d560984/java8/core/src/test/java/org/apache/tamaya/core/internal/A.java
----------------------------------------------------------------------
diff --git a/java8/core/src/test/java/org/apache/tamaya/core/internal/A.java b/java8/core/src/test/java/org/apache/tamaya/core/internal/A.java
new file mode 100644
index 0000000..aa77a5d
--- /dev/null
+++ b/java8/core/src/test/java/org/apache/tamaya/core/internal/A.java
@@ -0,0 +1,29 @@
+/*
+ * 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.core.internal;
+
+/**
+ * Test class for testing transitively evaluated property converters.
+ */
+public class A implements AutoCloseable{
+ @Override
+ public void close() throws Exception {
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/4d560984/java8/core/src/test/java/org/apache/tamaya/core/internal/B.java
----------------------------------------------------------------------
diff --git a/java8/core/src/test/java/org/apache/tamaya/core/internal/B.java b/java8/core/src/test/java/org/apache/tamaya/core/internal/B.java
new file mode 100644
index 0000000..31bafb6
--- /dev/null
+++ b/java8/core/src/test/java/org/apache/tamaya/core/internal/B.java
@@ -0,0 +1,29 @@
+/*
+ * 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.core.internal;
+
+/**
+ * Test class for testing transitively evaluated property converters.
+ */
+public class B extends A implements Runnable{
+ @Override
+ public void run() {
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/4d560984/java8/core/src/test/java/org/apache/tamaya/core/internal/C.java
----------------------------------------------------------------------
diff --git a/java8/core/src/test/java/org/apache/tamaya/core/internal/C.java b/java8/core/src/test/java/org/apache/tamaya/core/internal/C.java
new file mode 100644
index 0000000..aad1ef9
--- /dev/null
+++ b/java8/core/src/test/java/org/apache/tamaya/core/internal/C.java
@@ -0,0 +1,56 @@
+/*
+ * 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.core.internal;
+
+import java.io.IOException;
+import java.nio.CharBuffer;
+
+/**
+ * Test class for testing transitively evaluated property converters.
+ */
+public class C extends B implements Readable{
+
+ private String inValue;
+
+ public C(String inValue){
+ this.inValue = inValue;
+ }
+
+ @Override
+ public int read(CharBuffer cb) throws IOException {
+ return 0;
+ }
+
+ /**
+ * Returns the input value, set on creation. Used for test assertion.
+ * @return the in value.
+ */
+ public String getInValue() {
+ return inValue;
+ }
+
+ @Override
+ public String toString() {
+ return "C{" +
+ "inValue='" + inValue + '\'' +
+ '}';
+ }
+
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/4d560984/java8/core/src/test/java/org/apache/tamaya/core/internal/CTestConverter.java
----------------------------------------------------------------------
diff --git a/java8/core/src/test/java/org/apache/tamaya/core/internal/CTestConverter.java b/java8/core/src/test/java/org/apache/tamaya/core/internal/CTestConverter.java
new file mode 100644
index 0000000..62b8c9d
--- /dev/null
+++ b/java8/core/src/test/java/org/apache/tamaya/core/internal/CTestConverter.java
@@ -0,0 +1,31 @@
+/*
+ * 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.core.internal;
+
+import org.apache.tamaya.spi.PropertyConverter;
+
+/**
+ * Created by Anatole on 13.06.2015.
+ */
+public class CTestConverter implements PropertyConverter<C>{
+ @Override
+ public C convert(String value) {
+ return new C(value);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/4d560984/java8/core/src/test/java/org/apache/tamaya/core/internal/PropertyConverterManagerTest.java
----------------------------------------------------------------------
diff --git a/java8/core/src/test/java/org/apache/tamaya/core/internal/PropertyConverterManagerTest.java b/java8/core/src/test/java/org/apache/tamaya/core/internal/PropertyConverterManagerTest.java
index fb80e05..9b413aa 100644
--- a/java8/core/src/test/java/org/apache/tamaya/core/internal/PropertyConverterManagerTest.java
+++ b/java8/core/src/test/java/org/apache/tamaya/core/internal/PropertyConverterManagerTest.java
@@ -74,4 +74,89 @@ public class PropertyConverterManagerTest {
}
}
+
+ @Test
+ public void testDirectConverterMapping(){
+ PropertyConverterManager manager = new PropertyConverterManager();
+ List<PropertyConverter<C>> converters = manager.getPropertyConverters(TypeLiteral.of(C.class));
+ assertThat(converters, hasSize(1));
+
+ PropertyConverter<C> converter = converters.get(0);
+ C result = converter.convert("testDirectConverterMapping");
+
+ assertThat(result, notNullValue());
+ assertThat(result, instanceOf(C.class));
+ assertThat(((C)result).getInValue(), equalTo("testDirectConverterMapping"));
+ }
+
+ @Test
+ public void testDirectSuperclassConverterMapping(){
+ PropertyConverterManager manager = new PropertyConverterManager();
+ List<PropertyConverter<B>> converters = manager.getPropertyConverters(TypeLiteral.of(B.class));
+ assertThat(converters, hasSize(1));
+
+ PropertyConverter<B> converter = converters.get(0);
+ B result = converter.convert("testDirectSuperclassConverterMapping");
+
+ assertThat(result, notNullValue());
+ assertThat(result, instanceOf(C.class));
+ assertThat(((C)result).getInValue(), equalTo("testDirectSuperclassConverterMapping"));
+ }
+
+ @Test
+ public void testTransitiveSuperclassConverterMapping(){
+ PropertyConverterManager manager = new PropertyConverterManager();
+ List<PropertyConverter<A>> converters = manager.getPropertyConverters(TypeLiteral.of(A.class));
+ assertThat(converters, hasSize(1));
+
+ PropertyConverter<A> converter = converters.get(0);
+ A result = converter.convert("testTransitiveSuperclassConverterMapping");
+
+ assertThat(result, notNullValue());
+ assertThat(result, instanceOf(C.class));
+ assertThat(((C)result).getInValue(), equalTo("testTransitiveSuperclassConverterMapping"));
+ }
+
+ @Test
+ public void testDirectInterfaceMapping(){
+ PropertyConverterManager manager = new PropertyConverterManager();
+ List<PropertyConverter<Readable>> converters = manager.getPropertyConverters(TypeLiteral.of(Readable.class));
+ assertThat(converters, hasSize(1));
+
+ PropertyConverter<Readable> converter = converters.get(0);
+ Readable result = converter.convert("testDirectInterfaceMapping");
+
+ assertThat(result, notNullValue());
+ assertThat(result, instanceOf(C.class));
+ assertThat(((C)result).getInValue(), equalTo("testDirectInterfaceMapping"));
+ }
+
+ @Test
+ public void testTransitiveInterfaceMapping1(){
+ PropertyConverterManager manager = new PropertyConverterManager();
+ List<PropertyConverter<Runnable>> converters = manager.getPropertyConverters(TypeLiteral.of(Runnable.class));
+ assertThat(converters, hasSize(1));
+
+ PropertyConverter<Runnable> converter = converters.get(0);
+ Runnable result = converter.convert("testTransitiveInterfaceMapping1");
+
+ assertThat(result, notNullValue());
+ assertThat(result, instanceOf(C.class));
+ assertThat(((C)result).getInValue(), equalTo("testTransitiveInterfaceMapping1"));
+ }
+
+ @Test
+ public void testTransitiveInterfaceMapping2(){
+ PropertyConverterManager manager = new PropertyConverterManager();
+ List<PropertyConverter<AutoCloseable>> converters = manager.getPropertyConverters(TypeLiteral.of(AutoCloseable.class));
+ assertThat(converters, hasSize(1));
+
+ PropertyConverter<AutoCloseable> converter = converters.get(0);
+ AutoCloseable result = converter.convert("testTransitiveInterfaceMapping2");
+
+ assertThat(result, notNullValue());
+ assertThat(result, instanceOf(C.class));
+ assertThat(((C)result).getInValue(), equalTo("testTransitiveInterfaceMapping2"));
+ }
+
}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/4d560984/java8/core/src/test/resources/META-INF/services/org.apache.tamaya.spi.PropertyConverter
----------------------------------------------------------------------
diff --git a/java8/core/src/test/resources/META-INF/services/org.apache.tamaya.spi.PropertyConverter b/java8/core/src/test/resources/META-INF/services/org.apache.tamaya.spi.PropertyConverter
new file mode 100644
index 0000000..d039696
--- /dev/null
+++ b/java8/core/src/test/resources/META-INF/services/org.apache.tamaya.spi.PropertyConverter
@@ -0,0 +1,19 @@
+#
+# 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 current 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.
+#
+org.apache.tamaya.core.internal.CTestConverter
\ No newline at end of file