<commit_before>/*
 * This file is part of NucleusFramework for Bukkit, licensed under the MIT License (MIT).
 *
 * Copyright (c) JCThePants (www.jcwhatever.com)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

package com.jcwhatever.nucleus.utils.reflection;

import com.google.common.collect.ImmutableMap;
import com.jcwhatever.nucleus.utils.PreCon;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Collection;
import java.util.Map;
import javax.annotation.Nullable;

/**
 * Reflection utilities.
 */
public class ReflectionUtils {

    private ReflectionUtils () {}

    /**
     * Maps primitive types to wrapper types.
     */
    public static final Map<Class<?>, Class<?>> PRIMITIVES_TO_WRAPPERS
            = new ImmutableMap.Builder<Class<?>, Class<?>>()
            .put(boolean.class, Boolean.class)
            .put(byte.class, Byte.class)
            .put(char.class, Character.class)
            .put(short.class, Short.class)
            .put(int.class, Integer.class)
            .put(long.class, Long.class)
            .put(float.class, Float.class)
            .put(double.class, Double.class)
            .put(void.class, Void.class)
            .build();

    /**
     * Maps primitive wrapper types to primitives.
     */
    public static final Map<Class<?>, Class<?>> WRAPPERS_TO_PRIMITIVES
            = new ImmutableMap.Builder<Class<?>, Class<?>>()
            .put(Boolean.class, boolean.class)
            .put(Byte.class, byte.class)
            .put(Character.class, char.class)
            .put(Short.class, short.class)
            .put(Integer.class, int.class)
            .put(Long.class, long.class)
            .put(Float.class, float.class)
            .put(Double.class, double.class)
            .put(Void.class, void.class)
            .build();

    /**
     * Maps primitive names to primitive type.
     */
    public static final Map<String, Class<?>> NAMES_TO_PRIMITIVES
            = new ImmutableMap.Builder<String, Class<?>>()
            .put("boolean", boolean.class)
            .put("byte", byte.class)
            .put("char", char.class)
            .put("short", short.class)
            .put("int", int.class)
            .put("long", long.class)
            .put("float", float.class)
            .put("double", double.class)
            .put("void", void.class)
            .build();

    /**
     * Create a new {@link Reflection} instance for the specified
     * NMS version.
     *
     * @param nmsVersion  The nms version. This is the version package name
     *                    used by the NMS classes. (i.e v1_8_R1)
     */
    public static Reflection newReflection(String nmsVersion) {
        return new Reflection(nmsVersion);
    }

    /**
     * Determine if an object is an array.
     *
     * @param instance  The object to check.
     */
    public static int getArrayDimensions(Object instance) {
        PreCon.notNull(instance);

        String className = instance.getClass().getName();

        for (int i=0; i < className.length(); i++) {
            char ch = className.charAt(i);
            if (ch != '[')
                return i;
        }

        return 0;
    }

    /**
     * Get the component type of an array instance. If the instance
     * is not an array then the instance type is returned.
     *
     * @param instance  The instance of a 1 or more dimensional array.
     *
     * @return  The component type of the array.
     */
    public static Class<?> getArrayComponentType(Object instance) {

        if (!instance.getClass().isArray())
            return instance.getClass();

        Class<?> componentType = instance.getClass().getComponentType();

        while (componentType.isArray()) {
            componentType = componentType.getComponentType();
        }

        return componentType;
    }

    /**
     * Remove the final modifier from a field.
     *
     * @param field  The field.
     *
     * @return  True if successful, otherwise false.
     *
     * @throws NoSuchFieldException
     * @throws IllegalAccessException
     */
    public static boolean removeFinal(Field field) throws NoSuchFieldException, IllegalAccessException {
        PreCon.notNull(field);

        field.setAccessible(true);

        Field modifiersField = Field.class.getDeclaredField("modifiers");
        modifiersField.setAccessible(true);
        modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);

