in core/src/main/java/com/alibaba/fastjson2/util/BeanUtils.java [924:1131]
public static void getters(Class objectClass, Class mixinSource, boolean kotlin, Consumer<Method> methodConsumer) {
if (objectClass == null) {
return;
}
if (Proxy.isProxyClass(objectClass)) {
Class[] interfaces = objectClass.getInterfaces();
if (interfaces.length == 1) {
getters(interfaces[0], methodConsumer);
return;
}
}
if (ignore(objectClass)) {
return;
}
Class superClass = objectClass.getSuperclass();
if (TypeUtils.isProxy(objectClass)) {
getters(superClass, methodConsumer);
return;
}
boolean record = isRecord(objectClass);
boolean jdbcStruct = JdbcSupport.isStruct(objectClass);
String[] recordFieldNames = null;
if (record) {
recordFieldNames = getRecordFieldNames(objectClass);
}
Method[] methods = methodCache.get(objectClass);
if (methods == null) {
methods = getMethods(objectClass);
methodCache.putIfAbsent(objectClass, methods);
}
boolean protobufMessageV3 = superClass != null && "com.google.protobuf.GeneratedMessageV3".equals(superClass.getName());
for (Method method : methods) {
int paramType = method.getParameterCount();
if (paramType != 0) {
continue;
}
int mods = method.getModifiers();
if (Modifier.isStatic(mods)) {
continue;
}
Class<?> returnClass = method.getReturnType();
if (returnClass == Void.class || returnClass == void.class || ignore(returnClass)) {
continue;
}
Class<?> declaringClass = method.getDeclaringClass();
if (declaringClass == Enum.class || declaringClass == Object.class) {
continue;
}
String methodName = method.getName();
if (jdbcStruct) {
if (!"getSQLTypeName".equals(methodName) && !"getAttributes".equals(methodName)) {
continue;
}
}
boolean methodSkip = false;
switch (methodName) {
case "isInitialized":
case "getInitializationErrorString":
case "getSerializedSize":
if (protobufMessageV3) {
methodSkip = true;
}
break;
case "equals":
case "hashCode":
case "toString":
methodSkip = true;
break;
default:
break;
}
if (methodSkip) {
continue;
}
if (protobufMessageV3) {
if ((methodName.endsWith("Type") || methodName.endsWith("Bytes"))
&& "com.google.protobuf.ByteString".equals(returnClass.getName())) {
continue;
}
}
// skip thrift isSetXXX
if (methodName.startsWith("isSet") && returnClass == boolean.class) {
boolean setterFound = false, unsetFound = false, getterFound = false;
String setterName = BeanUtils.getterName(methodName, null);
String getterName = "g" + setterName.substring(1);
String unsetName = "un" + setterName;
for (Method m : methods) {
if (m.getName().equals(setterName)
&& m.getParameterCount() == 1
&& m.getReturnType() == void.class) {
setterFound = true;
} else if (m.getName().equals(getterName)
&& m.getParameterCount() == 0) {
getterFound = true;
} else if (m.getName().equals(unsetName)
&& m.getParameterCount() == 0
&& m.getReturnType() == void.class) {
unsetFound = true;
}
}
if (setterFound && unsetFound && getterFound
&& findAnnotation(method, JSONField.class) == null) {
continue;
}
}
if (record) {
boolean match = false;
for (String recordFieldName : recordFieldNames) {
if (methodName.equals(recordFieldName)) {
match = true;
break;
}
}
if (match) {
methodConsumer.accept(method);
continue;
}
}
final int methodNameLength = methodName.length();
boolean nameMatch = methodNameLength > 3 && methodName.startsWith("get");
if (nameMatch) {
char firstChar = methodName.charAt(3);
if (firstChar >= 'a' && firstChar <= 'z' && methodNameLength == 4) {
nameMatch = false;
}
} else if (returnClass == boolean.class || returnClass == Boolean.class || kotlin) {
nameMatch = methodNameLength > 2 && methodName.startsWith("is");
if (nameMatch) {
char firstChar = methodName.charAt(2);
if (firstChar >= 'a' && firstChar <= 'z' && methodNameLength == 3) {
nameMatch = false;
}
}
}
if (!nameMatch) {
if (isJSONField(method)) {
nameMatch = true;
}
}
if (!nameMatch && mixinSource != null) {
Method mixinMethod = getMethod(mixinSource, method);
if (mixinMethod != null) {
if (isJSONField(mixinMethod)) {
nameMatch = true;
}
}
}
if (!nameMatch
&& objectClass != returnClass
&& (!methodName.startsWith("build"))
&& fluentSetter(objectClass, methodName, returnClass) != null) {
nameMatch = true;
}
if (!nameMatch) {
continue;
}
if (protobufMessageV3) {
if (method.getDeclaringClass() == superClass) {
continue;
}
Class<?> returnType = method.getReturnType();
boolean ignore = false;
switch (methodName) {
case "getUnknownFields":
case "getSerializedSize":
case "getParserForType":
case "getMessageBytes":
case "getDefaultInstanceForType":
ignore = returnType.getName().startsWith("com.google.protobuf.") || returnType == objectClass;
break;
default:
break;
}
if (ignore) {
continue;
}
}
methodConsumer.accept(method);
}
}