alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Java example source code file (ReflectionNavigator.java)

This example Java source code file (ReflectionNavigator.java) is included in the alvinalexander.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Learn more about this Java project at its project page.

Java - Java tags/keywords

binderarg, class, field, genericarraytype, location, nosuchfieldexception, override, parameterizedtype, parameterizedtypeimpl, reflection, reflectionnavigator, string, type, typevisitor, util, void

The ReflectionNavigator.java Java example source code

/*
 * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package com.sun.xml.internal.bind.v2.model.nav;

import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.GenericDeclaration;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.lang.reflect.WildcardType;
import java.util.Arrays;
import java.util.Collection;

import com.sun.xml.internal.bind.v2.runtime.Location;

/**
 * {@link Navigator} implementation for {@code java.lang.reflect}.
 *
 */
/*package*/final class ReflectionNavigator implements Navigator<Type, Class, Field, Method> {

//  ----------  Singleton -----------------
    private static final ReflectionNavigator INSTANCE = new ReflectionNavigator();

    /*package*/static ReflectionNavigator getInstance() {
        return INSTANCE;
    }

    private ReflectionNavigator() {
    }
//  ---------------------------------------

    public Class getSuperClass(Class clazz) {
        if (clazz == Object.class) {
            return null;
        }
        Class sc = clazz.getSuperclass();
        if (sc == null) {
            sc = Object.class;        // error recovery
        }
        return sc;
    }

    private static final TypeVisitor<Type, Class> baseClassFinder = new TypeVisitor() {

        public Type onClass(Class c, Class sup) {
            // t is a raw type
            if (sup == c) {
                return sup;
            }

            Type r;

            Type sc = c.getGenericSuperclass();
            if (sc != null) {
                r = visit(sc, sup);
                if (r != null) {
                    return r;
                }
            }

            for (Type i : c.getGenericInterfaces()) {
                r = visit(i, sup);
                if (r != null) {
                    return r;
                }
            }

            return null;
        }

        public Type onParameterizdType(ParameterizedType p, Class sup) {
            Class raw = (Class) p.getRawType();
            if (raw == sup) {
                // p is of the form sup<...>
                return p;
            } else {
                // recursively visit super class/interfaces
                Type r = raw.getGenericSuperclass();
                if (r != null) {
                    r = visit(bind(r, raw, p), sup);
                }
                if (r != null) {
                    return r;
                }
                for (Type i : raw.getGenericInterfaces()) {
                    r = visit(bind(i, raw, p), sup);
                    if (r != null) {
                        return r;
                    }
                }
                return null;
            }
        }

        public Type onGenericArray(GenericArrayType g, Class sup) {
            // not clear what I should do here
            return null;
        }

        public Type onVariable(TypeVariable v, Class sup) {
            return visit(v.getBounds()[0], sup);
        }

        public Type onWildcard(WildcardType w, Class sup) {
            // not clear what I should do here
            return null;
        }

        /**
         * Replaces the type variables in {@code t} by its actual arguments.
         *
         * @param decl
         *      provides a list of type variables. See {@link GenericDeclaration#getTypeParameters()}
         * @param args
         *      actual arguments. See {@link ParameterizedType#getActualTypeArguments()}
         */
        private Type bind(Type t, GenericDeclaration decl, ParameterizedType args) {
            return binder.visit(t, new BinderArg(decl, args.getActualTypeArguments()));
        }
    };

    private static class BinderArg {

        final TypeVariable[] params;
        final Type[] args;

        BinderArg(TypeVariable[] params, Type[] args) {
            this.params = params;
            this.args = args;
            assert params.length == args.length;
        }

        public BinderArg(GenericDeclaration decl, Type[] args) {
            this(decl.getTypeParameters(), args);
        }

        Type replace(TypeVariable v) {
            for (int i = 0; i < params.length; i++) {
                if (params[i].equals(v)) {
                    return args[i];
                }
            }
            return v;   // this is a free variable
        }
    }
    private static final TypeVisitor<Type, BinderArg> binder = new TypeVisitor() {

        public Type onClass(Class c, BinderArg args) {
            return c;
        }

        public Type onParameterizdType(ParameterizedType p, BinderArg args) {
            Type[] params = p.getActualTypeArguments();

            boolean different = false;
            for (int i = 0; i < params.length; i++) {
                Type t = params[i];
                params[i] = visit(t, args);
                different |= t != params[i];
            }

            Type newOwner = p.getOwnerType();
            if (newOwner != null) {
                newOwner = visit(newOwner, args);
            }
            different |= p.getOwnerType() != newOwner;

            if (!different) {
                return p;
            }

            return new ParameterizedTypeImpl((Class<?>) p.getRawType(), params, newOwner);
        }

        public Type onGenericArray(GenericArrayType g, BinderArg types) {
            Type c = visit(g.getGenericComponentType(), types);
            if (c == g.getGenericComponentType()) {
                return g;
            }

            return new GenericArrayTypeImpl(c);
        }

        public Type onVariable(TypeVariable v, BinderArg types) {
            return types.replace(v);
        }

        public Type onWildcard(WildcardType w, BinderArg types) {
            // TODO: this is probably still incorrect
            // bind( "? extends T" ) with T= "? extends Foo" should be "? extends Foo",
            // not "? extends (? extends Foo)"
            Type[] lb = w.getLowerBounds();
            Type[] ub = w.getUpperBounds();
            boolean diff = false;

            for (int i = 0; i < lb.length; i++) {
                Type t = lb[i];
                lb[i] = visit(t, types);
                diff |= (t != lb[i]);
            }

            for (int i = 0; i < ub.length; i++) {
                Type t = ub[i];
                ub[i] = visit(t, types);
                diff |= (t != ub[i]);
            }

            if (!diff) {
                return w;
            }

            return new WildcardTypeImpl(lb, ub);
        }
    };

    public Type getBaseClass(Type t, Class sup) {
        return baseClassFinder.visit(t, sup);
    }

    public String getClassName(Class clazz) {
        return clazz.getName();
    }

    public String getTypeName(Type type) {
        if (type instanceof Class) {
            Class c = (Class) type;
            if (c.isArray()) {
                return getTypeName(c.getComponentType()) + "[]";
            }
            return c.getName();
        }
        return type.toString();
    }

    public String getClassShortName(Class clazz) {
        return clazz.getSimpleName();
    }

    public Collection<? extends Field> getDeclaredFields(Class clazz) {
        return Arrays.asList(clazz.getDeclaredFields());
    }

    public Field getDeclaredField(Class clazz, String fieldName) {
        try {
            return clazz.getDeclaredField(fieldName);
        } catch (NoSuchFieldException e) {
            return null;
        }
    }

    public Collection<? extends Method> getDeclaredMethods(Class clazz) {
        return Arrays.asList(clazz.getDeclaredMethods());
    }

    public Class getDeclaringClassForField(Field field) {
        return field.getDeclaringClass();
    }

    public Class getDeclaringClassForMethod(Method method) {
        return method.getDeclaringClass();
    }

    public Type getFieldType(Field field) {
        if (field.getType().isArray()) {
            Class c = field.getType().getComponentType();
            if (c.isPrimitive()) {
                return Array.newInstance(c, 0).getClass();
            }
        }
        return fix(field.getGenericType());
    }

    public String getFieldName(Field field) {
        return field.getName();
    }

    public String getMethodName(Method method) {
        return method.getName();
    }

    public Type getReturnType(Method method) {
        return fix(method.getGenericReturnType());
    }

    public Type[] getMethodParameters(Method method) {
        return method.getGenericParameterTypes();
    }

    public boolean isStaticMethod(Method method) {
        return Modifier.isStatic(method.getModifiers());
    }

    public boolean isFinalMethod(Method method) {
        return Modifier.isFinal(method.getModifiers());
    }

    public boolean isSubClassOf(Type sub, Type sup) {
        return erasure(sup).isAssignableFrom(erasure(sub));
    }

    public Class ref(Class c) {
        return c;
    }

    public Class use(Class c) {
        return c;
    }

    public Class asDecl(Type t) {
        return erasure(t);
    }

    public Class asDecl(Class c) {
        return c;
    }
    /**
     * Implements the logic for {@link #erasure(Type)}.
     */
    private static final TypeVisitor<Class, Void> eraser = new TypeVisitor() {

        public Class onClass(Class c, Void v) {
            return c;
        }

        public Class onParameterizdType(ParameterizedType p, Void v) {
            // TODO: why getRawType returns Type? not Class?
            return visit(p.getRawType(), null);
        }

        public Class onGenericArray(GenericArrayType g, Void v) {
            return Array.newInstance(
                    visit(g.getGenericComponentType(), null),
                    0).getClass();
        }

        public Class onVariable(TypeVariable tv, Void v) {
            return visit(tv.getBounds()[0], null);
        }

        public Class onWildcard(WildcardType w, Void v) {
            return visit(w.getUpperBounds()[0], null);
        }
    };

    /**
     * Returns the runtime representation of the given type.
     *
     * This corresponds to the notion of the erasure in JSR-14.
     *
     * <p>
     * Because of the difference in the way Annotation Processing and the Java reflection
     * treats primitive type and array type, we can't define this method
     * on {@link Navigator}.
     *
     * <p>
     * It made me realize how difficult it is to define the common navigation
     * layer for two different underlying reflection library. The other way
     * is to throw away the entire parameterization and go to the wrapper approach.
     */
    public <T> Class erasure(Type t) {
        return eraser.visit(t, null);
    }

    public boolean isAbstract(Class clazz) {
        return Modifier.isAbstract(clazz.getModifiers());
    }

    public boolean isFinal(Class clazz) {
        return Modifier.isFinal(clazz.getModifiers());
    }

    /**
     * Returns the {@link Type} object that represents {@code clazz<T1,T2,T3>}.
     */
    public Type createParameterizedType(Class rawType, Type... arguments) {
        return new ParameterizedTypeImpl(rawType, arguments, null);
    }

    public boolean isArray(Type t) {
        if (t instanceof Class) {
            Class c = (Class) t;
            return c.isArray();
        }
        if (t instanceof GenericArrayType) {
            return true;
        }
        return false;
    }

    public boolean isArrayButNotByteArray(Type t) {
        if (t instanceof Class) {
            Class c = (Class) t;
            return c.isArray() && c != byte[].class;
        }
        if (t instanceof GenericArrayType) {
            t = ((GenericArrayType) t).getGenericComponentType();
            return t != Byte.TYPE;
        }
        return false;
    }

    public Type getComponentType(Type t) {
        if (t instanceof Class) {
            Class c = (Class) t;
            return c.getComponentType();
        }
        if (t instanceof GenericArrayType) {
            return ((GenericArrayType) t).getGenericComponentType();
        }

        throw new IllegalArgumentException();
    }

    public Type getTypeArgument(Type type, int i) {
        if (type instanceof ParameterizedType) {
            ParameterizedType p = (ParameterizedType) type;
            return fix(p.getActualTypeArguments()[i]);
        } else {
            throw new IllegalArgumentException();
        }
    }

    public boolean isParameterizedType(Type type) {
        return type instanceof ParameterizedType;
    }

    public boolean isPrimitive(Type type) {
        if (type instanceof Class) {
            Class c = (Class) type;
            return c.isPrimitive();
        }
        return false;
    }

    public Type getPrimitive(Class primitiveType) {
        assert primitiveType.isPrimitive();
        return primitiveType;
    }

    public Location getClassLocation(final Class clazz) {
        return new Location() {

            @Override
            public String toString() {
                return clazz.getName();
            }
        };
    }

    public Location getFieldLocation(final Field field) {
        return new Location() {

            @Override
            public String toString() {
                return field.toString();
            }
        };
    }

    public Location getMethodLocation(final Method method) {
        return new Location() {

            @Override
            public String toString() {
                return method.toString();
            }
        };
    }

    public boolean hasDefaultConstructor(Class c) {
        try {
            c.getDeclaredConstructor();
            return true;
        } catch (NoSuchMethodException e) {
            return false; // todo: do this WITHOUT exception throw
        }
    }

    public boolean isStaticField(Field field) {
        return Modifier.isStatic(field.getModifiers());
    }

    public boolean isPublicMethod(Method method) {
        return Modifier.isPublic(method.getModifiers());
    }

    public boolean isPublicField(Field field) {
        return Modifier.isPublic(field.getModifiers());
    }

    public boolean isEnum(Class c) {
        return Enum.class.isAssignableFrom(c);
    }

    public Field[] getEnumConstants(Class clazz) {
        try {
            Object[] values = clazz.getEnumConstants();
            Field[] fields = new Field[values.length];
            for (int i = 0; i < values.length; i++) {
                fields[i] = clazz.getField(((Enum) values[i]).name());
            }
            return fields;
        } catch (NoSuchFieldException e) {
            // impossible
            throw new NoSuchFieldError(e.getMessage());
        }
    }

    public Type getVoidType() {
        return Void.class;
    }

    public String getPackageName(Class clazz) {
        String name = clazz.getName();
        int idx = name.lastIndexOf('.');
        if (idx < 0) {
            return "";
        } else {
            return name.substring(0, idx);
        }
    }

    @Override
    public Class loadObjectFactory(Class referencePoint, String pkg) {
        ClassLoader cl= SecureLoader.getClassClassLoader(referencePoint);
        if (cl == null)
            cl = SecureLoader.getSystemClassLoader();

        try {
            return cl.loadClass(pkg + ".ObjectFactory");
        } catch (ClassNotFoundException e) {
            return null;
        }
    }

    public boolean isBridgeMethod(Method method) {
        return method.isBridge();
    }

    public boolean isOverriding(Method method, Class base) {
        // this isn't actually correct,
        // as the JLS considers
        // class Derived extends Base<Integer> {
        //   Integer getX() { ... }
        // }
        // class Base<T> {
        //   T getX() { ... }
        // }
        // to be overrided. Handling this correctly needs a careful implementation

        String name = method.getName();
        Class[] params = method.getParameterTypes();

        while (base != null) {
            try {
                if (base.getDeclaredMethod(name, params) != null) {
                    return true;
                }
            } catch (NoSuchMethodException e) {
                // recursively go into the base class
            }

            base = base.getSuperclass();
        }

        return false;
    }

    public boolean isInterface(Class clazz) {
        return clazz.isInterface();
    }

    public boolean isTransient(Field f) {
        return Modifier.isTransient(f.getModifiers());
    }

    public boolean isInnerClass(Class clazz) {
        return clazz.getEnclosingClass() != null && !Modifier.isStatic(clazz.getModifiers());
    }

    @Override
    public boolean isSameType(Type t1, Type t2) {
        return t1.equals(t2);
    }

    /**
     * JDK 5.0 has a bug of creating {@link GenericArrayType} where it shouldn't.
     * fix that manually to work around the problem.
     *
     * See bug 6202725.
     */
    private Type fix(Type t) {
        if (!(t instanceof GenericArrayType)) {
            return t;
        }

        GenericArrayType gat = (GenericArrayType) t;
        if (gat.getGenericComponentType() instanceof Class) {
            Class c = (Class) gat.getGenericComponentType();
            return Array.newInstance(c, 0).getClass();
        }

        return t;
    }
}

Other Java examples (source code examples)

Here is a short list of links related to this Java ReflectionNavigator.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.