com.link_intersystems.lang.reflect.ReflectFacade.java Source code

Java tutorial

Introduction

Here is the source code for com.link_intersystems.lang.reflect.ReflectFacade.java

Source

/**
 * Copyright 2011 Link Intersystems GmbH <rene.link@link-intersystems.com>
 *
 * 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 com.link_intersystems.lang.reflect;

import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.util.Comparator;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.collections4.Predicate;
import org.apache.commons.collections4.Transformer;
import org.apache.commons.collections4.functors.AndPredicate;
import org.apache.commons.collections4.functors.EqualPredicate;
import org.apache.commons.collections4.functors.NotNullPredicate;
import org.apache.commons.collections4.functors.TransformedPredicate;
import org.apache.commons.lang3.reflect.MethodUtils;

import com.link_intersystems.lang.Assert;
import com.link_intersystems.lang.ref.Reference;
import com.link_intersystems.lang.ref.SerializableReference;

public abstract class ReflectFacade {

    private static final class SerializableReferenceImplementation
            implements SerializableReference<Predicate<Class<?>>> {
        /**
         *
         */
        private static final long serialVersionUID = -625148437829360498L;
        private transient Predicate<Class<?>> predicate;

        public Predicate<Class<?>> get() {
            if (predicate == null) {
                Predicate<Class<?>> isInterfacePredicate = new Predicate<Class<?>>() {

                    public boolean evaluate(Class<?> object) {
                        return object.isInterface();
                    }

                };
                predicate = isInterfacePredicate;
            }
            return predicate;
        }
    }

    private static final Predicate<Class<?>> CLASS_IS_INTERFACE_PREDICATE;

    static {
        CLASS_IS_INTERFACE_PREDICATE = new SerializablePredicate<Class<?>>(
                new SerializableReferenceImplementation());
    }

    /**
     * Adapts the {@link Class#isInterface()} method to an {@link Predicate}.
     * This Predicate that evaluates to true if the object it is evaluated
     * against is a {@link Class} and the class is an interface.
     *
     * @return a {@link Predicate} that evaluates to true if the object it is
     *         evaluated against is a {@link Class} and that {@link Class}
     *         represents an interface.
     * @since 1.0.0.0
     *
     */
    public static Predicate<Class<?>> getIsInterfacePredicate() {
        return CLASS_IS_INTERFACE_PREDICATE;
    }

    /**
     * A {@link Predicate} that evaluates to true if it is evaluated against
     * {@link Member} objects and the {@link Member#getName()} is equal to the
     * memberName this Predicate was constructed with.
     *
     * @return {@link Predicate} that evaluates to true if the {@link Member}'s
     *         name it is evaluated against is equal to the name that this
     *         {@link MemberNamePredicate} was constructed with.
     * @since 1.0.0.0
     */
    public static Predicate getMemberNamePredicate(String memberName) {
        Assert.notNull("memberName", memberName);

        class SerializableMemberNamePredicate implements SerializableReference<Predicate> {

            private static final long serialVersionUID = -625148437829360498L;

            private transient Predicate predicate;

            private final String memberName;

            public SerializableMemberNamePredicate(String memberName) {
                this.memberName = memberName;
            }

            public Predicate get() {
                if (predicate == null) {
                    Method memberGetNameMethod = MethodUtils.getAccessibleMethod(Member.class, "getName",
                            new Class<?>[0]);
                    MethodInvokingTransformer member2NameTransformer = new MethodInvokingTransformer(
                            memberGetNameMethod);
                    Predicate propertyValuePredicate = AndPredicate
                            .andPredicate(NotNullPredicate.notNullPredicate(), new EqualPredicate(memberName));
                    Predicate instance = TransformedPredicate.transformedPredicate(member2NameTransformer,
                            propertyValuePredicate);
                    Predicate memberNamePredicate = AndPredicate.andPredicate(NotNullPredicate.notNullPredicate(),
                            instance);
                    this.predicate = memberNamePredicate;
                }
                return predicate;
            }
        }

        return new SerializablePredicate(new SerializableMemberNamePredicate(memberName));
    }

    /**
     * A {@link Predicate} that evaluates to true if the object it is evaluated
     * against is a {@link Member} and that {@link Member}'s declaring class is
     * equal to the {@link Class} that this
     * {@link DeclaringClassMemberPredicate} was constructed with.
     *
     * @author Ren Link <a
     *         href="mailto:rene.link@link-intersystems.com">[rene.link@link-
     *         intersystems.com]</a>
     * @since 1.0.0.0
     */
    public static Predicate getDeclaringClassPredicate(Class<?> declaringClass) {
        Assert.notNull("declaringClass", declaringClass);

        class SerializableDeclaringClassPredicate implements SerializableReference<Predicate> {

            private static final long serialVersionUID = -625148437829360498L;

            private transient Predicate predicate;

            private final Class<?> declaringClass;

            public SerializableDeclaringClassPredicate(Class<?> declaringClass) {
                this.declaringClass = declaringClass;
            }

            public Predicate get() {
                if (predicate == null) {
                    Method getDeclaringClassMethod = MethodUtils.getAccessibleMethod(Member.class,
                            "getDeclaringClass", new Class<?>[0]);
                    MethodInvokingTransformer member2NameTransformer = new MethodInvokingTransformer(
                            getDeclaringClassMethod);
                    Predicate propertyValuePredicate = AndPredicate
                            .andPredicate(NotNullPredicate.notNullPredicate(), new EqualPredicate(declaringClass));
                    Predicate instance = TransformedPredicate.transformedPredicate(member2NameTransformer,
                            propertyValuePredicate);
                    Predicate memberNamePredicate = AndPredicate.andPredicate(NotNullPredicate.notNullPredicate(),
                            instance);
                    this.predicate = memberNamePredicate;
                }
                return predicate;
            }
        }

        return new SerializablePredicate(new SerializableDeclaringClassPredicate(declaringClass));
    }

    /**
     * A {@link Predicate} that evaluates to true if the {@link Class} that this
     * {@link AssignablePredicate} was constructed with is assignable from the
     * class that it is evaluated against.
     *
     * @return a {@link Predicate} that evaluates to true if the {@link Class}
     *         it is evaluated against is assignable from the class it was
     *         constructed with.
     * @since 1.0.0.0
     */
    public static Predicate getIsAssignablePredicate(Class<?> clazz) {
        Assert.notNull("clazz", clazz);

        return new AssignablePredicate(clazz);

    }

    /**
     * {@link Predicate} that evaluates to true if the {@link Member}'s name it
     * is evaluated against matches a given {@link Pattern}.
     *
     * @return a {@link Predicate} that evaluates to true if it is evaluated
     *         against a {@link Member} object and the {@link Member}'s name
     *         matches the namePattern.
     * @since 1.0.0.0
     */
    public static Predicate getMemberNamePatternPredicate(Pattern namePattern) {
        return new MemberNamePatternPredicate(namePattern);
    }

    /**
     * Compares two {@link Class}es by their canonical name.
     *
     * @return a {@link Comparator} that compares {@link Class}es by their
     *         canonical name.
     * @since 1.0.0.0
     */
    public static Comparator<Class<?>> getCanonicalClassNameComparator() {
        return CanonicalClassNameComparator.INSTANCE;
    }

    /**
     * Compares {@link Member}s by their name ({@link Member#getName()}).
     *
     * @return a {@link Comparator} that compares {@link Member}s by their name
     *         ({@link Member#getName()}).
     * @since 1.0.0.0
     */
    public static Comparator<Member> getMemberNameComparator() {
        return MemberNameComparator.INSTANCE;
    }

    /**
     * A {@link Transformer} that transforms a {@link Field} into it's type.
     *
     * @return a {@link Transformer} that transforms a {@link Field} into it's
     *         type.
     * @since 1.0.0.0
     */
    public static Transformer getFieldTypeTransformer() {
        return FieldTypeTransformer.getInstance();
    }

    /**
     * A {@link Transformer} that transforms a {@link Method} into it's return
     * type.
     *
     * @return a {@link Transformer} that transforms a {@link Method} into it's
     *         return type.
     * @since 1.0.0.0
     */
    public static Transformer getMethodTypeTransformer() {
        return MethodTypeTransformer.getInstance();
    }

    /**
     * A factory method for {@link SerializableReference} objects that hold
     * {@link Member}s.
     *
     * @param member
     * @return a {@link SerializableReference} that represents the member. This
     *         factory method can produce {@link SerializableReference}s for
     *         {@link Constructor}s, {@link Method}s and {@link Field}s.
     *
     * @since 1.0.0.0
     */
    public static SerializableReference<? extends Member> getSerializableReference(Member member) {
        if (member instanceof Method) {
            return getSerializableReference((Method) member);
        } else if (member instanceof Field) {
            return getSerializableReference((Field) member);
        } else if (member instanceof Constructor<?>) {
            return getSerializableReference((Constructor<?>) member);
        } else {
            throw new IllegalArgumentException("member must be one of the type " + Constructor.class + ", "
                    + Method.class + " or " + Field.class);
        }
    }

    /**
     * A factory method for {@link SerializableReference} object that hold
     * {@link Constructor}s.
     *
     * @param constructor
     * @return a {@link SerializableReference} that represents the
     *         {@link Constructor} and ensures that the constructor is available
     *         each time the {@link Reference#get()} method is called. Even
     *         after serialisation/deserialization of the
     *         {@link SerializableReference}.
     *
     * @since 1.0.0.0
     */
    public static SerializableReference<Constructor<?>> getSerializableReference(Constructor<?> constructor) {
        return new SerializableConstructor(constructor);
    }

    /**
     * A factory method for {@link SerializableReference} object that hold
     * {@link Method}s.
     *
     * @param method
     * @return a {@link SerializableReference} that represents the
     *         {@link Method} and ensures that the method is available each time
     *         the {@link Reference#get()} method is called. Even after
     *         serialisation/deserialization of the
     *         {@link SerializableReference}.
     *
     * @since 1.0.0.0
     */
    public static SerializableReference<Method> getSerializableReference(Method method) {
        return new SerializableMethod(method);
    }

    /**
     * A factory method for {@link SerializableReference} object that hold
     * {@link Field}s.
     *
     * @param field
     * @return a {@link SerializableReference} that represents the {@link Field}
     *         and ensures that the field is available each time the
     *         {@link Reference#get()} method is called. Even after
     *         serialisation/deserialization of the
     *         {@link SerializableReference}.
     *
     * @since 1.0.0.0
     */
    public static SerializableReference<Field> getSerializableReference(Field field) {
        return new SerializableField(field);
    }

    /**
     * A factory method for {@link SerializableReference} object that hold
     * {@link Package}s.
     *
     * @param field
     * @return a {@link SerializableReference} that represents the
     *         {@link Package} and ensures that the package is available each
     *         time the {@link Reference#get()} method is called. Even after
     *         serialisation/deserialization of the
     *         {@link SerializableReference}.
     *
     * @since 1.0.0.0
     */
    public static SerializableReference<Package> getSerializableReference(Package packageObj) {
        return new SerializablePackage(packageObj);
    }
}

