in firebase-database/src/main/java/com/google/firebase/database/core/utilities/encoding/CustomClassMapper.java [452:550]
public BeanMapper(Class<T> clazz) {
this.clazz = clazz;
this.throwOnUnknownProperties = clazz.isAnnotationPresent(ThrowOnExtraProperties.class);
this.warnOnUnknownProperties = !clazz.isAnnotationPresent(IgnoreExtraProperties.class);
this.properties = new HashMap<>();
this.setters = new HashMap<>();
this.getters = new HashMap<>();
this.fields = new HashMap<>();
Constructor<T> constructor = null;
try {
constructor = clazz.getDeclaredConstructor();
constructor.setAccessible(true);
} catch (NoSuchMethodException e) {
// We will only fail at deserialization time if no constructor is present
constructor = null;
}
this.constructor = constructor;
// Add any public getters to properties (including isXyz())
for (Method method : clazz.getMethods()) {
if (shouldIncludeGetter(method)) {
String propertyName = propertyName(method);
addProperty(propertyName);
method.setAccessible(true);
if (getters.containsKey(propertyName)) {
throw new DatabaseException("Found conflicting getters for name: " + method.getName());
}
getters.put(propertyName, method);
}
}
// Add any public fields to properties
for (Field field : clazz.getFields()) {
if (shouldIncludeField(field)) {
String propertyName = propertyName(field);
addProperty(propertyName);
}
}
// We can use private setters and fields for known (public) properties/getters. Since
// getMethods/getFields only returns public methods/fields we need to traverse the
// class hierarchy to find the appropriate setter or field.
Class<? super T> currentClass = clazz;
do {
// Add any setters
for (Method method : currentClass.getDeclaredMethods()) {
if (shouldIncludeSetter(method)) {
String propertyName = propertyName(method);
String existingPropertyName = properties.get(propertyName.toLowerCase(Locale.US));
if (existingPropertyName != null) {
if (!existingPropertyName.equals(propertyName)) {
throw new DatabaseException(
"Found setter with invalid " + "case-sensitive name: " + method.getName());
} else {
Method existingSetter = setters.get(propertyName);
if (existingSetter == null) {
method.setAccessible(true);
setters.put(propertyName, method);
} else if (!isSetterOverride(method, existingSetter)) {
// We require that setters with conflicting property names are
// overrides from a base class
throw new DatabaseException(
"Found a conflicting setters "
+ "with name: "
+ method.getName()
+ " (conflicts with "
+ existingSetter.getName()
+ " defined on "
+ existingSetter.getDeclaringClass().getName()
+ ")");
}
}
}
}
}
for (Field field : currentClass.getDeclaredFields()) {
String propertyName = propertyName(field);
// Case sensitivity is checked at deserialization time
// Fields are only added if they don't exist on a subclass
if (properties.containsKey(propertyName.toLowerCase(Locale.US))
&& !fields.containsKey(propertyName)) {
field.setAccessible(true);
fields.put(propertyName, field);
}
}
// Traverse class hierarchy until we reach java.lang.Object which contains a bunch
// of fields/getters we don't want to serialize
currentClass = currentClass.getSuperclass();
} while (currentClass != null && !currentClass.equals(Object.class));
if (properties.isEmpty()) {
throw new DatabaseException("No properties to serialize found on class " + clazz.getName());
}
}