        return true;
    }

    /**
     * Searches the provided collection of constructor candidates for a constructor
     * that can be used with the provided arguments.
     *
     * @param candidates  The candidate constructors to check.
     * @param args        The arguments to check.
     *
     * @return  Null if a matching constructor was not found.
     */
    @Nullable
    public static Constructor<?> findConstructorByArgs(Collection<Constructor<?>> candidates, Object... args) {
        for (Constructor<?> c : candidates) {

            Class<?>[] ptypes = c.getParameterTypes();
            if (ptypes.length != args.length)
                continue;

            boolean isMatch = true;

            for (int i=0; i < ptypes.length; i++) {

                Class<?> arg = args[i].getClass();<commit_msg>remove checked exceptions from ReflectionUtils#removeFinal<commit_after>/*
 * This file is part of NucleusFramework for Bukkit, licensed under the MIT License (MIT).
 *
 * Copyright (c) JCThePants (www.jcwhatever.com)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

package com.jcwhatever.nucleus.utils.reflection;

import com.google.common.collect.ImmutableMap;
import com.jcwhatever.nucleus.utils.PreCon;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Collection;
import java.util.Map;
import javax.annotation.Nullable;

/**
 * Reflection utilities.
 */
public class ReflectionUtils {

    private ReflectionUtils () {}

    /**
     * Maps primitive types to wrapper types.
     */
    public static final Map<Class<?>, Class<?>> PRIMITIVES_TO_WRAPPERS
            = new ImmutableMap.Builder<Class<?>, Class<?>>()
            .put(boolean.class, Boolean.class)
            .put(byte.class, Byte.class)
            .put(char.class, Character.class)
            .put(short.class, Short.class)
            .put(int.class, Integer.class)
            .put(long.class, Long.class)
            .put(float.class, Float.class)
            .put(double.class, Double.class)
            .put(void.class, Void.class)
            .build();

    /**
     * Maps primitive wrapper types to primitives.
     */
    public static final Map<Class<?>, Class<?>> WRAPPERS_TO_PRIMITIVES
            = new ImmutableMap.Builder<Class<?>, Class<?>>()
            .put(Boolean.class, boolean.class)
            .put(Byte.class, byte.class)
            .put(Character.class, char.class)
            .put(Short.class, short.class)
            .put(Integer.class, int.class)
            .put(Long.class, long.class)
            .put(Float.class, float.class)
            .put(Double.class, double.class)
            .put(Void.class, void.class)
            .build();

    /**
     * Maps primitive names to primitive type.
     */
    public static final Map<String, Class<?>> NAMES_TO_PRIMITIVES
            = new ImmutableMap.Builder<String, Class<?>>()
            .put("boolean", boolean.class)
            .put("byte", byte.class)
            .put("char", char.class)
            .put("short", short.class)
            .put("int", int.class)
            .put("long", long.class)
            .put("float", float.class)
            .put("double", double.class)
            .put("void", void.class)
            .build();

    /**
     * Create a new {@link Reflection} instance for the specified
     * NMS version.
     *
     * @param nmsVersion  The nms version. This is the version package name
     *                    used by the NMS classes. (i.e v1_8_R1)
     */
    public static Reflection newReflection(String nmsVersion) {
        return new Reflection(nmsVersion);
    }

    /**
     * Determine if an object is an array.
     *
     * @param instance  The object to check.
     */
    public static int getArrayDimensions(Object instance) {
        PreCon.notNull(instance);

        String className = instance.getClass().getName();

        for (int i=0; i < className.length(); i++) {
            char ch = className.charAt(i);
            if (ch != '[')
                return i;
        }

        return 0;
    }

    /**
     * Get the component type of an array instance. If the instance
     * is not an array then the instance type is returned.
     *
     * @param instance  The instance of a 1 or more dimensional array.
     *
     * @return  The component type of the array.
     */
    public static Class<?> getArrayComponentType(Object instance) {

        if (!instance.getClass().isArray())
            return instance.getClass();

        Class<?> componentType = instance.getClass().getComponentType();

        while (componentType.isArray()) {
            componentType = componentType.getComponentType();
        }

        return componentType;
    }

    /**
     * Remove the final modifier from a field.
     *
     * @param field  The field.
     *
     * @return  True if successful, otherwise false.
     */
    public static boolean removeFinal(Field field)  {
        PreCon.notNull(field);

        field.setAccessible(true);

        try {
            Field modifiersField = Field.class.getDeclaredField("modifiers");
            modifiersField.setAccessible(true);
            modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
        }
        catch (NoSuchFieldException | IllegalAccessException e) {
            return false;
        }

        return true;
    }

    /**
     * Searches the provided collection of constructor candidates for a constructor
     * that can be used with the provided arguments.
     *
     * @param candidates  The candidate constructors to check.
     * @param args        The arguments to check.
     *
     * @return  Null if a matching constructor was not found.
     */
    @Nullable
    public static Constructor<?> findConstructorByArgs(Collection<Constructor<?>> candidates, Object... args) {
        for (Constructor<?> c : candidates) {

            Class<?>[] ptypes = c.getParameterTypes();
            if (ptypes.length != args.length)
                continue;

            boolean isMatch = true;

            for (int i=0; i < ptypes.length; i++) {

                Class<?> arg = args[i].getClass();
{'fraction_non_alphanumeric': 0.10437290513679943, 'fraction_numerical': 0.0010912775742458493, 'mean_word_length': 2.3316021812516228, 'pattern_counts': {'":': 0, '<': 55, '<?xml version=': 0, '>': 51, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6439570', 'n_tokens_mistral': 3506, 'n_tokens_neox': 3405, 'n_words': 1107}