/*
* 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.internal.reflect;
import java.beans.Introspector;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.util.Collection;
/**
* Distinguishes "get" getters, "is" getters and setters from non-property methods.
*
* Generally follows the JavaBean conventions, with 2 exceptions: is methods can return `Boolean` (in addition to `boolean`) and setter methods can return non-void values.
*
* This is essentially a superset of the conventions supported by Java, Groovy and Kotlin.
*/
public enum PropertyAccessorType {
IS_GETTER(2) {
@Override
public Type propertyTypeFor(Method method) {
return method.getGenericReturnType();
}
},
GET_GETTER(3) {
@Override
public Type propertyTypeFor(Method method) {
return method.getGenericReturnType();
}
},
SETTER(3) {
@Override
public Type propertyTypeFor(Method method) {
Type[] parameterTypes = method.getGenericParameterTypes();
if (parameterTypes.length != 1) {
throw new IllegalArgumentException("Setter method should take one parameter: " + method);
}
return parameterTypes[0];
}
};
private final int prefixLength;
PropertyAccessorType(int prefixLength) {
this.prefixLength = prefixLength;
}
public String propertyNameFor(Method method) {
return propertyNameFor(method.getName());
}
public String propertyNameFor(String methodName) {
String methodNamePrefixRemoved = methodName.substring(prefixLength);
return Introspector.decapitalize(methodNamePrefixRemoved);
}
abstract public Type propertyTypeFor(Method method);
public static PropertyAccessorType of(Method method) {
if (isStatic(method)) {
return null;
}
String methodName = method.getName();
if (!hasVoidReturnType(method) && takesNoParameter(method)) {
if (isGetGetterName(methodName)) {
return GET_GETTER;
}
// is method that returns Boolean is not a getter according to JavaBeans, but include it for compatibility with Groovy
if (isIsGetterName(methodName) && (method.getReturnType().equals(Boolean.TYPE) || method.getReturnType().equals(Boolean.class))) {
return IS_GETTER;
}
}
if (takesSingleParameter(method) && isSetterName(methodName)) {
return SETTER;
}
return null;
}
public static PropertyAccessorType fromName(String methodName) {
if (isGetGetterName(methodName)) {
return GET_GETTER;
}
if (isIsGetterName(methodName)) {
return IS_GETTER;
}
if (isSetterName(methodName)) {
return SETTER;
}
return null;
}
private static boolean isStatic(Method method) {
return Modifier.isStatic(method.getModifiers());
}
public static boolean hasVoidReturnType(Method method) {
return void.class.equals(method.getReturnType());
}
public static boolean takesNoParameter(Method method) {
return method.getParameterTypes().length == 0;
}
public static boolean takesSingleParameter(Method method) {
return method.getParameterTypes().length == 1;
}
private static boolean isGetGetterName(String methodName) {
return methodName.startsWith("get") && methodName.length() > 3;
}
private static boolean isIsGetterName(String methodName) {
return methodName.startsWith("is") && methodName.length() > 2;
}
private static boolean isSetterName(String methodName) {
return methodName.startsWith("set") && methodName.length() > 3;
}
public static boolean hasGetter(Collection<PropertyAccessorType> accessorTypes) {
return accessorTypes.contains(GET_GETTER) || accessorTypes.contains(IS_GETTER);
}
public static boolean hasSetter(Collection<PropertyAccessorType> accessorTypes) {
return accessorTypes.contains(SETTER);
}
}