| /* |
| * Copyright 2017 HugeGraph Authors |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with this |
| * work for additional information regarding copyright ownership. The ASF |
| * licenses this file to You under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| * License for the specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| package com.baidu.hugegraph.testutil; |
| |
| import java.lang.reflect.Field; |
| import java.lang.reflect.InvocationTargetException; |
| import java.lang.reflect.Method; |
| import java.util.Arrays; |
| import java.util.Objects; |
| |
| import com.baidu.hugegraph.util.E; |
| import com.google.common.primitives.Primitives; |
| |
| public class Whitebox { |
| |
| public static final char SEPARATOR = '.'; |
| |
| public static void setInternalState(Object target, |
| String fieldName, Object value) { |
| assert target != null; |
| assert fieldName != null; |
| int sep = fieldName.lastIndexOf(SEPARATOR); |
| if (sep > 0) { |
| String prefix = fieldName.substring(0, sep); |
| Object result = getInternalState(target, prefix); |
| E.checkArgument(result != null, |
| "Can't set value on null field: `%s.%s`", |
| target, prefix); |
| target = result; |
| fieldName = fieldName.substring(sep + 1); |
| } |
| |
| Class<?> c = target instanceof Class<?> ? |
| (Class<?>) target : target.getClass(); |
| try { |
| Field f = getFieldFromHierarchy(c, fieldName); |
| f.setAccessible(true); |
| f.set(target, value); |
| } catch (Exception e) { |
| throw new RuntimeException(String.format( |
| "Can't set value of '%s' against object '%s'", |
| fieldName, target), e); |
| } |
| } |
| |
| public static <T> T getInternalState(Object target, String fieldName) { |
| assert fieldName != null; |
| int sep = fieldName.indexOf(SEPARATOR); |
| if (sep > 0) { |
| String field = fieldName.substring(0, sep); |
| Object value = getInternalState(target, field); |
| field = fieldName.substring(sep + 1); |
| return getInternalState(value, field); |
| } |
| |
| Class<?> c = target instanceof Class<?> ? |
| (Class<?>) target : target.getClass(); |
| try { |
| Field f = getFieldFromHierarchy(c, fieldName); |
| f.setAccessible(true); |
| @SuppressWarnings("unchecked") |
| T result = (T) f.get(target); |
| return result; |
| } catch (Exception e) { |
| throw new RuntimeException(String.format( |
| "Unable to get internal state on field '%s' of %s", |
| fieldName, target), e); |
| } |
| } |
| |
| private static Field getFieldFromHierarchy(Class<?> clazz, String field) { |
| Field f = getField(clazz, field); |
| while (f == null && clazz != Object.class) { |
| clazz = clazz.getSuperclass(); |
| f = getField(clazz, field); |
| } |
| if (f == null) { |
| throw new RuntimeException(String.format( |
| "Not declared field '%s' in class '%s'", |
| field, clazz.getSimpleName())); |
| } |
| return f; |
| } |
| |
| private static Field getField(Class<?> clazz, String field) { |
| try { |
| return clazz.getDeclaredField(field); |
| } catch (NoSuchFieldException e) { |
| return null; |
| } |
| } |
| |
| public static <T> T invokeStatic(Class<?> clazz, String methodName, |
| Object... args) { |
| return invoke(clazz, methodName, (Object) null, args); |
| } |
| |
| public static <T> T invokeStatic(Class<?> clazz, Class<?>[] classes, |
| String methodName, Object... args) { |
| return invoke(clazz, classes, methodName, (Object) null, args); |
| } |
| |
| public static <T> T invoke(Object owner, String field, |
| String methodName, Object... args) { |
| Object self = getInternalState(owner, field); |
| Objects.requireNonNull(self); |
| return invoke(self.getClass(), methodName, self, args); |
| } |
| |
| public static <T> T invoke(Object owner, String field, Class<?>[] classes, |
| String methodName, Object... args) { |
| Object self = getInternalState(owner, field); |
| Objects.requireNonNull(self); |
| return invoke(self.getClass(), classes, methodName, self, args); |
| } |
| |
| public static <T> T invoke(Class<?> clazz, String methodName, |
| Object self, Object... args) { |
| Class<?>[] classes = new Class<?>[args.length]; |
| int i = 0; |
| for (Object arg : args) { |
| E.checkArgument(arg != null, "The argument can't be null"); |
| classes[i++] = Primitives.unwrap(arg.getClass()); |
| } |
| return invoke(clazz, classes, methodName, self, args); |
| } |
| |
| public static <T> T invoke(Class<?> clazz, Class<?>[] classes, |
| String methodName, Object self, Object... args) { |
| Method method = method(clazz, methodName, classes); |
| try { |
| method.setAccessible(true); |
| @SuppressWarnings("unchecked") |
| T result = (T) method.invoke(self, args); |
| return result; |
| } catch (IllegalAccessException e) { |
| throw new RuntimeException(String.format( |
| "Can't invoke method '%s' of class '%s': %s", |
| methodName, clazz, e.getMessage()), e); |
| } catch (InvocationTargetException e) { |
| Throwable target = e.getTargetException(); |
| if (target instanceof RuntimeException) { |
| throw (RuntimeException) target; |
| } |
| throw new RuntimeException(String.format( |
| "Can't invoke method '%s' of class '%s': %s", |
| methodName, clazz, target.getMessage()), target); |
| } |
| } |
| |
| public static Method method(Class<?> clazz, String methodName, |
| Class<?>[] argsClasses) { |
| try { |
| return clazz.getDeclaredMethod(methodName, argsClasses); |
| } catch (NoSuchMethodException e) { |
| Class<?> superclass = clazz.getSuperclass(); |
| if (superclass != null) { |
| try { |
| return method(superclass, methodName, argsClasses); |
| } catch (Exception ignored) { |
| // pass |
| } |
| } |
| throw new RuntimeException(String.format( |
| "Can't find method '%s' with args %s of class '%s'", |
| methodName, Arrays.asList(argsClasses), clazz), e); |
| } |
| } |
| } |