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/01/03 12:59:24 UTC

[15/27] incubator-tamaya git commit: TAMAYA-19: Reorganized dormant part for better focus of future discussions.

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();
-    }
-
-}