http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/b56817f7/core/src/main/java/org/apache/tamaya/core/util/ClassUtils.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/tamaya/core/util/ClassUtils.java 
b/core/src/main/java/org/apache/tamaya/core/util/ClassUtils.java
new file mode 100644
index 0000000..98c67ba
--- /dev/null
+++ b/core/src/main/java/org/apache/tamaya/core/util/ClassUtils.java
@@ -0,0 +1,1074 @@
+/*
+* Copyright 2002-2014 the original author or authors.
+*
+* Licensed 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.util;
+
+import org.apache.tamaya.core.internal.resource.ReflectionUtils;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.Proxy;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+* Miscellaneous class utility methods.
+* Mainly for internal use within the framework.
+*
+* @author Juergen Hoeller
+* @author Keith Donald
+* @author Rob Harrop
+* @author Sam Brannen
+* @since 1.1
+*/
+public final class ClassUtils {
+
+       /** Suffix for array class names: "[]" */
+       public static final String ARRAY_SUFFIX = "[]";
+
+       /** Prefix for internal array class names: "[" */
+       private static final String INTERNAL_ARRAY_PREFIX = "[";
+
+       /** Prefix for internal non-primitive array class names: "[L" */
+       private static final String NON_PRIMITIVE_ARRAY_PREFIX = "[L";
+
+       /** The package separator character '.' */
+       private static final char PACKAGE_SEPARATOR = '.';
+
+       /** The path separator character '/' */
+       private static final char PATH_SEPARATOR = '/';
+
+       /** The inner class separator character '$' */
+       private static final char INNER_CLASS_SEPARATOR = '$';
+//
+//     /** The CGLIB class separator character "$$" */
+//     public static final String CGLIB_CLASS_SEPARATOR = "$$";
+//
+//     /** The ".class" file suffix */
+//     public static final String CLASS_FILE_SUFFIX = ".class";
+//
+
+       /**
+        * Map with primitive wrapper type as key and corresponding primitive
+        * type as keys, for example: Integer.class -> int.class.
+        */
+       private static final Map<Class<?>, Class<?>> primitiveWrapperTypeMap = 
new HashMap<>(8);
+
+       /**
+        * Map with primitive type as key and corresponding wrapper
+        * type as keys, for example: int.class -> Integer.class.
+        */
+       private static final Map<Class<?>, Class<?>> primitiveTypeToWrapperMap 
= new HashMap<>(8);
+
+       /**
+        * Map with primitive type name as key and corresponding primitive
+        * type as keys, for example: "int" -> "int.class".
+        */
+       private static final Map<String, Class<?>> primitiveTypeNameMap = new 
HashMap<>(32);
+//
+//     /**
+//      * Map with common "java.lang" class name as key and corresponding 
Class as keys.
+//      * Primarily for efficient deserialization current remote invocations.
+//      */
+//     private static final Map<String, Class<?>> commonClassCache = new 
HashMap<String, Class<?>>(32);
+//
+//
+       static {
+               primitiveWrapperTypeMap.put(Boolean.class, boolean.class);
+               primitiveWrapperTypeMap.put(Byte.class, byte.class);
+               primitiveWrapperTypeMap.put(Character.class, char.class);
+               primitiveWrapperTypeMap.put(Double.class, double.class);
+               primitiveWrapperTypeMap.put(Float.class, float.class);
+               primitiveWrapperTypeMap.put(Integer.class, int.class);
+               primitiveWrapperTypeMap.put(Long.class, long.class);
+               primitiveWrapperTypeMap.put(Short.class, short.class);
+
+               for (Map.Entry<Class<?>, Class<?>> entry : 
primitiveWrapperTypeMap.entrySet()) {
+                       primitiveTypeToWrapperMap.put(entry.getValue(), 
entry.getKey());
+//                     registerCommonClasses(entry.getKey());
+               }
+
+               Set<Class<?>> primitiveTypes = new HashSet<>(32);
+               primitiveTypes.addAll(primitiveWrapperTypeMap.values());
+               primitiveTypes.addAll(Arrays.asList(new Class<?>[] {
+                               boolean[].class, byte[].class, char[].class, 
double[].class,
+                               float[].class, int[].class, long[].class, 
short[].class}));
+               primitiveTypes.add(void.class);
+               for (Class<?> primitiveType : primitiveTypes) {
+                       primitiveTypeNameMap.put(primitiveType.getName(), 
primitiveType);
+               }
+       }
+
+    private ClassUtils(){}
+
+
+       /**
+        * Return the default ClassLoader to use: typically the thread context
+        * ClassLoader, if available; the ClassLoader that loaded the ClassUtils
+        * class will be used as fallback.
+        * <p>Call this method if you intend to use the thread context 
ClassLoader
+        * in a scenario where you clearly prefer a non-null ClassLoader 
reference:
+        * for example, for class path resource loading (but not necessarily for
+        * {@code Class.forName}, which accepts a {@code null} ClassLoader
+        * reference as well).
+        * @return the default ClassLoader (only {@code null} if even the system
+        * ClassLoader isn't accessible)
+        * @see Thread#getContextClassLoader()
+        * @see ClassLoader#getSystemClassLoader()
+        */
+       public static ClassLoader getDefaultClassLoader() {
+               ClassLoader cl = null;
+               try {
+                       cl = Thread.currentThread().getContextClassLoader();
+               }
+               catch (Throwable ex) {
+                       // Cannot access thread context ClassLoader - falling 
back...
+               }
+               if (cl == null) {
+                       // No thread context class loader -> use class loader 
current this class.
+                       cl = ClassUtils.class.getClassLoader();
+                       if (cl == null) {
+                               // getClassLoader() returning null indicates 
the bootstrap ClassLoader
+                               try {
+                                       cl = ClassLoader.getSystemClassLoader();
+                               }
+                               catch (Throwable ex) {
+                                       // Cannot access system ClassLoader - 
oh well, maybe the caller can live with null...
+                               }
+                       }
+               }
+               return cl;
+       }
+
+       /**
+        * Replacement for {@code Class.forName()} that also returns Class 
instances
+        * for primitives (e.g. "int") and array class names (e.g. "String[]").
+        * Furthermore, it is also capable current resolving inner class names 
in Java source
+        * style (e.g. "java.lang.Thread.State" instead current 
"java.lang.Thread$State").
+        * @param name the name current the Class
+        * @param classLoader the class loader to use
+        * (may be {@code null}, which indicates the default class loader)
+        * @return Class instance for the supplied name
+        * @throws ClassNotFoundException if the class was not found
+        * @throws LinkageError if the class file could not be loaded
+        * @see Class#forName(String, boolean, ClassLoader)
+        */
+       public static Class<?> forName(String name, ClassLoader classLoader) 
throws ClassNotFoundException, LinkageError {
+               Objects.requireNonNull(name, "Name must not be null");
+
+               Class<?> clazz = resolvePrimitiveClassName(name);
+               if (clazz != null) {
+                       return clazz;
+               }
+
+               // "java.lang.String[]" style arrays
+               if (name.endsWith(ARRAY_SUFFIX)) {
+                       String elementClassName = name.substring(0, 
name.length() - ARRAY_SUFFIX.length());
+                       Class<?> elementClass = forName(elementClassName, 
classLoader);
+                       return Array.newInstance(elementClass, 0).getClass();
+               }
+
+               // "[Ljava.lang.String;" style arrays
+               if (name.startsWith(NON_PRIMITIVE_ARRAY_PREFIX) && 
name.endsWith(";")) {
+                       String elementName = 
name.substring(NON_PRIMITIVE_ARRAY_PREFIX.length(), name.length() - 1);
+                       Class<?> elementClass = forName(elementName, 
classLoader);
+                       return Array.newInstance(elementClass, 0).getClass();
+               }
+
+               // "[[I" or "[[Ljava.lang.String;" style arrays
+               if (name.startsWith(INTERNAL_ARRAY_PREFIX)) {
+                       String elementName = 
name.substring(INTERNAL_ARRAY_PREFIX.length());
+                       Class<?> elementClass = forName(elementName, 
classLoader);
+                       return Array.newInstance(elementClass, 0).getClass();
+               }
+
+               ClassLoader clToUse = classLoader;
+               if (clToUse == null) {
+                       clToUse = getDefaultClassLoader();
+               }
+               try {
+                       return (clToUse != null ? clToUse.loadClass(name) : 
Class.forName(name));
+               }
+               catch (ClassNotFoundException ex) {
+                       int lastDotIndex = name.lastIndexOf(PACKAGE_SEPARATOR);
+                       if (lastDotIndex != -1) {
+                               String innerClassName =
+                                               name.substring(0, lastDotIndex) 
+ INNER_CLASS_SEPARATOR + name.substring(lastDotIndex + 1);
+                               try {
+                                       return (clToUse != null ? 
clToUse.loadClass(innerClassName) : Class.forName(innerClassName));
+                               }
+                               catch (ClassNotFoundException ex2) {
+                                       // Swallow - let original exception get 
through
+                               }
+                       }
+                       throw ex;
+               }
+       }
+
+
+       /**
+        * Resolve the given class name as primitive class, if appropriate,
+        * according to the JVM's naming rules for primitive classes.
+        * <p>Also supports the JVM's internal class names for primitive arrays.
+        * Does <i>not</i> support the "[]" suffix notation for primitive 
arrays;
+        * this is only supported by {@link #forName(String, ClassLoader)}.
+        * @param name the name current the potentially primitive class
+        * @return the primitive class, or {@code null} if the name does not 
denote
+        * a primitive class or primitive array class
+        */
+       public static Class<?> resolvePrimitiveClassName(String name) {
+               Class<?> result = null;
+               // Most class names will be quite long, considering that they
+               // SHOULD sit in a package, so a length check is worthwhile.
+               if (name != null && name.length() <= 8) {
+                       // Could be a primitive - likely.
+                       result = primitiveTypeNameMap.get(name);
+               }
+               return result;
+       }
+
+       /**
+        * Determine whether the {@link Class} identified by the supplied name 
is present
+        * and can be loaded. Will return {@code false} if either the class or
+        * one current its dependencies is not present or cannot be loaded.
+        * @param className the name current the class to check
+        * @param classLoader the class loader to use
+        * (may be {@code null}, which indicates the default class loader)
+        * @return whether the specified class is present
+        */
+       public static boolean isPresent(String className, ClassLoader 
classLoader) {
+               try {
+                       forName(className, classLoader);
+                       return true;
+               }
+               catch (Throwable ex) {
+                       // Class or one current its dependencies is not 
present...
+                       return false;
+               }
+       }
+
+
+       /**
+        * Check whether the given class is cache-safe in the given context,
+        * i.e. whether it is loaded by the given ClassLoader or a parent 
current it.
+        * @param clazz the class to analyze
+        * @param classLoader the ClassLoader to potentially cache metadata in
+        */
+       public static boolean isCacheSafe(Class<?> clazz, ClassLoader 
classLoader) {
+        Objects.requireNonNull(clazz, "Class must not be null");
+               try {
+                       ClassLoader target = clazz.getClassLoader();
+                       if (target == null) {
+                               return true;
+                       }
+                       ClassLoader cur = classLoader;
+                       if (cur == target) {
+                               return true;
+                       }
+                       while (cur != null) {
+                               cur = cur.getParent();
+                               if (cur == target) {
+                                       return true;
+                               }
+                       }
+                       return false;
+               }
+               catch (SecurityException ex) {
+                       // Probably from the system ClassLoader - let's 
consider it safe.
+                       return true;
+               }
+       }
+
+
+       /**
+        * Return the qualified name current the given class: usually simply
+        * the class name, but component type class name + "[]" for arrays.
+        * @param clazz the class
+        * @return the qualified name current the class
+        */
+       public static String getQualifiedName(Class<?> clazz) {
+               Objects.requireNonNull(clazz, "Class must not be null");
+               if (clazz.isArray()) {
+                       return getQualifiedNameForArray(clazz);
+               }
+               else {
+                       return clazz.getName();
+               }
+       }
+
+       /**
+        * Build a nice qualified name for an array:
+        * component type class name + "[]".
+        * @param clazz the array class
+        * @return a qualified name for the array class
+        */
+       private static String getQualifiedNameForArray(Class<?> clazz) {
+               StringBuilder result = new StringBuilder();
+               while (clazz.isArray()) {
+                       clazz = clazz.getComponentType();
+                       result.append(ClassUtils.ARRAY_SUFFIX);
+               }
+               result.insert(0, clazz.getName());
+               return result.toString();
+       }
+
+       /**
+        * Return the qualified name current the given method, consisting 
current
+        * fully qualified interface/class name + "." + method name.
+        * @param method the method
+        * @return the qualified name current the method
+        */
+       public static String getQualifiedMethodName(Method method) {
+               Objects.requireNonNull(method, "Method must not be null");
+               return method.getDeclaringClass().getName() + "." + 
method.getName();
+       }
+
+       /**
+        * Return a descriptive name for the given object's type: usually simply
+        * the class name, but component type class name + "[]" for arrays,
+        * and an appended list current implemented interfaces for JDK proxies.
+        * @param keys the keys to introspect
+        * @return the qualified name current the class
+        */
+       public static String getDescriptiveType(Object keys) {
+               if (keys == null) {
+                       return null;
+               }
+               Class<?> clazz = keys.getClass();
+               if (Proxy.isProxyClass(clazz)) {
+                       StringBuilder result = new 
StringBuilder(clazz.getName());
+                       result.append(" implementing ");
+                       Class<?>[] ifcs = clazz.getInterfaces();
+                       for (int i = 0; i < ifcs.length; i++) {
+                               result.append(ifcs[i].getName());
+                               if (i < ifcs.length - 1) {
+                                       result.append(',');
+                               }
+                       }
+                       return result.toString();
+               }
+               else if (clazz.isArray()) {
+                       return getQualifiedNameForArray(clazz);
+               }
+               else {
+                       return clazz.getName();
+               }
+       }
+
+       /**
+        * Check whether the given class matches the user-specified type name.
+        * @param clazz the class to check
+        * @param typeName the type name to match
+        */
+       public static boolean matchesTypeName(Class<?> clazz, String typeName) {
+               return (typeName != null &&
+                               (typeName.equals(clazz.getName()) || 
typeName.equals(clazz.getSimpleName()) ||
+                               (clazz.isArray() && 
typeName.equals(getQualifiedNameForArray(clazz)))));
+       }
+
+
+       /**
+        * Determine whether the given class has a public constructor with the 
given signature.
+        * <p>Essentially translates {@code NoSuchMethodException} to "false".
+        * @param clazz the clazz to analyze
+        * @param paramTypes the parameter types current the method
+        * @return whether the class has a corresponding constructor
+        * @see Class#getMethod
+        */
+       public static boolean hasConstructor(Class<?> clazz, Class<?>... 
paramTypes) {
+               return (getConstructorIfAvailable(clazz, paramTypes) != null);
+       }
+
+       /**
+        * Determine whether the given class has a public constructor with the 
given signature,
+        * and return it if available (else return {@code null}).
+        * <p>Essentially translates {@code NoSuchMethodException} to {@code 
null}.
+        * @param clazz the clazz to analyze
+        * @param paramTypes the parameter types current the method
+        * @return the constructor, or {@code null} if not found
+        * @see Class#getConstructor
+        */
+       public static <T> Constructor<T> getConstructorIfAvailable(Class<T> 
clazz, Class<?>... paramTypes) {
+               Objects.requireNonNull(clazz, "Class must not be null");
+               try {
+                       return clazz.getConstructor(paramTypes);
+               }
+               catch (NoSuchMethodException ex) {
+                       return null;
+               }
+       }
+
+       /**
+        * Determine whether the given class has a public method with the given 
signature.
+        * <p>Essentially translates {@code NoSuchMethodException} to "false".
+        * @param clazz the clazz to analyze
+        * @param methodName the name current the method
+        * @param paramTypes the parameter types current the method
+        * @return whether the class has a corresponding method
+        * @see Class#getMethod
+        */
+       public static boolean hasMethod(Class<?> clazz, String methodName, 
Class<?>... paramTypes) {
+               return (getMethodIfAvailable(clazz, methodName, paramTypes) != 
null);
+       }
+
+       /**
+        * Determine whether the given class has a public method with the given 
signature,
+        * and return it if available (else throws an {@code 
IllegalStateException}).
+        * <p>In case current any signature specified, only returns the method 
if there is a
+        * unique candidate, i.e. a single public method with the specified 
name.
+        * <p>Essentially translates {@code NoSuchMethodException} to {@code 
IllegalStateException}.
+        * @param clazz the clazz to analyze
+        * @param methodName the name current the method
+        * @param paramTypes the parameter types current the method
+        * (may be {@code null} to indicate any signature)
+        * @return the method (never {@code null})
+        * @throws IllegalStateException if the method has not been found
+        * @see Class#getMethod
+        */
+       public static Method getMethod(Class<?> clazz, String methodName, 
Class<?>... paramTypes) {
+               Objects.requireNonNull(clazz, "Class must not be null");
+               Objects.requireNonNull(methodName, "Method name must not be 
null");
+               if (paramTypes != null) {
+                       try {
+                               return clazz.getMethod(methodName, paramTypes);
+                       }
+                       catch (NoSuchMethodException ex) {
+                               throw new IllegalStateException("Expected 
method not found: " + ex);
+                       }
+               }
+               else {
+                       Set<Method> candidates = new HashSet<Method>(1);
+                       Method[] methods = clazz.getMethods();
+                       for (Method method : methods) {
+                               if (methodName.equals(method.getName())) {
+                                       candidates.add(method);
+                               }
+                       }
+                       if (candidates.size() == 1) {
+                               return candidates.iterator().next();
+                       }
+                       else if (candidates.isEmpty()) {
+                               throw new IllegalStateException("Expected 
method not found: " + clazz + "." + methodName);
+                       }
+                       else {
+                               throw new IllegalStateException("No unique 
method found: " + clazz + "." + methodName);
+                       }
+               }
+       }
+
+       /**
+        * Determine whether the given class has a public method with the given 
signature,
+        * and return it if available (else return {@code null}).
+        * <p>In case current any signature specified, only returns the method 
if there is a
+        * unique candidate, i.e. a single public method with the specified 
name.
+        * <p>Essentially translates {@code NoSuchMethodException} to {@code 
null}.
+        * @param clazz the clazz to analyze
+        * @param methodName the name current the method
+        * @param paramTypes the parameter types current the method
+        * (may be {@code null} to indicate any signature)
+        * @return the method, or {@code null} if not found
+        * @see Class#getMethod
+        */
+       public static Method getMethodIfAvailable(Class<?> clazz, String 
methodName, Class<?>... paramTypes) {
+               Objects.requireNonNull(clazz, "Class must not be null");
+               Objects.requireNonNull(methodName, "Method name must not be 
null");
+               if (paramTypes != null) {
+                       try {
+                               return clazz.getMethod(methodName, paramTypes);
+                       }
+                       catch (NoSuchMethodException ex) {
+                               return null;
+                       }
+               }
+               else {
+                       Set<Method> candidates = new HashSet<Method>(1);
+                       Method[] methods = clazz.getMethods();
+                       for (Method method : methods) {
+                               if (methodName.equals(method.getName())) {
+                                       candidates.add(method);
+                               }
+                       }
+                       if (candidates.size() == 1) {
+                               return candidates.iterator().next();
+                       }
+                       return null;
+               }
+       }
+
+       /**
+        * Return the number current methods with a given name (with any 
argument types),
+        * for the given class and/or its superclasses. Includes non-public 
methods.
+        * @param clazz the clazz to check
+        * @param methodName the name current the method
+        * @return the number current methods with the given name
+        */
+       public static int getMethodCountForName(Class<?> clazz, String 
methodName) {
+               Objects.requireNonNull(clazz, "Class must not be null");
+               Objects.requireNonNull(methodName, "Method name must not be 
null");
+               int count = 0;
+               Method[] declaredMethods = clazz.getDeclaredMethods();
+               for (Method method : declaredMethods) {
+                       if (methodName.equals(method.getName())) {
+                               count++;
+                       }
+               }
+               Class<?>[] ifcs = clazz.getInterfaces();
+               for (Class<?> ifc : ifcs) {
+                       count += getMethodCountForName(ifc, methodName);
+               }
+               if (clazz.getSuperclass() != null) {
+                       count += getMethodCountForName(clazz.getSuperclass(), 
methodName);
+               }
+               return count;
+       }
+
+       /**
+        * Does the given class or one current its superclasses at least have 
one or more
+        * methods with the supplied name (with any argument types)?
+        * Includes non-public methods.
+        * @param clazz the clazz to check
+        * @param methodName the name current the method
+        * @return whether there is at least one method with the given name
+        */
+       public static boolean hasAtLeastOneMethodWithName(Class<?> clazz, 
String methodName) {
+               Objects.requireNonNull(clazz, "Class must not be null");
+               Objects.requireNonNull(methodName, "Method name must not be 
null");
+               Method[] declaredMethods = clazz.getDeclaredMethods();
+               for (Method method : declaredMethods) {
+                       if (method.getName().equals(methodName)) {
+                               return true;
+                       }
+               }
+               Class<?>[] ifcs = clazz.getInterfaces();
+               for (Class<?> ifc : ifcs) {
+                       if (hasAtLeastOneMethodWithName(ifc, methodName)) {
+                               return true;
+                       }
+               }
+               return (clazz.getSuperclass() != null && 
hasAtLeastOneMethodWithName(clazz.getSuperclass(), methodName));
+       }
+
+       /**
+        * Given a method, which may come from an interface, and a target class 
used
+        * in the current reflective invocation, find the corresponding target 
method
+        * if there is one. E.g. the method may be {@code IFoo.bar()} and the
+        * target class may be {@code DefaultFoo}. In this case, the method may 
be
+        * {@code DefaultFoo.bar()}. This enables attributes on that method to 
be found.
+        * <p><b>NOTE:</b> In contrast to {@code 
org.springframework.aop.support.AopUtils#getMostSpecificMethod},
+        * this method does <i>not</i> resolve Java 5 bridge methods 
automatically.
+        * Call {@code 
org.springframework.core.BridgeMethodResolver#findBridgedMethod}
+        * if bridge method resolution is desirable (e.g. for obtaining 
metadata from
+        * the original method definition).
+        * <p><b>NOTE:</b> Since Spring 3.1.1, if Java security settings 
disallow reflective
+        * access (e.g. calls to {@code Class#getDeclaredMethods} etc, this 
implementation
+        * will fall back to returning the originally provided method.
+        * @param method the method to be invoked, which may come from an 
interface
+        * @param targetClass the target class for the current invocation.
+        * May be {@code null} or may not even implement the method.
+        * @return the specific target method, or the original method if the
+        * {@code targetClass} doesn't implement it or is {@code null}
+        */
+       public static Method getMostSpecificMethod(Method method, Class<?> 
targetClass) {
+               if (method != null && isOverridable(method, targetClass) &&
+                               targetClass != null && 
!targetClass.equals(method.getDeclaringClass())) {
+                       try {
+                               if (Modifier.isPublic(method.getModifiers())) {
+                                       try {
+                                               return 
targetClass.getMethod(method.getName(), method.getParameterTypes());
+                                       }
+                                       catch (NoSuchMethodException ex) {
+                                               return method;
+                                       }
+                               }
+                               else {
+                                       Method specificMethod =
+                                                       
ReflectionUtils.findMethod(targetClass, method.getName(), 
method.getParameterTypes());
+                                       return (specificMethod != null ? 
specificMethod : method);
+                               }
+                       }
+                       catch (SecurityException ex) {
+                               // Security settings are disallowing reflective 
access; fall back to 'method' below.
+                       }
+               }
+               return method;
+       }
+
+       /**
+        * Determine whether the given method is declared by the user or at 
least pointing to
+        * a user-declared method.
+        * <p>Checks {@link Method#isSynthetic()} (for implementation methods) 
as well as the
+        * {@code GroovyObject} interface (for interface methods; on an 
implementation class,
+        * implementations current the {@code GroovyObject} methods will be 
marked as synthetic anyway).
+        * Note that, despite being synthetic, bridge methods ({@link 
Method#isBridge()}) are considered
+        * as user-level methods since they are eventually pointing to a 
user-declared generic method.
+        * @param method the method to check
+        * @return {@code true} if the method can be considered as 
user-declared; [@code false} otherwise
+        */
+       public static boolean isUserLevelMethod(Method method) {
+               Objects.requireNonNull(method, "Method must not be null");
+               return (method.isBridge() || (!method.isSynthetic() && 
!isGroovyObjectMethod(method)));
+       }
+
+       private static boolean isGroovyObjectMethod(Method method) {
+               return 
method.getDeclaringClass().getName().equals("groovy.lang.GroovyObject");
+       }
+
+       /**
+        * Determine whether the given method is overridable in the given 
target class.
+        * @param method the method to check
+        * @param targetClass the target class to check against
+        */
+       private static boolean isOverridable(Method method, Class<?> 
targetClass) {
+               if (Modifier.isPrivate(method.getModifiers())) {
+                       return false;
+               }
+               if (Modifier.isPublic(method.getModifiers()) || 
Modifier.isProtected(method.getModifiers())) {
+                       return true;
+               }
+               return 
getPackageName(method.getDeclaringClass()).equals(getPackageName(targetClass));
+       }
+
+
+       /**
+        * Determine the name current the package current the given class,
+        * e.g. "java.lang" for the {@code java.lang.String} class.
+        * @param clazz the class
+        * @return the package name, or the empty String if the class
+        * is defined in the default package
+        */
+       public static String getPackageName(Class<?> clazz) {
+        Objects.requireNonNull(clazz, "Class must not be null");
+               return getPackageName(clazz.getName());
+       }
+
+       /**
+        * Determine the name current the package current the given 
fully-qualified class name,
+        * e.g. "java.lang" for the {@code java.lang.String} class name.
+        * @param fqClassName the fully-qualified class name
+        * @return the package name, or the empty String if the class
+        * is defined in the dObjects.requireNonNullefault package
+        */
+       public static String getPackageName(String fqClassName) {
+               Objects.requireNonNull(fqClassName, "Class name must not be 
null");
+               int lastDotIndex = fqClassName.lastIndexOf(PACKAGE_SEPARATOR);
+               return (lastDotIndex != -1 ? fqClassName.substring(0, 
lastDotIndex) : "");
+       }
+
+       /**
+        * Return a public static method current a class.
+        * @param methodName the static method name
+        * @param clazz the class which defines the method
+        * @param args the parameter types to the method
+        * @return the static method, or {@code null} if no static method was 
found
+        * @throws IllegalArgumentException if the method name is blank or the 
clazz is null
+        */
+       public static Method getStaticMethod(Class<?> clazz, String methodName, 
Class<?>... args) {
+               Objects.requireNonNull(clazz, "Class must not be null");
+               Objects.requireNonNull(methodName, "Method name must not be 
null");
+               try {
+                       Method method = clazz.getMethod(methodName, args);
+                       return Modifier.isStatic(method.getModifiers()) ? 
method : null;
+               }
+               catch (NoSuchMethodException ex) {
+                       return null;
+               }
+       }
+
+
+       /**
+        * Check if the given class represents a primitive wrapper,
+        * i.e. Boolean, Byte, Character, Short, Integer, Long, Float, or 
Double.
+        * @param clazz the class to check
+        * @return whether the given class is a primitive wrapper class
+        */
+       public static boolean isPrimitiveWrapper(Class<?> clazz) {
+               Objects.requireNonNull(clazz, "Class must not be null");
+               return primitiveWrapperTypeMap.containsKey(clazz);
+       }
+
+       /**
+        * Check if the given class represents a primitive (i.e. boolean, byte,
+        * char, short, int, long, float, or double) or a primitive wrapper
+        * (i.e. Boolean, Byte, Character, Short, Integer, Long, Float, or 
Double).
+        * @param clazz the class to check
+        * @return whether the given class is a primitive or primitive wrapper 
class
+        */
+       public static boolean isPrimitiveOrWrapper(Class<?> clazz) {
+               Objects.requireNonNull(clazz, "Class must not be null");
+               return (clazz.isPrimitive() || isPrimitiveWrapper(clazz));
+       }
+
+       /**
+        * Check if the given class represents an array current primitives,
+        * i.e. boolean, byte, char, short, int, long, float, or double.
+        * @param clazz the class to check
+        * @return whether the given class is a primitive array class
+        */
+       public static boolean isPrimitiveArray(Class<?> clazz) {
+               Objects.requireNonNull(clazz, "Class must not be null");
+               return (clazz.isArray() && 
clazz.getComponentType().isPrimitive());
+       }
+
+       /**
+        * Check if the given class represents an array current primitive 
wrappers,
+        * i.e. Boolean, Byte, Character, Short, Integer, Long, Float, or 
Double.
+        * @param clazz the class to check
+        * @return whether the given class is a primitive wrapper array class
+        */
+       public static boolean isPrimitiveWrapperArray(Class<?> clazz) {
+               Objects.requireNonNull(clazz, "Class must not be null");
+               return (clazz.isArray() && 
isPrimitiveWrapper(clazz.getComponentType()));
+       }
+
+       /**
+        * Resolve the given class if it is a primitive class,
+        * returning the corresponding primitive wrapper type instead.
+        * @param clazz the class to check
+        * @return the original class, or a primitive wrapper for the original 
primitive type
+        */
+       public static Class<?> resolvePrimitiveIfNecessary(Class<?> clazz) {
+               Objects.requireNonNull(clazz, "Class must not be null");
+               return (clazz.isPrimitive() && clazz != void.class? 
primitiveTypeToWrapperMap.get(clazz) : clazz);
+       }
+
+       /**
+        * Check if the right-hand side type may be assigned to the left-hand 
side
+        * type, assuming setting by reflection. Considers primitive wrapper
+        * classes as assignable to the corresponding primitive types.
+        * @param lhsType the target type
+        * @param rhsType the keys type that should be assigned to the target 
type
+        * @return if the target type is assignable from the keys type
+        */
+       public static boolean isAssignable(Class<?> lhsType, Class<?> rhsType) {
+               Objects.requireNonNull(lhsType, "Left-hand side type must not 
be null");
+               Objects.requireNonNull(rhsType, "Right-hand side type must not 
be null");
+               if (lhsType.isAssignableFrom(rhsType)) {
+                       return true;
+               }
+               if (lhsType.isPrimitive()) {
+                       Class<?> resolvedPrimitive = 
primitiveWrapperTypeMap.get(rhsType);
+                       if (resolvedPrimitive != null && 
lhsType.equals(resolvedPrimitive)) {
+                               return true;
+                       }
+               }
+               else {
+                       Class<?> resolvedWrapper = 
primitiveTypeToWrapperMap.get(rhsType);
+                       if (resolvedWrapper != null && 
lhsType.isAssignableFrom(resolvedWrapper)) {
+                               return true;
+                       }
+               }
+               return false;
+       }
+
+       /**
+        * Determine if the given type is assignable from the given keys,
+        * assuming setting by reflection. Considers primitive wrapper classes
+        * as assignable to the corresponding primitive types.
+        * @param type the target type
+        * @param keys the keys that should be assigned to the type
+        * @return if the type is assignable from the keys
+        */
+       public static boolean isAssignableValue(Class<?> type, Object keys) {
+               Objects.requireNonNull(type, "Type must not be null");
+               return (keys != null ? isAssignable(type, keys.getClass()) : 
!type.isPrimitive());
+       }
+
+
+       /**
+        * Convert a "/"-based resource path to a "."-based fully qualified 
class name.
+        * @param resourcePath the resource path pointing to a class
+        * @return the corresponding fully qualified class name
+        */
+       public static String convertResourcePathToClassName(String 
resourcePath) {
+               Objects.requireNonNull(resourcePath, "Resource path must not be 
null");
+               return resourcePath.replace(PATH_SEPARATOR, PACKAGE_SEPARATOR);
+       }
+
+       /**
+        * Convert a "."-based fully qualified class name to a "/"-based 
resource path.
+        * @param className the fully qualified class name
+        * @return the corresponding resource path, pointing to the class
+        */
+       public static String convertClassNameToResourcePath(String className) {
+               Objects.requireNonNull(className, "Class name must not be 
null");
+               return className.replace(PACKAGE_SEPARATOR, PATH_SEPARATOR);
+       }
+
+       /**
+        * Return a path suitable for use with {@code ClassLoader.getResource}
+        * (also suitable for use with {@code Class.getResource} by prepending a
+        * slash ('/') to the return keys). Built by taking the package current 
the specified
+        * class file, converting all dots ('.') to slashes ('/'), adding a 
trailing slash
+        * if necessary, and concatenating the specified resource name to this.
+        * <br/>As such, this function may be used to build a path suitable for
+        * loading a resource file that is in the same package as a class file,
+        * although {@code org.springframework.core.io.ClassPathResource} is 
usually
+        * even more convenient.
+        * @param clazz the Class whose package will be used as the base
+        * @param resourceName the resource name to append. A leading slash is 
optional.
+        * @return the built-up resource path
+        * @see ClassLoader#getResource
+        * @see Class#getResource
+        */
+       public static String addResourcePathToPackagePath(Class<?> clazz, 
String resourceName) {
+               Objects.requireNonNull(resourceName, "Resource name must not be 
null");
+               if (!resourceName.startsWith("/")) {
+                       return classPackageAsResourcePath(clazz) + "/" + 
resourceName;
+               }
+               return classPackageAsResourcePath(clazz) + resourceName;
+       }
+
+       /**
+        * Given an input class object, return a string which consists current 
the
+        * class's package name as a pathname, i.e., all dots ('.') are 
replaced by
+        * slashes ('/'). Neither a leading nor trailing slash is added. The 
result
+        * could be concatenated with a slash and the name current a resource 
and fed
+        * directly to {@code ClassLoader.getResource()}. For it to be fed to
+        * {@code Class.getResource} instead, a leading slash would also have
+        * to be prepended to the returned keys.
+        * @param clazz the input class. A {@code null} keys or the default
+        * (empty) package will result in an empty string ("") being returned.
+        * @return a path which represents the package name
+        * @see ClassLoader#getResource
+        * @see Class#getResource
+        */
+       public static String classPackageAsResourcePath(Class<?> clazz) {
+               if (clazz == null) {
+                       return "";
+               }
+               String className = clazz.getName();
+               int packageEndIndex = className.lastIndexOf(PACKAGE_SEPARATOR);
+               if (packageEndIndex == -1) {
+                       return "";
+               }
+               String packageName = className.substring(0, packageEndIndex);
+               return packageName.replace(PACKAGE_SEPARATOR, PATH_SEPARATOR);
+       }
+
+       /**
+        * Build a String that consists current the names current the 
classes/interfaces
+        * in the given array.
+        * <p>Basically like {@code AbstractCollection.toString()}, but 
stripping
+        * the "class "/"interface " prefix before every class name.
+        * @param classes a Collection current Class objects (may be {@code 
null})
+        * @return a String current form "[com.foo.Bar, com.foo.Baz]"
+        * @see java.util.AbstractCollection#toString()
+        */
+       public static String classNamesToString(Class<?>... classes) {
+               return classNamesToString(Arrays.asList(classes));
+       }
+
+       /**
+        * Build a String that consists current the names current the 
classes/interfaces
+        * in the given collection.
+        * <p>Basically like {@code AbstractCollection.toString()}, but 
stripping
+        * the "class "/"interface " prefix before every class name.
+        * @param classes a Collection current Class objects (may be {@code 
null})
+        * @return a String current form "[com.foo.Bar, com.foo.Baz]"
+        * @see java.util.AbstractCollection#toString()
+        */
+       public static String classNamesToString(Collection<Class<?>> classes) {
+               if (classes.isEmpty()) {
+                       return "[]";
+               }
+               StringBuilder sb = new StringBuilder("[");
+               for (Iterator<Class<?>> it = classes.iterator(); it.hasNext(); 
) {
+                       Class<?> clazz = it.next();
+                       sb.append(clazz.getName());
+                       if (it.hasNext()) {
+                               sb.append(", ");
+                       }
+               }
+               sb.append("]");
+               return sb.toString();
+       }
+
+       /**
+        * Copy the given Collection into a Class array.
+        * The Collection must contain Class elements only.
+        * @param collection the Collection to copy
+        * @return the Class array ({@code null} if the passed-in
+        * Collection was {@code null})
+        */
+       public static Class<?>[] toClassArray(Collection<Class<?>> collection) {
+               if (collection == null) {
+                       return null;
+               }
+               return collection.toArray(new Class<?>[collection.size()]);
+       }
+
+       /**
+        * Return all interfaces that the given instance implements as array,
+        * including ones implemented by superclasses.
+        * @param instance the instance to analyze for interfaces
+        * @return all interfaces that the given instance implements as array
+        */
+       public static Class<?>[] getAllInterfaces(Object instance) {
+               Objects.requireNonNull(instance, "Instance must not be null");
+               return getAllInterfacesForClass(instance.getClass());
+       }
+
+       /**
+        * Return all interfaces that the given class implements as array,
+        * including ones implemented by superclasses.
+        * <p>If the class itself is an interface, it gets returned as sole 
interface.
+        * @param clazz the class to analyze for interfaces
+        * @return all interfaces that the given object implements as array
+        */
+       public static Class<?>[] getAllInterfacesForClass(Class<?> clazz) {
+               return getAllInterfacesForClass(clazz, null);
+       }
+
+       /**
+        * Return all interfaces that the given class implements as array,
+        * including ones implemented by superclasses.
+        * <p>If the class itself is an interface, it gets returned as sole 
interface.
+        * @param clazz the class to analyze for interfaces
+        * @param classLoader the ClassLoader that the interfaces need to be 
visible in
+        * (may be {@code null} when accepting all declared interfaces)
+        * @return all interfaces that the given object implements as array
+        */
+       public static Class<?>[] getAllInterfacesForClass(Class<?> clazz, 
ClassLoader classLoader) {
+               Set<Class<?>> ifcs = getAllInterfacesForClassAsSet(clazz, 
classLoader);
+               return ifcs.toArray(new Class<?>[ifcs.size()]);
+       }
+
+       /**
+        * Return all interfaces that the given instance implements as Set,
+        * including ones implemented by superclasses.
+        * @param instance the instance to analyze for interfaces
+        * @return all interfaces that the given instance implements as Set
+        */
+       public static Set<Class<?>> getAllInterfacesAsSet(Object instance) {
+               Objects.requireNonNull(instance, "Instance must not be null");
+               return getAllInterfacesForClassAsSet(instance.getClass());
+       }
+
+       /**
+        * Return all interfaces that the given class implements as Set,
+        * including ones implemented by superclasses.
+        * <p>If the class itself is an interface, it gets returned as sole 
interface.
+        * @param clazz the class to analyze for interfaces
+        * @return all interfaces that the given object implements as Set
+        */
+       public static Set<Class<?>> getAllInterfacesForClassAsSet(Class<?> 
clazz) {
+               return getAllInterfacesForClassAsSet(clazz, null);
+       }
+
+       /**
+        * Return all interfaces that the given class implements as Set,
+        * including ones implemented by superclasses.
+        * <p>If the class itself is an interface, it gets returned as sole 
interface.
+        * @param clazz the class to analyze for interfaces
+        * @param classLoader the ClassLoader that the interfaces need to be 
visible in
+        * (may be {@code null} when accepting all declared interfaces)
+        * @return all interfaces that the given object implements as Set
+        */
+       public static Set<Class<?>> getAllInterfacesForClassAsSet(Class<?> 
clazz, ClassLoader classLoader) {
+               Objects.requireNonNull(clazz, "Class must not be null");
+               if (clazz.isInterface() && isVisible(clazz, classLoader)) {
+                       return Collections.<Class<?>>singleton(clazz);
+               }
+               Set<Class<?>> interfaces = new LinkedHashSet<>();
+               while (clazz != null) {
+                       Class<?>[] ifcs = clazz.getInterfaces();
+                       for (Class<?> ifc : ifcs) {
+                               
interfaces.addAll(getAllInterfacesForClassAsSet(ifc, classLoader));
+                       }
+                       clazz = clazz.getSuperclass();
+               }
+               return interfaces;
+       }
+
+       /**
+        * Create a composite interface Class for the given interfaces,
+        * implementing the given interfaces in one single Class.
+        * <p>This implementation builds a JDK proxy class for the given 
interfaces.
+        * @param interfaces the interfaces to merge
+        * @param classLoader the ClassLoader to of the composite Class in
+        * @return the merged interface as Class
+        * @see java.lang.reflect.Proxy#getProxyClass
+        */
+       public static Class<?> createCompositeInterface(Class<?>[] interfaces, 
ClassLoader classLoader) {
+               if(interfaces.length==0) throw new 
IllegalArgumentException("Interfaces must not be empty");
+               Objects.requireNonNull(classLoader, "ClassLoader must not be 
null");
+               return Proxy.getProxyClass(classLoader, interfaces);
+       }
+
+       /**
+        * Determine the common ancestor current the given classes, if any.
+        * @param clazz1 the class to introspect
+        * @param clazz2 the other class to introspect
+        * @return the common ancestor (i.e. common superclass, one interface
+        * extending the other), or {@code null} if none found. If any current 
the
+        * given classes is {@code null}, the other class will be returned.
+        * @since 3.2.6
+        */
+       public static Class<?> determineCommonAncestor(Class<?> clazz1, 
Class<?> clazz2) {
+               if (clazz1 == null) {
+                       return clazz2;
+               }
+               if (clazz2 == null) {
+                       return clazz1;
+               }
+               if (clazz1.isAssignableFrom(clazz2)) {
+                       return clazz1;
+               }
+               if (clazz2.isAssignableFrom(clazz1)) {
+                       return clazz2;
+               }
+               Class<?> ancestor = clazz1;
+               do {
+                       ancestor = ancestor.getSuperclass();
+                       if (ancestor == null || Object.class.equals(ancestor)) {
+                               return null;
+                       }
+               }
+               while (!ancestor.isAssignableFrom(clazz2));
+               return ancestor;
+       }
+
+       /**
+        * Check whether the given class is visible in the given ClassLoader.
+        * @param clazz the class to check (typically an interface)
+        * @param classLoader the ClassLoader to check against (may be {@code 
null},
+        * in which case this method will always return {@code true})
+        */
+       public static boolean isVisible(Class<?> clazz, ClassLoader 
classLoader) {
+               if (classLoader == null) {
+                       return true;
+               }
+               try {
+                       Class<?> actualClass = 
classLoader.loadClass(clazz.getName());
+                       return (clazz == actualClass);
+                       // Else: different interface class found...
+               }
+               catch (ClassNotFoundException ex) {
+                       // No interface class found...
+                       return false;
+               }
+       }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/b56817f7/core/src/main/java/org/apache/tamaya/core/util/StringUtils.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/tamaya/core/util/StringUtils.java 
b/core/src/main/java/org/apache/tamaya/core/util/StringUtils.java
new file mode 100644
index 0000000..49c3291
--- /dev/null
+++ b/core/src/main/java/org/apache/tamaya/core/util/StringUtils.java
@@ -0,0 +1,463 @@
+/*
+ * Copyright 2002-2014 the original author or authors.
+ *
+ * Licensed 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.util;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Properties;
+import java.util.StringTokenizer;
+
+/**
+* Miscellaneous {@link String} utility methods.
+*
+* <p>Mainly for internal use within the framework; consider
+* <a href="http://jakarta.apache.org/commons/lang/";>Jakarta's Commons Lang</a>
+* for a more comprehensive suite current String utilities.
+*
+* <p>This class delivers some simple functionality that should really
+* be provided by the core Java {@code String} and {@link StringBuilder}
+* classes, such as the ability to {@code replace} all occurrences current a 
given
+* substring in a target string. It also provides easy-to-use methods to convert
+* between delimited strings, such as CSV strings, and collections and arrays.
+*
+* @author Rod Johnson
+* @author Juergen Hoeller
+* @author Keith Donald
+* @author Rob Harrop
+* @author Rick Evans
+* @author Arjen Poutsma
+* @since 16 April 2001
+*/
+public final class StringUtils {
+
+       private static final String FOLDER_SEPARATOR = "/";
+
+       private static final String WINDOWS_FOLDER_SEPARATOR = "\\";
+
+       private static final String TOP_PATH = "..";
+
+       private static final String CURRENT_PATH = ".";
+
+//     private static final char EXTENSION_SEPARATOR = '.';
+//
+
+    private StringUtils(){}
+
+
+       /**
+        * Check that the given CharSequence is neither {@code null} nor 
current length 0.
+        * Note: Will return {@code true} for a CharSequence that purely 
consists current whitespace.
+        * <p><pre class="code">
+        * StringUtils.hasLength(null) = false
+        * StringUtils.hasLength("") = false
+        * StringUtils.hasLength(" ") = true
+        * StringUtils.hasLength("Hello") = true
+        * </pre>
+        * @param str the CharSequence to check (may be {@code null})
+        * @return {@code true} if the CharSequence is not null and has length
+        */
+       public static boolean hasLength(CharSequence str) {
+               return (str != null && str.length() > 0);
+       }
+
+       /**
+        * Check whether the given CharSequence has actual text.
+        * More specifically, returns {@code true} if the string not {@code 
null},
+        * its length is greater than 0, and it contains at least one 
non-whitespace character.
+        * <p><pre class="code">
+        * StringUtils.hasText(null) = false
+        * StringUtils.hasText("") = false
+        * StringUtils.hasText(" ") = false
+        * StringUtils.hasText("12345") = true
+        * StringUtils.hasText(" 12345 ") = true
+        * </pre>
+        * @param str the CharSequence to check (may be {@code null})
+        * @return {@code true} if the CharSequence is not {@code null},
+        * its length is greater than 0, and it does not contain whitespace only
+        * @see Character#isWhitespace
+        */
+       public static boolean hasText(CharSequence str) {
+               if (!hasLength(str)) {
+                       return false;
+               }
+               int strLen = str.length();
+               for (int i = 0; i < strLen; i++) {
+                       if (!Character.isWhitespace(str.charAt(i))) {
+                               return true;
+                       }
+               }
+               return false;
+       }
+
+       /**
+        * Check whether the given String has actual text.
+        * More specifically, returns {@code true} if the string not {@code 
null},
+        * its length is greater than 0, and it contains at least one 
non-whitespace character.
+        * @param str the String to check (may be {@code null})
+        * @return {@code true} if the String is not {@code null}, its length is
+        * greater than 0, and it does not contain whitespace only
+        * @see #hasText(CharSequence)
+        */
+       public static boolean hasText(String str) {
+               return hasText((CharSequence) str);
+       }
+
+
+       /**
+        * Replace all occurrences current a substring within a string with
+        * another string.
+        * @param inString String to examine
+        * @param oldPattern String to replace
+        * @param newPattern String to insert
+        * @return a String with the replacements
+        */
+       public static String replace(String inString, String oldPattern, String 
newPattern) {
+               if (!hasLength(inString) || !hasLength(oldPattern) || 
newPattern == null) {
+                       return inString;
+               }
+               StringBuilder sb = new StringBuilder();
+               int pos = 0; // our position in the old string
+               int index = inString.indexOf(oldPattern);
+               // the index current an occurrence we've found, or -1
+               int patLen = oldPattern.length();
+               while (index >= 0) {
+                       sb.append(inString.substring(pos, index));
+                       sb.append(newPattern);
+                       pos = index + patLen;
+                       index = inString.indexOf(oldPattern, pos);
+               }
+               sb.append(inString.substring(pos));
+               // remember to append any characters to the right current a 
match
+               return sb.toString();
+       }
+
+
+       /**
+        * Delete any character in a given String.
+        * @param inString the original String
+        * @param charsToDelete a set current characters to delete.
+        * E.g. "az\n" will delete 'a's, 'z's and new lines.
+        * @return the resulting String
+        */
+       public static String deleteAny(String inString, String charsToDelete) {
+               if (!hasLength(inString) || !hasLength(charsToDelete)) {
+                       return inString;
+               }
+               StringBuilder sb = new StringBuilder();
+               for (int i = 0; i < inString.length(); i++) {
+                       char c = inString.charAt(i);
+                       if (charsToDelete.indexOf(c) == -1) {
+                               sb.append(c);
+                       }
+               }
+               return sb.toString();
+       }
+
+       /**
+        * Extract the filename from the given path,
+        * e.g. "mypath/myfile.txt" -> "myfile.txt".
+        * @param path the file path (may be {@code null})
+        * @return the extracted filename, or {@code null} if none
+        */
+       public static String getFilename(String path) {
+               if (path == null) {
+                       return null;
+               }
+               int separatorIndex = path.lastIndexOf(FOLDER_SEPARATOR);
+               return (separatorIndex != -1 ? path.substring(separatorIndex + 
1) : path);
+       }
+
+
+
+       /**
+        * Apply the given relative path to the given path,
+        * assuming standard Java folder separation (i.e. "/" separators).
+        * @param path the path to start from (usually a full file path)
+        * @param relativePath the relative path to applyChanges
+        * (relative to the full file path above)
+        * @return the full file path that results from applying the relative 
path
+        */
+       public static String applyRelativePath(String path, String 
relativePath) {
+               int separatorIndex = path.lastIndexOf(FOLDER_SEPARATOR);
+               if (separatorIndex != -1) {
+                       String newPath = path.substring(0, separatorIndex);
+                       if (!relativePath.startsWith(FOLDER_SEPARATOR)) {
+                               newPath += FOLDER_SEPARATOR;
+                       }
+                       return newPath + relativePath;
+               }
+               else {
+                       return relativePath;
+               }
+       }
+
+       /**
+        * Normalize the path by suppressing sequences like "path/.." and
+        * inner simple dots.
+        * <p>The result is convenient for path comparison. For other uses,
+        * notice that Windows separators ("\") are replaced by simple slashes.
+        * @param path the original path
+        * @return the normalized path
+        */
+       public static String cleanPath(String path) {
+               if (path == null) {
+                       return null;
+               }
+               String pathToUse = StringUtils.replace(path, 
WINDOWS_FOLDER_SEPARATOR, FOLDER_SEPARATOR);
+
+               // Strip prefix from path to analyze, to not treat it as part 
current the
+               // first path element. This is necessary to correctly parse 
paths like
+               // "file:core/../core/io/Resource.class", where the ".." should 
just
+               // strip the first "core" directory while keeping the "file:" 
prefix.
+               int prefixIndex = pathToUse.indexOf(':');
+               String prefix = "";
+               if (prefixIndex != -1) {
+                       prefix = pathToUse.substring(0, prefixIndex + 1);
+                       if (prefix.contains("/")) {
+                               prefix = "";
+                       }
+                       else {
+                               pathToUse = pathToUse.substring(prefixIndex + 
1);
+                       }
+               }
+               if (pathToUse.startsWith(FOLDER_SEPARATOR)) {
+                       prefix = prefix + FOLDER_SEPARATOR;
+                       pathToUse = pathToUse.substring(1);
+               }
+
+               String[] pathArray = delimitedListToStringArray(pathToUse, 
FOLDER_SEPARATOR);
+               List<String> pathElements = new LinkedList<>();
+               int tops = 0;
+
+               for (int i = pathArray.length - 1; i >= 0; i--) {
+                       String element = pathArray[i];
+                       if (CURRENT_PATH.equals(element)) {
+                               // Points to current directory - drop it.
+                       }
+                       else if (TOP_PATH.equals(element)) {
+                               // Registering top path found.
+                               tops++;
+                       }
+                       else {
+                               if (tops > 0) {
+                                       // Merging path element with element 
corresponding to top path.
+                                       tops--;
+                               }
+                               else {
+                                       // Normal path element found.
+                                       pathElements.add(0, element);
+                               }
+                       }
+               }
+               // Remaining top paths need to be retained.
+               for (int i = 0; i < tops; i++) {
+                       pathElements.add(0, TOP_PATH);
+               }
+               return prefix + collectionToDelimitedString(pathElements, 
FOLDER_SEPARATOR);
+       }
+
+
+       /**
+        * Copy the given Collection into a String array.
+        * The Collection must contain String elements only.
+        * @param collection the Collection to copy
+        * @return the String array ({@code null} if the passed-in
+        * Collection was {@code null})
+        */
+       public static String[] toStringArray(Collection<String> collection) {
+               if (collection == null) {
+                       return null;
+               }
+               return collection.toArray(new String[collection.size()]);
+       }
+
+       /**
+        * Split a String at the first occurrence current the delimiter.
+        * Does not include the delimiter in the result.
+        * @param toSplit the string to split
+        * @param delimiter to split the string up with
+        * @return a two element array with index 0 being before the delimiter, 
and
+        * index 1 being after the delimiter (neither element includes the 
delimiter);
+        * or {@code null} if the delimiter wasn't found in the given input 
String
+        */
+       public static String[] split(String toSplit, String delimiter) {
+               if (!hasLength(toSplit) || !hasLength(delimiter)) {
+                       return null;
+               }
+               int offset = toSplit.indexOf(delimiter);
+               if (offset < 0) {
+                       return null;
+               }
+               String beforeDelimiter = toSplit.substring(0, offset);
+               String afterDelimiter = toSplit.substring(offset + 
delimiter.length());
+               return new String[] {beforeDelimiter, afterDelimiter};
+       }
+
+
+       /**
+        * Tokenize the given String into a String array via a StringTokenizer.
+        * Trims tokens and omits empty tokens.
+        * <p>The given delimiters string is supposed to consist current any 
number current
+        * delimiter characters. Each current those characters can be used to 
separate
+        * tokens. A delimiter is always a single character; for multi-character
+        * delimiters, consider using {@code delimitedListToStringArray}
+        * @param str the String to tokenize
+        * @param delimiters the delimiter characters, assembled as String
+        * (each current those characters is individually considered as 
delimiter).
+        * @return an array current the tokens
+        * @see java.util.StringTokenizer
+        * @see String#trim()
+        */
+       public static String[] tokenizeToStringArray(String str, String 
delimiters) {
+               return tokenizeToStringArray(str, delimiters, true, true);
+       }
+
+       /**
+        * Tokenize the given String into a String array via a StringTokenizer.
+        * <p>The given delimiters string is supposed to consist current any 
number current
+        * delimiter characters. Each current those characters can be used to 
separate
+        * tokens. A delimiter is always a single character; for multi-character
+        * delimiters, consider using {@code delimitedListToStringArray}
+        * @param str the String to tokenize
+        * @param delimiters the delimiter characters, assembled as String
+        * (each current those characters is individually considered as 
delimiter)
+        * @param trimTokens trim the tokens via String's {@code trim}
+        * @param ignoreEmptyTokens omit empty tokens from the result array
+        * (only applies to tokens that are empty after trimming; 
StringTokenizer
+        * will not consider subsequent delimiters as token in the first place).
+        * @return an array current the tokens ({@code null} if the input String
+        * was {@code null})
+        * @see java.util.StringTokenizer
+        * @see String#trim()
+        */
+       public static String[] tokenizeToStringArray(
+                       String str, String delimiters, boolean trimTokens, 
boolean ignoreEmptyTokens) {
+
+               if (str == null) {
+                       return null;
+               }
+               StringTokenizer st = new StringTokenizer(str, delimiters);
+               List<String> tokens = new ArrayList<>();
+               while (st.hasMoreTokens()) {
+                       String token = st.nextToken();
+                       if (trimTokens) {
+                               token = token.trim();
+                       }
+                       if (!ignoreEmptyTokens || token.length() > 0) {
+                               tokens.add(token);
+                       }
+               }
+               return toStringArray(tokens);
+       }
+
+       /**
+        * Take a String which is a delimited list and convert it to a String 
array.
+        * <p>A single delimiter can consists current more than one character: 
It will still
+        * be considered as single delimiter string, rather than as bunch 
current potential
+        * delimiter characters - in contrast to {@code tokenizeToStringArray}.
+        * @param str the input String
+        * @param delimiter the delimiter between elements (this is a single 
delimiter,
+        * rather than a bunch individual delimiter characters)
+        * @return an array current the tokens in the list
+        * @see #tokenizeToStringArray
+        */
+       public static String[] delimitedListToStringArray(String str, String 
delimiter) {
+               return delimitedListToStringArray(str, delimiter, null);
+       }
+
+       /**
+        * Take a String which is a delimited list and convert it to a String 
array.
+        * <p>A single delimiter can consists current more than one character: 
It will still
+        * be considered as single delimiter string, rather than as bunch 
current potential
+        * delimiter characters - in contrast to {@code tokenizeToStringArray}.
+        * @param str the input String
+        * @param delimiter the delimiter between elements (this is a single 
delimiter,
+        * rather than a bunch individual delimiter characters)
+        * @param charsToDelete a set current characters to delete. Useful for 
deleting unwanted
+        * line breaks: e.g. "\r\n\f" will delete all new lines and line feeds 
in a String.
+        * @return an array current the tokens in the list
+        * @see #tokenizeToStringArray
+        */
+       public static String[] delimitedListToStringArray(String str, String 
delimiter, String charsToDelete) {
+               if (str == null) {
+                       return new String[0];
+               }
+               if (delimiter == null) {
+                       return new String[] {str};
+               }
+               List<String> result = new ArrayList<>();
+               if ("".equals(delimiter)) {
+                       for (int i = 0; i < str.length(); i++) {
+                               result.add(deleteAny(str.substring(i, i + 1), 
charsToDelete));
+                       }
+               }
+               else {
+                       int pos = 0;
+                       int delPos;
+                       while ((delPos = str.indexOf(delimiter, pos)) != -1) {
+                               result.add(deleteAny(str.substring(pos, 
delPos), charsToDelete));
+                               pos = delPos + delimiter.length();
+                       }
+                       if (str.length() > 0 && pos <= str.length()) {
+                               // Add rest current String, but not in case 
current empty input.
+                               result.add(deleteAny(str.substring(pos), 
charsToDelete));
+                       }
+               }
+               return toStringArray(result);
+       }
+
+
+       /**
+        * Convenience method to return a Collection as a delimited (e.g. CSV)
+        * String. E.g. useful for {@code toString()} implementations.
+        * @param coll the Collection to display
+        * @param delim the delimiter to use (probably a ",")
+        * @param prefix the String to start each element with
+        * @param suffix the String to end each element with
+        * @return the delimited String
+        */
+       public static String collectionToDelimitedString(Collection<?> coll, 
String delim, String prefix, String suffix) {
+               if (coll.isEmpty()) {
+                       return "";
+               }
+               StringBuilder sb = new StringBuilder();
+               Iterator<?> it = coll.iterator();
+               while (it.hasNext()) {
+                       sb.append(prefix).append(it.next()).append(suffix);
+                       if (it.hasNext()) {
+                               sb.append(delim);
+                       }
+               }
+               return sb.toString();
+       }
+
+       /**
+        * Convenience method to return a Collection as a delimited (e.g. CSV)
+        * String. E.g. useful for {@code toString()} implementations.
+        * @param coll the Collection to display
+        * @param delim the delimiter to use (probably a ",")
+        * @return the delimited String
+        */
+       public static String collectionToDelimitedString(Collection<?> coll, 
String delim) {
+               return collectionToDelimitedString(coll, delim, "", "");
+       }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/b56817f7/core/src/test/java/org/apache/tamaya/core/testdata/TestPropertySourceProvider.java
----------------------------------------------------------------------
diff --git 
a/core/src/test/java/org/apache/tamaya/core/testdata/TestPropertySourceProvider.java
 
b/core/src/test/java/org/apache/tamaya/core/testdata/TestPropertySourceProvider.java
new file mode 100644
index 0000000..56413ca
--- /dev/null
+++ 
b/core/src/test/java/org/apache/tamaya/core/testdata/TestPropertySourceProvider.java
@@ -0,0 +1,32 @@
+/*
+ * 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.testdata;
+
+import org.apache.tamaya.core.PathBasedPropertySourceProvider;
+import org.apache.tamaya.core.formats.PropertiesFormat;
+
+/**
+ * Test provider reading properties from classpath:cfg/final/**.properties.
+ */
+public class TestPropertySourceProvider extends 
PathBasedPropertySourceProvider{
+
+    public TestPropertySourceProvider() {
+        super("final-testdata-properties", PropertiesFormat.of(200), 
"classpath:cfg/final/**/*.properties");
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/b56817f7/dormant/api/PropertyMapSupplier.java
----------------------------------------------------------------------
diff --git a/dormant/api/PropertyMapSupplier.java 
b/dormant/api/PropertyMapSupplier.java
new file mode 100644
index 0000000..69dd308
--- /dev/null
+++ b/dormant/api/PropertyMapSupplier.java
@@ -0,0 +1,37 @@
+/*
+* 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;
+
+import java.util.Map;
+
+/**
+ * Supplier for a property map.
+ */
+@FunctionalInterface
+public interface PropertyMapSupplier {
+
+    /**
+     * Access the current properties as Map. The resulting Map may not return 
all items accessible, e.g.
+     * when the underlying storage does not support iteration of its entries.
+     *
+     * @return the a corresponding map, never null.
+     */
+   Map<String,String> getProperties();
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/b56817f7/dormant/api/src/main/java/org/apache/tamaya/ConfigQuery.java
----------------------------------------------------------------------
diff --git a/dormant/api/src/main/java/org/apache/tamaya/ConfigQuery.java 
b/dormant/api/src/main/java/org/apache/tamaya/ConfigQuery.java
deleted file mode 100644
index 58d8742..0000000
--- a/dormant/api/src/main/java/org/apache/tamaya/ConfigQuery.java
+++ /dev/null
@@ -1,37 +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;
-
-
-/**
- * Interface for an query that converts a Configuration into another object. 
One typical
- * use cases would creating a complex configuration parameter type fromMap a 
Configuration instance or
- * constraint views on configuration.
- */
-@FunctionalInterface
-public interface ConfigQuery<T>{
-
-    /**
-     * Queries the given configuration.
-     * @param config the configuration to be wuiried, not null.
-     * @return the result T.
-     */
-    T query(Configuration config);
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/b56817f7/dormant/api/src/main/java/org/apache/tamaya/ConfiguredValue.java
----------------------------------------------------------------------
diff --git a/dormant/api/src/main/java/org/apache/tamaya/ConfiguredValue.java 
b/dormant/api/src/main/java/org/apache/tamaya/ConfiguredValue.java
deleted file mode 100644
index e75cd51..0000000
--- a/dormant/api/src/main/java/org/apache/tamaya/ConfiguredValue.java
+++ /dev/null
@@ -1,256 +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;
-
-import org.apache.tamaya.annotation.LoadPolicy;
-
-import java.beans.PropertyChangeEvent;
-import java.util.Optional;
-import java.util.function.Consumer;
-import java.util.function.Function;
-import java.util.function.Predicate;
-import java.util.function.Supplier;
-
-/**
- * A accessor for a single configured value. This can be used to support 
values that may be reinjected, reconfigured or
- * final.
- * <h3>Implementation Requirements</h3>
- * Instances of this class must be
- * <ul>
- *     <li>Serializable</li>
- *     <li>Immutable</li>
- *     <li>Thread safe</li>
- * </ul>
- */
-public interface ConfiguredValue<T> {
-
-    /**
-     * Access the {@link org.apache.tamaya.annotation.LoadPolicy} used for 
updating this value.
-     * @return the load policy, never null.
-     */
-    LoadPolicy getLoadPolicy();
-
-    /**
-     * get the UTC timestamp in ms of the last access to a value, using get().
-     * @return the UTC timestamp of the last access
-     */
-    long getLastAccess();
-
-    /**
-     * get the UTC timestamp in ms of the last update to the value,.
-     * @return the UTC timestamp of the last update
-     */
-    long getLastUpdate();
-
-    /**
-     * Access if this instance has been updated since the given UTC timestamp 
in ms.
-     * @param timestamp
-     * @return true, if his instance has been updated since the given UTC 
timestamp in ms.
-     */
-    boolean isUpdatedSince(long timestamp);
-
-    /**
-     * Access if this instance has been accessed since the given UTC timestamp 
in ms.
-     * @param timestamp
-     * @return true, if his instance has been accessed since the given UTC 
timestamp in ms.
-     */
-    boolean isAccessedSince(long timestamp);
-
-    /**
-     * Add a listener to be called, when this value is changed.
-     * @param l the listner, not null
-     */
-    void addListener(Consumer<PropertyChangeEvent> l);
-
-    /**
-     * Removes a listener to be called, when this value is changed.
-     * @param l the listner to be removed, not null
-     */
-    void removeListener(Consumer<PropertyChangeEvent> l);
-
-    /**
-     * Evaluate if the item value has been updated since the last access.
-     * @return true, if item value has been updated since the last access.
-     */
-    default boolean isUpdated(){
-        return isUpdatedSince(getLastAccess());
-    }
-
-    /**
-     * If a value is present in this {@code ConfiguredValue}, returns the 
value,
-     * otherwise throws {@code ConfigException}.
-     *
-     * @return the non-null value held by this {@code Optional}
-     * @throws org.apache.tamaya.ConfigException if there is no value present
-     *
-     * @see ConfiguredValue#isPresent()
-     */
-    T get();
-
-    /**
-     * If a value is present in this {@code ConfiguredValue}, returns the 
value,
-     * otherwise throws {@code ConfigException}.
-     *
-     * @return the non-null value held by this {@code Optional}
-     * @throws org.apache.tamaya.ConfigException if there is no value present
-     *
-     * @see ConfiguredValue#isPresent()
-     */
-    default T updateAndGet(){
-        update();
-        return get();
-    }
-
-    /**
-     * Reevaluates the current value based on the instance's settings from the 
underlying configurations
-     * and applies the new value to its internal state. On change any 
registered listeners will be triggered.
-     */
-    void update();
-
-    /**
-     * Return {@code true} if there is a value present, otherwise {@code 
false}.
-     *
-     * @return {@code true} if there is a value present, otherwise {@code 
false}
-     */
-    boolean isPresent();
-
-    /**
-     * If a value is present, invoke the specified consumer with the value,
-     * otherwise do nothing.
-     *
-     * @param consumer block to be executed if a value is present
-     * @throws NullPointerException if value is present and {@code consumer} is
-     * null
-     */
-    void ifPresent(Consumer<? super T> consumer);
-
-    /**
-     * If a value is present, and the value matches the given predicate,
-     * return an {@code Optional} describing the value, otherwise return an
-     * empty {@code Optional}.
-     *
-     * @param predicate a predicate to apply to the value, if present
-     * @return an {@code Optional} describing the value of this {@code 
Optional}
-     * if a value is present and the value matches the given predicate,
-     * otherwise an empty {@code Optional}
-     * @throws NullPointerException if the predicate is null
-     */
-    ConfiguredValue<T> filter(Predicate<? super T> predicate);
-
-    /**
-     * If a value is present, apply the provided mapping function to it,
-     * and if the result is non-null, return an {@code Optional} describing the
-     * result.  Otherwise return an empty {@code Optional}.
-     *
-     * @apiNote This method supports post-processing on optional values, 
without
-     * the need to explicitly check for a return status.  For example, the
-     * following code traverses a stream of file names, selects one that has
-     * not yet been processed, and then opens that file, returning an
-     * {@code Optional<FileInputStream>}:
-     *
-     * <pre>{@code
-     *     Optional<FileInputStream> fis =
-     *         names.stream().filter(name -> !isProcessedYet(name))
-     *                       .findFirst()
-     *                       .map(name -> new FileInputStream(name));
-     * }</pre>
-     *
-     * Here, {@code findFirst} returns an {@code Optional<String>}, and then
-     * {@code map} returns an {@code Optional<FileInputStream>} for the desired
-     * file if one exists.
-     *
-     * @param <U> The type of the result of the mapping function
-     * @param mapper a mapping function to apply to the value, if present
-     * @return an {@code Optional} describing the result of applying a mapping
-     * function to the value of this {@code Optional}, if a value is present,
-     * otherwise an empty {@code Optional}
-     * @throws NullPointerException if the mapping function is null
-     */
-    <U> ConfiguredValue<U> map(Function<? super T, ? extends U> mapper);
-
-    /**
-     * If a value is present, apply the provided {@code Optional}-bearing
-     * mapping function to it, return that result, otherwise return an empty
-     * {@code Optional}.  This method is similar to {@link #map(Function)},
-     * but the provided mapper is one whose result is already an {@code 
Optional},
-     * and if invoked, {@code flatMap} does not wrap it with an additional
-     * {@code Optional}.
-     *
-     * @param <U> The type parameter to the {@code Optional} returned by
-     * @param mapper a mapping function to apply to the value, if present
-     *           the mapping function
-     * @return the result of applying an {@code Optional}-bearing mapping
-     * function to the value of this {@code Optional}, if a value is present,
-     * otherwise an empty {@code Optional}
-     * @throws NullPointerException if the mapping function is null or returns
-     * a null result
-     */
-    <U> ConfiguredValue<U> flatMap(Function<? super T, ConfiguredValue<U>> 
mapper);
-
-    /**
-     * Return the value if present, otherwise return {@code other}.
-     *
-     * @param other the value to be returned if there is no value present, may
-     * be null
-     * @return the value, if present, otherwise {@code other}
-     */
-    T orElse(T other);
-
-    /**
-     * Return the value if present, otherwise invoke {@code other} and return
-     * the result of that invocation.
-     *
-     * @param other a {@code Supplier} whose result is returned if no value
-     * is present
-     * @return the value if present otherwise the result of {@code other.get()}
-     * @throws NullPointerException if value is not present and {@code other} 
is
-     * null
-     */
-    T orElseGet(Supplier<? extends T> other);
-
-    /**
-     * Return the contained value, if present, otherwise throw an exception
-     * to be created by the provided supplier.
-     *
-     * @apiNote A method reference to the exception constructor with an empty
-     * argument list can be used as the supplier. For example,
-     * {@code IllegalStateException::new}
-     *
-     * @param <X> Type of the exception to be thrown
-     * @param exceptionSupplier The supplier which will return the exception to
-     * be thrown
-     * @return the present value
-     * @throws X if there is no value present
-     * @throws NullPointerException if no value is present and
-     * {@code exceptionSupplier} is null
-     */
-    <X extends Throwable> T orElseThrow(Supplier<? extends X> 
exceptionSupplier) throws X;
-
-    /**
-     * Converts this value to an {@link java.util.Optional} instance.
-     * @return an {@link java.util.Optional} instance, never null.
-     */
-    default Optional<T> toOptional(){
-        if(isPresent()){
-            return Optional.of(get());
-        }
-        return Optional.empty();
-    }
-
-}

Reply via email to