/*
* 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 com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.gradle.internal.Cast;
import org.gradle.internal.reflect.PropertyAccessorType;
import org.gradle.model.internal.asm.AsmClassGeneratorUtils;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Proxy;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
public class PropertyAccessorExtractionContext {
private final PropertyAccessorType accessorType;
private final Collection<Method> declaringMethods;
private final Method mostSpecificDeclaration;
private final String mostSpecificSignature;
private final boolean declaredInManagedType;
private final boolean declaredAsAbstract;
private final Map<Class<? extends Annotation>, Annotation> annotations;
public PropertyAccessorExtractionContext(PropertyAccessorType accessorType, Iterable<Method> declaringMethods) {
Method mostSpecificDeclaration = ModelSchemaUtils.findMostSpecificMethod(declaringMethods);
this.accessorType = accessorType;
this.declaringMethods = ImmutableList.copyOf(declaringMethods);
this.mostSpecificDeclaration = mostSpecificDeclaration;
this.mostSpecificSignature = AsmClassGeneratorUtils.signature(mostSpecificDeclaration);
this.declaredInManagedType = ModelSchemaUtils.isMethodDeclaredInManagedType(declaringMethods);
this.declaredAsAbstract = Modifier.isAbstract(this.mostSpecificDeclaration.getModifiers());
this.annotations = collectAnnotations(declaringMethods);
}
private Map<Class<? extends Annotation>, Annotation> collectAnnotations(Iterable<Method> methods) {
Map<Class<? extends Annotation>, Annotation> annotations = Maps.newLinkedHashMap();
for (Method method : methods) {
for (Annotation annotation : method.getDeclaredAnnotations()) {
// Make sure more specific annotation doesn't get overwritten with less specific one
if (!annotations.containsKey(annotation.annotationType())) {
annotations.put(annotation.annotationType(), annotation);
}
}
}
return Collections.unmodifiableMap(annotations);
}
public PropertyAccessorType getAccessorType() {
return accessorType;
}
public Collection<Method> getDeclaringMethods() {
return declaringMethods;
}
public Method getMostSpecificDeclaration() {
return mostSpecificDeclaration;
}
public String getMostSpecificSignature() {
return mostSpecificSignature;
}
public boolean isDeclaredInManagedType() {
return declaredInManagedType;
}
public boolean isDeclaredAsAbstract() {
return declaredAsAbstract;
}
public boolean isAnnotationPresent(Class<? extends Annotation> annotationType) {
return annotations.containsKey(annotationType);
}
public <A extends Annotation> A getAnnotation(Class<A> annotationType) {
return Cast.uncheckedCast(annotations.get(annotationType));
}
public Collection<Annotation> getAnnotations() {
return annotations.values();
}
public List<Method> getGetters() {
List<Method> getters;
if (mostSpecificDeclaration.getReturnType()==Boolean.TYPE) {
getters = Lists.newArrayList();
for (Method getter : declaringMethods) {
if (Proxy.isProxyClass(getter.getDeclaringClass())) {
continue;
}
getters.add(getter);
}
} else {
getters = Collections.singletonList(mostSpecificDeclaration);
}
return getters;
}
@Override
public String toString() {
return String.format("%s.%s()/%s", mostSpecificDeclaration.getDeclaringClass().getSimpleName(), mostSpecificDeclaration.getName(), accessorType);
}
}