blob: 5e1cdbea71d8903db5f5af18b92b40a697b0ce6d [file] [log] [blame]
// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.utils;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
public class ReflectionHelper {
@SuppressWarnings("unchecked")
public static <T> T performReflection(Object object, ReflectiveOperation<?> operation)
throws Exception {
return (T) operation.compute(object);
}
public static ReflectiveOperationSequenceBuilder builder() {
return new ReflectiveOperationSequenceBuilder();
}
public enum DeclaredType {
FIELD,
METHOD
}
public abstract static class ReflectiveOperation<Member> {
final Class<?> classForDeclaration;
final String declaredMember;
final Consumer<Member> modifier;
final ReflectiveOperation<?> nextOperation;
private ReflectiveOperation(
Class<?> classForDeclaration,
String declaredMember,
ReflectiveOperation<?> nextOperation,
Consumer<Member> modifier) {
this.classForDeclaration = classForDeclaration;
this.declaredMember = declaredMember;
this.nextOperation = nextOperation;
this.modifier = modifier;
}
public abstract Object compute(Object object) throws Exception;
}
public static class ReflectiveMethodOperation extends ReflectiveOperation<Method> {
private ReflectiveMethodOperation(
Class<?> classForDeclaration,
String declaredMember,
ReflectiveOperation<?> nextOperation,
Consumer<Method> modifier) {
super(classForDeclaration, declaredMember, nextOperation, modifier);
}
@Override
public Object compute(Object object) throws Exception {
Class<?> clazz = classForDeclaration == null ? object.getClass() : classForDeclaration;
Method declaredMethod = clazz.getDeclaredMethod(declaredMember);
modifier.accept(declaredMethod);
// The reflection helper do not support arguments at this point.
Object returnValue = declaredMethod.invoke(object);
return nextOperation != null ? nextOperation.compute(returnValue) : returnValue;
}
}
public static class ReflectiveFieldOperation extends ReflectiveOperation<Field> {
private ReflectiveFieldOperation(
Class<?> classForDeclaration,
String declaredMember,
ReflectiveOperation<?> nextOperation,
Consumer<Field> modifier) {
super(classForDeclaration, declaredMember, nextOperation, modifier);
}
@Override
public Object compute(Object object) throws Exception {
Class<?> clazz = classForDeclaration == null ? object.getClass() : classForDeclaration;
Field declaredField = clazz.getDeclaredField(declaredMember);
modifier.accept(declaredField);
Object fieldValue = declaredField.get(object);
return nextOperation != null ? nextOperation.compute(fieldValue) : fieldValue;
}
}
public static class ReflectiveOperationSequenceBuilder {
List<ReflectiveOperationBuilder> reflectiveOperationBuilderList = new ArrayList<>();
public ReflectiveOperationBuilder readMethod(String declaredMember) {
return add(declaredMember, DeclaredType.METHOD);
}
public ReflectiveOperationBuilder readField(String declaredMember) {
return add(declaredMember, DeclaredType.FIELD);
}
private ReflectiveOperationBuilder add(String declaredMember, DeclaredType declaredType) {
ReflectiveOperationBuilder reflectiveOperationBuilder =
new ReflectiveOperationBuilder(declaredMember, declaredType, this);
reflectiveOperationBuilderList.add(reflectiveOperationBuilder);
return reflectiveOperationBuilder;
}
public ReflectiveOperation<?> build() {
assert !reflectiveOperationBuilderList.isEmpty();
ReflectiveOperation<?> lastOperation = null;
for (int i = reflectiveOperationBuilderList.size() - 1; i >= 0; i--) {
lastOperation = reflectiveOperationBuilderList.get(i).build(lastOperation);
}
return lastOperation;
}
}
public static class ReflectiveOperationBuilder {
private final String declaredMember;
private final DeclaredType declaredType;
private boolean setAccessible = false;
private final ReflectiveOperationSequenceBuilder sequenceBuilder;
private ReflectiveOperationBuilder(
String declaredMember,
DeclaredType declaredType,
ReflectiveOperationSequenceBuilder sequenceBuilder) {
this.declaredMember = declaredMember;
this.declaredType = declaredType;
this.sequenceBuilder = sequenceBuilder;
}
public ReflectiveOperationBuilder setSetAccessible(boolean setAccessible) {
this.setAccessible = setAccessible;
return this;
}
public ReflectiveOperationSequenceBuilder done() {
return sequenceBuilder;
}
private ReflectiveOperation<?> build(ReflectiveOperation<?> nextOperation) {
if (declaredType == DeclaredType.FIELD) {
return new ReflectiveFieldOperation(
null,
declaredMember,
nextOperation,
field -> {
if (setAccessible) {
field.setAccessible(true);
}
});
} else {
assert declaredType == DeclaredType.METHOD;
return new ReflectiveMethodOperation(
null,
declaredMember,
nextOperation,
method -> {
if (setAccessible) {
method.setAccessible(true);
}
});
}
}
}
}