All Downloads are FREE. Search and download functionalities are using the official Maven repository.

yakworks.commons.lang.ClassUtils.groovy Maven / Gradle / Ivy

There is a newer version: 3.14
Show newest version
/*
* Copyright 2021 original authors
* SPDX-License-Identifier: Apache-2.0
*/
package yakworks.commons.lang

import java.lang.reflect.Field
import java.lang.reflect.Modifier

import groovy.transform.CompileStatic

import org.codehaus.groovy.reflection.CachedClass
import org.codehaus.groovy.reflection.ClassInfo
import org.codehaus.groovy.runtime.InvokerHelper
import org.codehaus.groovy.transform.trait.Traits

import jakarta.annotation.Nullable
import yakworks.util.ReflectionUtils

/**
 * There are 2 ClassUtils. This groovy based one and the one in yakworks.utils which is the java/spring one.
 * This is the one to mostly use.
 *
 */
@CompileStatic
@SuppressWarnings("unchecked")
class ClassUtils {

    protected static final List BASIC_TYPES = [
        String, Boolean, Byte, Short, Integer, Long, Float, Double, Character
    ] as List

    /**
     * Wrapper around InvokerHelper.invokeStaticMethod, here just so we can remember it
     */
    static Object callStaticMethod(Class type, String method, Object arguments) {
        return InvokerHelper.invokeStaticMethod(type, method, arguments)
    }

    /**
     * checks if Class is basic type (String, long/Long, boolean/Boolean, etc...)
     */
    static boolean isBasicType(Class c) {
        BASIC_TYPES.contains(c) || c.isPrimitive()
    }

    static boolean isBasicType(Object o) {
        if(o == null) return false
        return isBasicType(o.class)
    }

    /**
     * simple helper to load the class from the currentThread.classLoader
     * @param clazz the class name
     * @return the loaded class
     * @throws  ClassNotFoundException
     *          If the class was not found
     */
    static Class loadClass(String clazz){
        def classLoader = Thread.currentThread().contextClassLoader
        classLoader.loadClass(clazz)
    }

    /**
     * gets the static properties from implemented traits on a class
     * @param mainClass the class to look for traits on.
     * @param name the name of the property
     * @param requiredTyped the type of the property
     * @return the list of values
     */
    public static  List getStaticValuesFromTraits(Class mainClass, String name, Class requiredTyped) {
        CachedClass cachedClass = ClassInfo.getClassInfo(mainClass).getCachedClass() //classInfo.getCachedClass()
        Collection hierarchy = cachedClass.getHierarchy()
        Class javaClass = cachedClass.getTheClass()
        List values = []
        for (ClassInfo current : hierarchy) {
            def traitClass = current.getTheClass()
            def isTrait = Traits.isTrait(traitClass)
            if(!isTrait) continue
            def traitFieldName = getTraitFieldName(traitClass, name)
            T theval = getStaticPropertyValue(mainClass, traitFieldName, requiredTyped)
            if(theval){
                //println "$traitFieldName found with $theval"
                values.add(theval)
            }
        }
        Collections.reverse(values)
        return values
    }

    /**
     * trait fields get added in the form package_class__field name. this returns that
     */
    static String getTraitFieldName(Class traitClass, String fieldName) {
        return traitClass.getName().replace('.', '_') + "__" + fieldName;
    }


    public static  T getStaticPropertyValue(Class clazz, String name, Class requiredType) {
        return returnOnlyIfInstanceOf(getStaticPropertyValue(GroovySystem.getMetaClassRegistry().getMetaClass(clazz), name), requiredType);
    }

    private static  T returnOnlyIfInstanceOf(Object value, Class type) {
        if (value != null && (type == Object || AssignUtils.isAssignableFrom(type, value.getClass()))) {
            return (T)value;
        }
        return null;
    }

    static Object getStaticPropertyValue(Class clazz, String name) {
        return getStaticPropertyValue(clazz.metaClass, name);
    }

    static Object getStaticPropertyValue(MetaClass theMetaClass, String name) {
        MetaProperty metaProperty = theMetaClass.getMetaProperty(name);
        if(metaProperty != null && Modifier.isStatic(metaProperty.getModifiers())) {
            return metaProperty.getProperty(theMetaClass.getTheClass());
        }
        return null;
    }

    static Class getPropertyType(Class cls, String propertyName) {
        MetaProperty metaProperty = GroovySystem.getMetaClassRegistry().getMetaClass(cls).getMetaProperty(propertyName);
        if(metaProperty != null) {
            return metaProperty.getType();
        }
        return null;
    }

    /**
     * trickery to set a private final field
     *
     * @param clazz the class
     * @param instance the instance to set it on
     * @param fieldName the name of the field
     * @param value the value to set
     */
    static void setPrivateFinal(Class clazz, Object instance, String fieldName, Object value){
        //make the constrainedProperties accessible, remove private
        Field field = clazz.getDeclaredField(fieldName)
        field.setAccessible(true)
        //remove final modifier
        Field modifiersField = Field.getDeclaredField("modifiers")
        modifiersField.setAccessible(true)
        modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL)
        //set the value now
        field.set(instance, value)
    }

    /**
     * Cleaner trickery to set a private or final field.
     * Uses yakworks.util.ReflectionUtils to find the field, so it can be in the super class 
* then will make it accesible if it needs to
* then will set the value on the field. * * @param instance the instance to set it on * @param fieldName the name of the field * @param value the value to set */ static void setFieldValue(Object instance, String fieldName, Object value){ setFieldValue(instance.getClass(), instance, fieldName, value) def field = ReflectionUtils.findField(instance.getClass(), fieldName); ReflectionUtils.makeAccessible(field) field.set(instance, value) } /** * see the instance based one for docs. * If doesnt works by not specifying the class and letting it find the field * or performance is critical and your shaving yaktoseconds then use this one. */ static void setFieldValue(Class clazz, Object instance, String fieldName, Object value){ //its private so set with reflection def field = ReflectionUtils.findField(clazz, fieldName); ReflectionUtils.makeAccessible(field) field.set(instance, value) } /** * Determine whether the {@link Class} identified by the supplied name is present * and can be loaded. Will return {@code false} if either the class or * one of its dependencies is not present or cannot be loaded. * @param className the name of the class to check * @param classLoader the class loader to use * (may be {@code null} which indicates the default class loader) * @return whether the specified class is present (including all of its * superclasses and interfaces) * @throws IllegalStateException if the corresponding class is resolvable but * there was a readability mismatch in the inheritance hierarchy of the class * (typically a missing dependency declaration in a Jigsaw module definition * for a superclass or interface implemented by the class to be checked here) */ public static boolean isPresent(String className, @Nullable ClassLoader classLoader) { yakworks.util.ClassUtils.isPresent(className, classLoader) } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy