com.swtxml.util.reflector.MethodQuery.java Source code

Java tutorial

Introduction

Here is the source code for com.swtxml.util.reflector.MethodQuery.java

Source

/*******************************************************************************
 * Copyright (c) 2008 Ralf Ebert
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     Ralf Ebert - initial API and implementation
 *******************************************************************************/
package com.swtxml.util.reflector;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.ObjectUtils;
import org.eclipse.core.runtime.Assert;

import com.swtxml.util.lang.CollectionUtils;
import com.swtxml.util.lang.Filters;
import com.swtxml.util.lang.IFilter;

public class MethodQuery {

    private Visibility visibility;
    private Subclasses subclasses;
    private List<IFilter<Method>> filters = new ArrayList<IFilter<Method>>();

    private static class AnyType {

    }

    public static final Class<?> ANY_TYPE = AnyType.class;

    MethodQuery(Visibility visibility, Subclasses subclasses) {
        this.visibility = visibility;
        this.subclasses = subclasses;
    }

    private Collection<Method> getMethods(Class<?> type) {
        if (visibility == Visibility.PUBLIC && subclasses == Subclasses.INCLUDE) {
            return Arrays.asList(type.getMethods());
        } else if (visibility == Visibility.PRIVATE && subclasses == Subclasses.INCLUDE) {
            return getAllMethods(type);
        }
        throw new UnsupportedOperationException(
                "Querying with " + visibility + " and " + subclasses + " not supported at the moment.");
    };

    public MethodQuery nameStartsWith(final String str) {
        filters.add(new IFilter<Method>() {
            public boolean match(Method method) {
                return method.getName().startsWith(str);
            }

            @Override
            public String toString() {
                return "name starts with \"" + str + "\"";
            }
        });
        return this;
    }

    public MethodQuery nameMatches(final String regex) {
        filters.add(new IFilter<Method>() {
            public boolean match(Method method) {
                return method.getName().matches(regex);
            }

            @Override
            public String toString() {
                return "name matches \"" + regex + "\"";
            }
        });
        return this;
    }

    public MethodQuery parameters(final Class<?>... signature) {
        filters.add(new IFilter<Method>() {
            public boolean match(Method method) {
                if (method.getParameterTypes().length != signature.length) {
                    return false;
                }
                for (int i = 0; i < signature.length; i++) {
                    if (AnyType.class.isAssignableFrom(signature[i])) {
                        continue;
                    } else if (!signature[i].isAssignableFrom(method.getParameterTypes()[i])) {
                        return false;
                    }
                }
                return true;
            }

            @Override
            public String toString() {
                return "parameters=\"" + Arrays.toString(signature) + "\"";
            }
        });
        return this;
    }

    public Collection<Method> all(Class<?> type) {
        return CollectionUtils.select(getMethods(type), getFilter());
    }

    private IFilter<Method> getFilter() {
        return Filters.and(filters);
    }

    public MethodQuery name(final String name) {
        filters.add(new IFilter<Method>() {
            public boolean match(Method method) {
                return method.getName().equals(name);
            }

            @Override
            public String toString() {
                return "name=\"" + name + "\"";
            }
        });
        return this;
    }

    public Method exactOne(Class<?> type) {
        Collection<Method> results = all(type);
        if (results.size() == 1) {
            return results.iterator().next();
        } else if (results.isEmpty()) {
            throw new ReflectorException("No method " + getFilter() + " found in " + type + "!");
        } else {
            throw new ReflectorException(
                    "Ambiguous methods found for " + getFilter() + " in " + type + ": " + results);
        }
    }

    public MethodQuery optionalParameter(final Class<?> type) {
        Assert.isNotNull(type, "type");
        filters.add(new IFilter<Method>() {
            public boolean match(Method method) {
                return method.getParameterTypes().length == 0
                        || (method.getParameterTypes().length == 1 && type == method.getParameterTypes()[0]);

            }

            @Override
            public String toString() {
                return "optional parameter \"" + type.getSimpleName() + "\"";
            }
        });
        return this;
    }

    public MethodQuery returnType(final Class<?> type) {
        filters.add(new IFilter<Method>() {
            public boolean match(Method method) {
                return ObjectUtils.equals(type, method.getReturnType());
            }

            @Override
            public String toString() {
                return "return type \"" + (type != null ? type.getSimpleName() : "null") + "\"";
            }
        });
        return this;
    }

    /**
     * Same as Class.getMethods() but with private methods included. Returns all
     * methods of <type> and its superclasses, overwritten superclass methods
     * are not included.
     */
    private Collection<Method> getAllMethods(Class<?> type) {
        Map<String, Method> signatureToMethod = new HashMap<String, Method>();
        while (type != null) {
            for (Method method : type.getDeclaredMethods()) {
                if (method.isBridge() || method.isSynthetic()) {
                    continue;
                }

                String signature = getSignature(method);
                if (!signatureToMethod.containsKey(signature)) {
                    signatureToMethod.put(signature, method);
                }
            }
            type = type.getSuperclass();
        }

        return signatureToMethod.values();
    }

    private String getSignature(Method method) {
        StringBuffer s = new StringBuffer();
        s.append(method.getName());

        for (Class<?> param : method.getParameterTypes()) {
            s.append(':');
            s.append(param.getName());
        }

        return s.toString();
    }

}