
io.github.imsejin.common.util.ReflectionUtils Maven / Gradle / Ivy
/*
* Copyright 2021 Sejin Im
*
* Licensed 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 io.github.imsejin.common.util;
import io.github.imsejin.common.annotation.ExcludeFromGeneratedJacocoReport;
import io.github.imsejin.common.assertion.Asserts;
import javax.annotation.Nullable;
import java.lang.reflect.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* Reflection utilities
*/
public final class ReflectionUtils {
@ExcludeFromGeneratedJacocoReport
private ReflectionUtils() {
throw new UnsupportedOperationException(getClass().getName() + " is not allowed to instantiate");
}
/**
* Gets fields of the type including its inherited fields.
*
* @param type type of the object
* @return inherited and own fields (non-static)
* @see Class#getDeclaredFields()
* @see Class#getSuperclass()
*/
public static List getInheritedFields(Class> type) {
Asserts.that(type).isNotNull();
List fields = new ArrayList<>();
for (Class> clazz = type; clazz != null; clazz = clazz.getSuperclass()) {
fields.addAll(0, Arrays.asList(clazz.getDeclaredFields()));
}
// Removes a instance of outer class when the type is non-static inner class.
if (!Modifier.isStatic(type.getModifiers()) && (type.isMemberClass() || type.isLocalClass())) {
fields.remove(0);
}
// Removes static fields from list.
fields.removeIf(it -> Modifier.isStatic(it.getModifiers()));
return fields;
}
/**
* Returns value of the field.
*
* @param instance instance if method is static, null
* @param field targeted field
* @return field value
* @throws RuntimeException if get value from the field
*/
@Nullable
public static Object getFieldValue(@Nullable Object instance, Field field) {
Asserts.that(field).isNotNull();
if (!Modifier.isStatic(field.getModifiers())) Asserts.that(instance).isNotNull();
// Enables to have access to the field even private field.
field.setAccessible(true);
try {
// Returns value in the field.
return field.get(instance);
} catch (IllegalAccessException e) {
String message = String.format("Failed to get value from the field(%s) of the class(%s)",
field.getName(), instance.getClass().getName());
throw new RuntimeException(message, e);
}
}
/**
* Sets up value into the field.
*
* @param instance instance if method is static, null
* @param field targeted field
* @param value value to be set into field
* @throws RuntimeException if failed to set value into the field
*/
public static void setFieldValue(@Nullable Object instance, Field field, Object value) {
Asserts.that(field).isNotNull();
if (!Modifier.isStatic(field.getModifiers())) Asserts.that(instance).isNotNull();
if (field.getType().isPrimitive()) Asserts.that(value)
.as("Value is not allowed to set null to primitive field: {0} <= null", field.getType())
.isNotNull();
// Enables to have access to the field even private field.
field.setAccessible(true);
// Sets value into the field.
try {
field.set(instance, value);
} catch (IllegalAccessException e) {
String message = String.format("Failed to set value into the field(%s) of the class(%s)",
field.getName(), instance.getClass().getName());
throw new RuntimeException(message, e);
}
}
/**
* Returns the specific constructor declared by given type.
*
* @param type class
* @param paramTypes parameter types of constructor
* @param type of instance
* @return constructor
*/
public static Constructor getDeclaredConstructor(Class type, @Nullable Class>... paramTypes) {
Asserts.that(type).isNotNull();
if (paramTypes != null) Asserts.that(paramTypes).doesNotContainNull();
try {
// Gets constructor with the specific parameter types.
return type.getDeclaredConstructor(paramTypes);
} catch (NoSuchMethodException e) {
String message = String.format("Cannot find a constructor: %s(%s)",
type, Arrays.toString(paramTypes).replaceAll("\\[|]", ""));
throw new RuntimeException(message, e);
}
}
/**
* Returns instance of type using default constructor.
*
* @param type class
* @param type of instance
* @return instance of type
* @throws RuntimeException if the type doesn't have default constructor
* @throws RuntimeException if failed to instantiate
*/
public static T instantiate(Class type) {
return instantiate(type, null, null);
}
/**
* Returns instance of type using the specific constructor.
*
* @param type class
* @param paramTypes parameter types of constructor
* @param initArgs initial arguments of constructor
* @param type of instance
* @return instance of type
* @throws RuntimeException if the type doesn't have default constructor
* @throws RuntimeException if failed to instantiate
*/
public static T instantiate(Class type, @Nullable Class>[] paramTypes, @Nullable Object[] initArgs) {
Asserts.that(type).isNotNull();
if (paramTypes != null) Asserts.that(paramTypes).doesNotContainNull().isSameLength(initArgs);
if (initArgs != null) Asserts.that(initArgs).isSameLength(paramTypes);
Constructor constructor;
try {
// Gets constructor with the specific parameter types.
constructor = type.getDeclaredConstructor(paramTypes);
} catch (NoSuchMethodException e) {
String message = String.format("Cannot find a constructor: %s(%s)",
type, Arrays.toString(paramTypes).replaceAll("\\[|]", ""));
throw new RuntimeException(message, e);
}
constructor.setAccessible(true);
// Instantiates new model and sets up data into the model's fields.
try {
return constructor.newInstance(initArgs);
} catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
String message = String.format("Failed to instantiate by constructor: %s(%s)",
type, Arrays.toString(paramTypes).replaceAll("\\[|]", ""));
throw new RuntimeException(message, e);
}
}
/**
* Returns the specific method declared by given type.
*
* @param type class
* @param methodName name of method
* @param paramTypes parameter types of method
* @return method
*/
public static Method getDeclaredMethod(Class> type, String methodName, @Nullable Class>... paramTypes) {
Asserts.that(type).isNotNull();
Asserts.that(methodName).isNotNull().hasText();
if (paramTypes != null) Asserts.that(paramTypes).doesNotContainNull();
try {
return type.getDeclaredMethod(methodName, paramTypes);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
}
}
/**
* Invokes the specific method and returns its result.
*
* @param type class
* @param instance instance if method is static, null
* @param methodName name of method
* @param paramTypes parameter types of method
* @param args arguments of method
* @return result of method
*/
public static Object invoke(Class> type, @Nullable Object instance,
String methodName, @Nullable Class>[] paramTypes, @Nullable Object[] args) {
Asserts.that(type).isNotNull();
Asserts.that(methodName).isNotNull().hasText();
if (paramTypes != null) Asserts.that(paramTypes).doesNotContainNull().isSameLength(args);
if (args != null) Asserts.that(args).isSameLength(paramTypes);
Method method;
try {
method = type.getDeclaredMethod(methodName, paramTypes);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
}
if (!Modifier.isStatic(method.getModifiers())) Asserts.that(instance).isNotNull();
method.setAccessible(true);
try {
return method.invoke(instance, args);
} catch (IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException(e);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy