| // 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); |
| } |
| }); |
| } |
| } |
| } |
| } |