/**
 * Compares two {@link Member}s by their name ({@link Member#getName()}).
 *
 * @author Ren Link <a
 *         href="mailto:rene.link@link-intersystems.com">[rene.link@link-
 *         intersystems.com]</a>
 * @since 1.0.0.0
 */
class MemberNameComparator implements Comparator<Member>, Serializable {

    /**
     *
     */
    private static final long serialVersionUID = 8826998287267302658L;

    /**
     * Singleton instance of the {@link MemberNameComparator}.
     *
     * @since 1.0.0.0
     */
    public static final Comparator<Member> INSTANCE = new MemberNameComparator();

    /**
     * {@inheritDoc}
     *
     * @see MemberNameComparator class javadoc
     * @since 1.0.0.0
     */
    public int compare(Member o1, Member o2) {
        int compareValue = 0;
        if (o1 == null) {
            if (o2 == null) {
                compareValue = 0;
            } else {
                compareValue = -1;
            }
        } else {
            if (o2 == null) {
                compareValue = 1;
            } else {
                String name1 = o1.getName();
                String name2 = o2.getName();
                compareValue = name1.compareTo(name2);
            }
        }
        return compareValue;
    }

}

/**
 * A {@link Transformer} that transforms a {@link Method} into it's return type.
 *
 * @author Ren Link <a
 *         href="mailto:rene.link@link-intersystems.com">[rene.link@link-
 *         intersystems.com]</a>
 * @since 1.0.0.0
 */
