![JAR search and dependency download from the Maven repository](/logo.png)
org.araguacaima.commons.utils.ReflectionUtils Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of commons-utils Show documentation
Show all versions of commons-utils Show documentation
Common utilities is a set of java utilities for managing typical actions when working with enums,
files, exceptions, zip/jar files, classes (via Reflection), maps, numbers and so on.
Most of the utilities extend functionalities offered by amazing libraries such as:
* commons-beanutils (apache)
* commons-lang3 (apache)
* commons-io (apache)
* commons-math3 (apache)
* commons-collections4 (apache)
* jreversepro (akkumar)
/*
* Copyright 2017 araguacaima
*
* 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 org.araguacaima.commons.utils;
import com.google.common.collect.ObjectArrays;
import org.apache.commons.beanutils.PropertyUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import sun.reflect.ConstructorAccessor;
import sun.reflect.FieldAccessor;
import sun.reflect.ReflectionFactory;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.*;
import java.util.*;
@SuppressWarnings("unchecked")
@Component
public class ReflectionUtils {
private static final Logger log = LoggerFactory.getLogger(ReflectionUtils.class);
public final Collection COMMONS_JAVA_TYPES_EXCLUSIONS = new ArrayList() {
{
add("java.util.Currency");
add("java.util.Calendar");
add("org.joda.time.Period");
}
};
public final Collection COMMONS_TYPES_PREFIXES = new ArrayList() {
{
add("java.lang");
add("java.util");
add("java.math");
add("java.io");
add("java.sql");
add("java.text");
add("java.net");
add("org.joda.time");
}
};
private final Collection COMMONS_COLLECTIONS_IMPLEMENTATIONS = new ArrayList() {
{
add(ArrayList.class);
add(TreeSet.class);
add(HashSet.class);
add(LinkedHashSet.class);
add(LinkedList.class);
}
};
private final DataTypesConverter dataTypesConverter;
private final ReflectionFactory reflectionFactory = ReflectionFactory.getReflectionFactory();
@Autowired
public ReflectionUtils(DataTypesConverter dataTypesConverter) {
this.dataTypesConverter = dataTypesConverter;
}
/**
* Add an enum instance to the enum class given as argument
*
* @param the type of the enum (implicit)
* @param type the class of the enum to be modified
* @param name the name of the new enum instance to be added to the class.
* @param value the value for the name of the new enum instance.
* @param description the full description of the new enum instance.
*/
@SuppressWarnings("unchecked")
public > void addEnum(Class type, String name, String value, String description) {
// 0. Sanity checks
if (!Enum.class.isAssignableFrom(type)) {
throw new RuntimeException("class " + type + " is not an instance of Enum");
}
// 1. Lookup "$VALUES" holder in enum class and get previous enum instances
Field valuesField = null;
Field[] fields = type.getClass().getDeclaredFields();
for (Field field : fields) {
if (field.getName().equals("enumConstants")) {
valuesField = field;
AccessibleObject.setAccessible(new Field[]{valuesField}, true);
break;
}
}
try {
// 2. Copy it
T[] previousValues;
List values = new ArrayList<>();
if (valuesField != null) {
previousValues = (T[]) valuesField.get(type);
if (previousValues != null) {
values = new ArrayList<>(Arrays.asList(previousValues));
}
}
// 3. build new enum
T newValue; // could be used to pass values to the enum constuctor if needed
newValue = (T) makeEnum(type, // The target enum class
name, value, description,// THE NEW ENUM INSTANCE TO BE DYNAMICALLY ADDED
values.size(), new Class>[]{}, // could be used to pass values to the enum constuctor if needed
new Object[]{});
// 4. add new value
values.add(newValue);
// 5. Set new values field
setFailsafeFieldValue(valuesField, type, values.toArray((T[]) Array.newInstance(type, 0)));
// 6. Clean enum cache
// cleanEnumCache(type);
} catch (Exception e) {
log.error(e.getMessage());
throw new RuntimeException(e.getMessage(), e);
}
}
private Object makeEnum(Class> enumClass,
String name,
String value,
String description,
int ordinal,
Class>[] additionalTypes,
Object[] additionalValues)
throws Exception {
Object[] parms = new Object[additionalValues.length + 2];
parms[0] = name;
parms[1] = ordinal;
System.arraycopy(additionalValues, 0, parms, 2, additionalValues.length);
Object o = enumClass.cast(getConstructorAccessor(enumClass, additionalTypes).newInstance(parms));
try {
Method mValue = o.getClass().getMethod("setValue", String.class);
mValue.setAccessible(true);
mValue.invoke(o, value);
Method mDescription = o.getClass().getMethod("setDescription", String.class);
mDescription.setAccessible(true);
mDescription.invoke(o, description);
} catch (Throwable ignored) {
}
return o;
}
private void setFailsafeFieldValue(Field field, Class> target, Object value)
throws NoSuchFieldException, IllegalAccessException {
// let's make the field accessible
field.setAccessible(true);
// next we change the modifier in the Field instance to
// not be final anymore, thus tricking reflection into
// letting us modify the final field
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
int modifiers = modifiersField.getInt(field);
// blank out the final bit in the modifiers int
modifiers &= ~Modifier.FINAL;
modifiersField.setInt(field, modifiers);
FieldAccessor fa = reflectionFactory.newFieldAccessor(field, false);
fa.set(target, value);
}
private ConstructorAccessor getConstructorAccessor(Class> enumClass, Class>[] additionalParameterTypes)
throws NoSuchMethodException {
Class>[] parameterTypes = new Class[additionalParameterTypes.length + 2];
parameterTypes[0] = String.class;
parameterTypes[1] = int.class;
System.arraycopy(additionalParameterTypes, 0, parameterTypes, 2, additionalParameterTypes.length);
return reflectionFactory.newConstructorAccessor(enumClass.getDeclaredConstructor(parameterTypes));
}
@SuppressWarnings({"unchecked", "JavaReflectionMemberAccess"})
public Object changeAnnotationValue(Annotation annotation, String key, Object newValue) {
InvocationHandler handler = Proxy.getInvocationHandler(annotation);
Field f;
try {
f = handler.getClass().getDeclaredField("memberValues");
} catch (NoSuchFieldException | SecurityException e) {
throw new IllegalStateException(e);
}
f.setAccessible(true);
Map memberValues;
try {
memberValues = (Map) f.get(handler);
} catch (IllegalArgumentException | IllegalAccessException e) {
throw new IllegalStateException(e);
}
Object oldValue = memberValues.get(key);
if (oldValue == null || oldValue.getClass() != newValue.getClass()) {
throw new IllegalArgumentException();
}
memberValues.put(key, newValue);
return oldValue;
}
private void cleanEnumCache(Class> enumClass)
throws NoSuchFieldException, IllegalAccessException {
blankField(enumClass, "enumConstantDirectory"); // Sun (Oracle?!?) JDK 1.5/6
blankField(enumClass, "enumConstants"); // IBM JDK
}
private void blankField(Class> enumClass, String fieldName)
throws NoSuchFieldException, IllegalAccessException {
for (Field field : Class.class.getDeclaredFields()) {
if (field.getName().contains(fieldName)) {
AccessibleObject.setAccessible(new Field[]{field}, true);
setFailsafeFieldValue(field, enumClass, null);
break;
}
}
}
public Object createAndInitializeCollection(Class> clazz, Object value) {
Class generics = extractGenerics(clazz);
return getObject(clazz, value, generics);
}
public Class extractGenerics(Class clazz) {
if (clazz == null) {
return null;
}
if (!isCollectionImplementation(clazz)) {
return clazz;
}
Class generics;
if (Collection.class.isAssignableFrom(clazz)) {
Type genericSuperclass = clazz.getGenericSuperclass();
if (genericSuperclass == null) {
generics = Object.class;
} else {
try {
Object type = ((ParameterizedType) genericSuperclass).getActualTypeArguments()[0];
generics = (Class) type;
} catch (ClassCastException ignored) {
try {
generics = (Class) clazz.getGenericInterfaces()[0];
} catch (Throwable t) {
generics = Object.class;
}
}
}
} else
generics = getClass(clazz);
return generics;
}
private Object getObject(Class> clazz, Object value, Class> generics) {
Object result;
if (Collection.class.isAssignableFrom(clazz)) {
result = ((ParameterizedType) clazz.getGenericSuperclass()).getActualTypeArguments()[0];
try {
((Collection) result).add(value);
} catch (Exception ignored) {
}
} else
result = getObject_(clazz, value, generics);
return result;
}
public boolean isCollectionImplementation(Class clazz) {
return clazz != null && (Collection.class.isAssignableFrom(clazz) || Object[].class.isAssignableFrom(clazz)
|| clazz.isArray());
}
private Class getClass(Class clazz) {
Class generics = null;
if (Object[].class.isAssignableFrom(clazz)) {
try {
generics = Class.forName(clazz.toString().replaceFirst("class \\[L", StringUtils.EMPTY).replace(";",
StringUtils.EMPTY));
} catch (ClassNotFoundException e) {
log.error(e.getMessage());
}
} else if (clazz.isArray()) {
try {
Method method = Class.class.getDeclaredMethod("getPrimitiveClass", String.class);
method.setAccessible(true);
generics = (Class) method.invoke(Class.forName("java.lang.Class"),
clazz.getSimpleName().replace("[]", StringUtils.EMPTY));
} catch (InvocationTargetException | ClassNotFoundException | NoSuchMethodException |
IllegalAccessException | NullPointerException ignored) {
}
}
return generics;
}
private Object getObject_(Class> clazz, Object value, Class> generics) {
Object result = null;
if (Object[].class.isAssignableFrom(clazz) || clazz.isArray()) {
try {
result = ObjectArrays.newArray(generics, 0);
result = ObjectArrays.concat((Object[]) result, value);
} catch (Exception ignored) {
}
} else {
throw new IllegalArgumentException("Invalid Type. Incoming type must be a collection implementation");
}
return result;
}
public Object createAndInitializeCollection(Class> clazz, String methodName, Object value)
throws IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException {
Class generics = extractGenerics(clazz);
Object bean = generics.newInstance();
PropertyUtils.setProperty(bean, methodName, value);
return getObject(clazz, bean, generics);
}
public Collection
© 2015 - 2025 Weber Informatics LLC | Privacy Policy