001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018package org.apache.commons.proxy2.impl;
019
020import java.lang.reflect.Method;
021import java.lang.reflect.Modifier;
022import java.util.Collection;
023import java.util.HashMap;
024import java.util.HashSet;
025import java.util.Map;
026import java.util.Set;
027
028/**
029 * A useful superclass for {@link ProxyClassGenerator} implementations.
030 * 
031 * @since 1.0
032 */
033public abstract class AbstractProxyClassGenerator implements ProxyClassGenerator
034{
035    //******************************************************************************************************************
036    // Static Methods
037    //******************************************************************************************************************
038
039    /**
040     * Returns all methods that a proxy class must implement from the proxy interfaces. This method makes sure there are
041     * no method signature clashes. For methods with the same signature (name and parameter types), the one encountered
042     * first will be returned in the result. Final methods are also excluded from the result.
043     * 
044     * @param proxyClasses
045     *            the interfaces the proxy class must implement
046     * @return all methods that the proxy class must implement
047     */
048    public static Method[] getImplementationMethods(Class<?>[] proxyClasses)
049    {
050        final Map<MethodSignature, Method> signatureMethodMap = new HashMap<MethodSignature, Method>();
051        final Set<MethodSignature> finalizedSignatures = new HashSet<MethodSignature>();
052        for (int i = 0; i < proxyClasses.length; i++)
053        {
054            Class<?> proxyInterface = proxyClasses[i];
055            final Method[] methods = proxyInterface.getMethods();
056            for (int j = 0; j < methods.length; j++)
057            {
058                final MethodSignature signature = new MethodSignature(methods[j]);
059                if (Modifier.isFinal(methods[j].getModifiers()))
060                {
061                    finalizedSignatures.add(signature);
062                }
063                else if (!signatureMethodMap.containsKey(signature))
064                {
065                    signatureMethodMap.put(signature, methods[j]);
066                }
067            }
068        }
069        final Collection<Method> resultingMethods = signatureMethodMap.values();
070        for (MethodSignature signature : finalizedSignatures)
071        {
072            resultingMethods.remove(signatureMethodMap.get(signature));
073        }
074        return resultingMethods.toArray(new Method[resultingMethods.size()]);
075    }
076}