class MethodTypeTransformer implements Transformer, Serializable {

    /**
     *
     */
    private static final long serialVersionUID = -7766636718627804940L;

    /**
     * See class documentation.
     *
     * @param fieldType
     * @return
     */
    public static Transformer getInstance() {
        return new MethodTypeTransformer();
    }

    /**
     * {@inheritDoc} Transforms a {@link Method} into it's return type.
     *
     * @since 1.0.0.0
     */
    public Object transform(Object input) {
        Method method = (Method) input;
        return method.getReturnType();
    }

}

/**
 * A {@link Transformer} that transforms a {@link Field} into it's type.
 *
 * @author Ren Link <a
 *         href="mailto:rene.link@link-intersystems.com">[rene.link@link-
 *         intersystems.com]</a>
 * @since 1.0.0.0
 */
class FieldTypeTransformer implements Transformer, Serializable {

    /**
     *
     */
    private static final long serialVersionUID = -5506590991172237537L;

    /**
     * See class documentation.
     *
     * @param fieldType
     * @return
     * @since 1.0.0.0
     */
    public static Transformer getInstance() {
        return new FieldTypeTransformer();
    }

    /**
     * {@inheritDoc}
     *
     * @param input
     *            must be a {@link Field}.
     * @since 1.0.0.0
     */
    public Object transform(Object input) {
        Field field = (Field) input;
        Class<?> type = field.getType();
        return type;
    }

}

