001package org.unix4j.util;
002
003/**
004 * Utility class with static methods to help loading a Java 7 version of a class
005 * if it is available, and the Java 6 version otherwise.
006 */
007public class Java7Util {
008
009        /**
010         * The suffix used for Java 7 classes, the string "7".
011         */
012        public static final String JAVA7_CLASS_NAME_SUFFIX = "7";
013
014        /**
015         * Returns true if the system property "java.version" starts with "1.7".
016         *
017         * @return true if the current java version is 1.7
018     */
019        public static final boolean isJava7() {
020                return System.getProperty("java.version").startsWith("1.7");
021        }
022
023        /**
024         * Returns a new instance of the Java 7 version of the given class if it
025         * exists and can be instantiated. Otherwise, the given
026         * {@code defaultInstance} is returned.
027         * <p>
028         * The Java 7 version of the class must be a subtype of {@code baseClass}
029         * and its fully qualified name must be identical to that of
030         * {@code baseClass} with a suffix "7". For instance, if the Java 6 base
031         * class is called "org.unix4j.MyClass", the Java 7 version must be called
032         * "org.unix4j.MyClass7". Furthermore, the class must have a default
033         * constructor with no arguments.
034         * <p>
035         * If the Java 7 version of the class is not found (usually because unix4j
036         * was compiled with a Java 6 compiler) or if the Java 7 class cannot be
037         * instantiated (usually because unix4j is run in a Java 6 JVM), the given
038         * {@code defaultInstance} is returned.
039         * 
040         * @param <T>
041         *            the generic return type
042         * @param baseClass
043         *            the base class and superclass of the Java 7 class
044         * @return a new instance of the Java 7 subtype if possible and
045         *         {@code defaultInstance} otherwise
046         */
047        public static <T> T newInstance(Class<T> baseClass, T defaultInstance) {
048                final Class<? extends T> clazz = loadClass(baseClass);
049                try {
050                        return clazz.newInstance();
051                } catch (Exception e) {
052                        return defaultInstance;
053                }
054        }
055
056        /**
057         * Returns the Java 7 version of the given class if it exists and can be
058         * loaded, and the given {@code baseClass} otherwise.
059         * <p>
060         * The Java 7 version of the class must be a subtype of {@code baseClass}
061         * and its fully qualified name must be identical to that of
062         * {@code baseClass} with a suffix "7". For instance, if the Java 6 base
063         * class is called "org.unix4j.MyClass", the Java 7 version must be called
064         * "org.unix4j.MyClass7".
065         * <p>
066         * If the Java 7 version of the class is not found (usually because unix4j
067         * was compiled with a Java 6 compiler), the given {@code defaultInstance}
068         * is returned. If the class is found but it is not a subtype of the given
069         * {@code baseClass}, an exception is thrown.
070         * 
071         * @param <T>
072         *            the generic type of the base class
073         * @param baseClass
074         *            the base class and superclass of the Java 7 class
075         * @return the Java 7 subclass if possible and {@code baseClass} otherwise
076         * @throws NullPointerException
077         *             if {@code baseClass} is null
078         * @throws IllegalArgumentException
079         *             if the Java 7 class is found but it is not a subclass of
080         *             {@code baseClass}
081         */
082        public static <T> Class<? extends T> loadClass(Class<T> baseClass) {
083                if (baseClass == null) {
084                        throw new NullPointerException("baseClass cannot be null");
085                }
086                final Class<?> java7Class;
087                try {
088                        java7Class = Class.forName(baseClass.getName() + JAVA7_CLASS_NAME_SUFFIX);
089                } catch (ClassNotFoundException e) {
090                        return baseClass;
091                }
092                if (baseClass.isAssignableFrom(java7Class)) {
093                        return java7Class.asSubclass(baseClass);
094                }
095                throw new IllegalArgumentException("class " + java7Class.getName() + " is not a subclass of " + baseClass.getName());
096        }
097}