@Override
public String translateName(Field f) {
// Determining if AutoValue is tough, since annotations are SOURCE retention.
if (Modifier.isAbstract(f.getDeclaringClass().getSuperclass().getModifiers())) { // AutoValue means abstract.
for (Invokable<?, ?> target : constructors(TypeToken.of(f.getDeclaringClass().getSuperclass()))) {
SerializedNames names = target.getAnnotation(SerializedNames.class);
if (names != null && target.isStatic()) { // == factory method
// Fields and constructor params are written by AutoValue in same order as methods are declared.
// By contract, SerializedNames factory methods must declare its names in the same order,
Field[] fields = f.getDeclaringClass().getDeclaredFields();
checkState(fields.length == names.value().length, "Incorrect number of names on " + names);
for (int i = 0; i < fields.length; i++) {
if (fields[i].equals(f)) {
return names.value()[i];
}
}
// The input field was not a declared field. Accidentally placed on something not AutoValue?
throw new IllegalStateException("Inconsistent state. Ensure type is AutoValue on " + target);
}