/**
 * {@link Predicate} that evaluates to true if the {@link Member}'s name it is
 * evaluated against matches a given {@link Pattern}.
 *
 * @author Ren Link <a
 *         href="mailto:rene.link@link-intersystems.com">[rene.link@link-
 *         intersystems.com]</a>
 * @since 1.0.0.0
 */
class MemberNamePatternPredicate implements Predicate, Serializable {

    /**
     *
     */
    private static final long serialVersionUID = 7433776975628507987L;

    private transient Matcher matcher;

    private final Pattern namePattern;

    /**
     * Constructs a {@link MemberNamePatternPredicate} with the given
     * {@link Pattern}.
     *
     * @param namePattern
     *            the {@link Pattern} to use when evaluating.
     * @since 1.0.0.0
     */
    public MemberNamePatternPredicate(Pattern namePattern) {
        Assert.notNull("namePattern", namePattern);
        this.namePattern = namePattern;
        matcher = namePattern.matcher("");
    }

    private Matcher getMatcher(String string) {
        if (matcher == null) {
            /**
             * In case of deserialization
             */
            matcher = namePattern.matcher(string);
        } else {
            matcher.reset(string);
        }
        return matcher;
    }

    /**
     * {@inheritDoc}
     *
     * @see MemberNamePatternPredicate class javadoc
     * @since 1.0.0.0
     */
    public boolean evaluate(Object object) {
        if (!Member.class.isInstance(object)) {
            throw new IllegalArgumentException(
                    MemberNamePatternPredicate.class.getSimpleName() + " can only handle " + Member.class);
        }
        Member member = (Member) object;
        String memberName = member.getName();
        Matcher matcher = getMatcher(memberName);
        return matcher.matches();
    }

}

