/*
 * Copyright 2015 the original author or authors.
 *
 * 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 org.gradle.model.internal.manage.schema.extract;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Collection;

public class PropertyAccessorExtractionContext {
    private final Collection<Method> declaringMethods;
    private final Method mostSpecificDeclaration;
    private final boolean declaredInManagedType;
    private final boolean declaredAsAbstract;

    public PropertyAccessorExtractionContext(Collection<Method> declaringMethods) {
        this(declaringMethods, ModelSchemaUtils.isMethodDeclaredInManagedType(declaringMethods));
    }

    public PropertyAccessorExtractionContext(Collection<Method> declaringMethods, boolean declaredInManagedType) {
        this.declaringMethods = declaringMethods;
        this.mostSpecificDeclaration = declaringMethods.iterator().next();
        this.declaredInManagedType = declaredInManagedType;
        this.declaredAsAbstract = Modifier.isAbstract(this.mostSpecificDeclaration.getModifiers());
    }

    public Collection<Method> getDeclaringMethods() {
        return declaringMethods;
    }

    public Method getMostSpecificDeclaration() {
        return mostSpecificDeclaration;
    }

    public boolean isDeclaredInManagedType() {
        return declaredInManagedType;
    }

    public boolean isDeclaredAsAbstract() {
        return declaredAsAbstract;
    }
}

@@ -668,16 +668,60 @@
 tract;%0A%0A
+import java.lang.reflect.InvocationHandler;%0A
 import j
@@ -776,24 +776,56 @@
 t.Modifier;%0A
+import java.lang.reflect.Proxy;%0A
 import java.
@@ -1489,41 +1489,47 @@
 n = 
-declaringMethods.iterator().next(
+findMostSpecificMethod(declaringMethods
 );%0A 
@@ -1686,32 +1686,1210 @@
 iers());%0A    %7D%0A%0A
+    /**%0A     * Tries to find the most specific declaration of a method that is not declared in a %7B@link Proxy%7D class.%0A     * Mock objects generated via %7B@link Proxy#newProxyInstance(ClassLoader, Class%5B%5D, InvocationHandler)%7D%0A     * lose their generic type parameters and can confuse schema extraction. This way we can ignore these%0A     * declarations, and use the ones from the proxied interfaces instead.%0A     *%0A     * @param method declarations of the same method from different types in the type hierarchy. They are%0A     *      expected to be in order of specificity, i.e. overrides preceding overridden declarations.%0A     * @return the most specific declaration of the method.%0A     * @throws IllegalArgumentException if no declaration can be found.%0A     */%0A    private static Method findMostSpecificMethod(Collection%3CMethod%3E declaringMethods) %7B%0A        for (Method method : declaringMethods) %7B%0A            if (Proxy.isProxyClass(method.getDeclaringClass())) %7B%0A                continue;%0A            %7D%0A            return method;%0A        %7D%0A        throw new IllegalArgumentException(%22No non-proxy declaration of method found. Declarations checked: %22 + declaringMethods);%0A    %7D%0A%0A
     public Colle

Fix for proxied mock objects losing their type parameters