/**
 * An {@link Predicate} that evaluates to true if the {@link Class} that this
 * {@link AssignablePredicate} was constructed with is assignable from the class
 * that it is evaluated against.
 *
 * @author Ren Link <a
 *         href="mailto:rene.link@link-intersystems.com">[rene.link@link-
 *         intersystems.com]</a>
 * @since 1.0.0.0
 */
class AssignablePredicate implements Predicate, Serializable {

    /**
     *
     */
    private static final long serialVersionUID = 8619979013477832617L;

    private final Class<?> clazz;

    public static Predicate getInstance(Class<?> clazz) {
        return new AssignablePredicate(clazz);
    }

    /**
     * Constructs a new {@link AssignablePredicate} that evaluates to true if
     * the given class is assignable from the class it is evaluated against.
     *
     * @param clazz
     * @since 1.0.0.0
     */
    public AssignablePredicate(Class<?> clazz) {
        Assert.notNull("clazz", clazz);
        this.clazz = clazz;
    }

    /**
     * {@inheritDoc}
     *
     * @param object
     *            must be a {@link Class}. Other objects always evaluate to
     *            false.
     * @since 1.0.0.0
     */
    public boolean evaluate(Object object) {
        boolean isAssignable = false;
        Class<?> class2Compare = null;

        if (object instanceof Class<?>) {
            class2Compare = Class.class.cast(object);
        }

        if (class2Compare == null && object != null) {
            class2Compare = object.getClass();
        }

        if (class2Compare != null) {
            isAssignable = clazz.isAssignableFrom(class2Compare);
        }

        return isAssignable;
    }

}

/**
 * Compares two {@link Class}es by their canonical name.
 *
 * @author Ren Link <a
 *         href="mailto:rene.link@link-intersystems.com">[rene.link@link-
 *         intersystems.com]</a>
 * @since 1.0.0.0
 */
class CanonicalClassNameComparator implements Comparator<Class<?>>, Serializable {

    /**
     *
     */
    private static final long serialVersionUID = 1112739163768529278L;

    /**
     * A singleton of the {@link CanonicalClassNameComparator}.
     *
     * @since 1.0.0.0
     */
    public static final Comparator<Class<?>> INSTANCE = new CanonicalClassNameComparator();

    /**
     * {@inheritDoc}
     * <p>
     * Compares two {@link Class}es by their canonical name.
     * </p>
     *
     * @since 1.0.0.0
     */
    public int compare(Class<?> o1, Class<?> o2) {
        int compareValue = 0;
        if (o1 == null) {
            if (o2 == null) {
                compareValue = 0;
            } else {
                compareValue = -1;
            }
        } else {
            if (o2 == null) {
                compareValue = 1;
            } else {
                String canonicalName1 = o1.getCanonicalName();
                String canonicalName2 = o2.getCanonicalName();
                compareValue = canonicalName1.compareTo(canonicalName2);
            }
        }
        return compareValue;
    }

}

class SerializablePredicate<T> implements Predicate<T>, Serializable {

    /**
     *
     */
    private static final long serialVersionUID = 6679937464429440905L;

    private SerializableReference<Predicate<T>> serializablePredicate;

    public SerializablePredicate(SerializableReference<Predicate<T>> serializablePredicate) {
        Assert.notNull("serializablePredicate", serializablePredicate);
        this.serializablePredicate = serializablePredicate;
    }

    public boolean evaluate(T object) {
        Predicate<T> predicate = serializablePredicate.get();
        boolean result = predicate.evaluate(object);
        return result;
    }
}