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

org.algorithmx.rules.util.LambdaUtils Maven / Gradle / Ivy

/**
 * This software is licensed under the Apache 2 license, quoted below.
 *
 * Copyright (c) 1999-2019, Live Software & Consultants Inc ([email protected])
 *
 * 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 org.algorithmx.rules.util;

import org.algorithmx.rules.spring.util.Assert;
import org.algorithmx.rules.spring.util.ClassUtils;

import java.io.Serializable;
import java.lang.invoke.SerializedLambda;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Optional;

/**
 * Lambda related utilities.
 *
 * Inspired by Benji Weber : http://benjiweber.com/blog/2015/08/04/lambda-type-references/
 *
 * @author Max Arulananthan
 * @since 1.0
 */
public final class LambdaUtils {

    private LambdaUtils() {
        super();
    }

    /**
     * Determines if the given class is a Lambda.
     *
     * @param target target object.
     * @return true if the target class is a Lambda; false otherwise.
     */
    public static boolean isLambda(Object target) {
        Assert.notNull(target, "target cannot be null.");

        try {
            if (!target.getClass().isSynthetic()) return false;
            return (target instanceof Serializable) ? getSerializedLambda((Serializable) target) != null : false;
        } catch (IllegalStateException e) {
            return false;
        }
    }

    /**
     * Returns the Serialized form of the Lambda.
     *
     * @param target Lambda object
     * @return Serialized form of the given lambda.
     * @throws IllegalStateException if the given target object really isn't a Lambda or if we are unable to deserialize the Lambda.
     */
    public static SerializedLambda getSerializedLambda(Serializable target) {
        Assert.notNull(target, "target cannot be null.");
        Method writeReplaceMethod = getWriteReplaceMethod(target.getClass());

        try {
            // Make sure we found the method
            if (writeReplaceMethod == null) {
                throw new IllegalStateException("Unable to find writeReplace method! Not a SerializedLambda?");
            }
            // Make it callable
            writeReplaceMethod.setAccessible(true);
            Object result = writeReplaceMethod.invoke(target);

            if (!(result instanceof SerializedLambda)) {
                throw new IllegalStateException("writeReplaceMethod did not return a SerializedLambda ["
                        + result + "]. is this Lambda?");
            }

            return (SerializedLambda) writeReplaceMethod.invoke(target);
        } catch (IllegalAccessException | InvocationTargetException e) {
            throw new IllegalStateException("Unable to execute writeReplace method! [" + writeReplaceMethod + "]");
        }
    }

    /**
     * Returns the Serialized form of the Lambda.
     *
     * @param target Lambda object
     * @return Serialized form of the given lambda; null in case of any error.
     */
    public static SerializedLambda getSafeSerializedLambda(Serializable target) {
        try {
            return getSerializedLambda(target);
        } catch (IllegalStateException e) {
            return null;
        }
    }

    /**
     * Return the Lambda implementation class.
     *
     * @param lambda serialized lambda form
     * @return Lambda implementation class.
     * @throws IllegalStateException if we are unable to load the implementing Class.
     */
    public static Class getImplementationClass(SerializedLambda lambda) {
        Assert.notNull(lambda, "lambda cannot be null.");
        String className = null;

        try {
            className = lambda.getImplClass().replaceAll("/", ".");
            return ClassUtils.forName(className, null);
        } catch (ClassNotFoundException e) {
            throw new IllegalStateException("Unable to load the implementing Lambda class [" + className + "]");
        }
    }

    /**
     * Returns the Lambda implementation method.
     *
     * @param lambda serialized lambda form
     * @param implementingClass Lambda implementation class.
     * @return Lambda implementation method.
     * @throws IllegalStateException if we are unable to locate the Lambda implementing method.
     */
    public static Method getImplementationMethod(SerializedLambda lambda, Class implementingClass) {
        Assert.notNull(lambda, "lambda cannot be null.");
        Assert.notNull(implementingClass, "implementingClass cannot be null.");
        Optional result = Arrays.stream(implementingClass.getDeclaredMethods())
                .filter(method -> method.getName().equals(lambda.getImplMethodName()))
                .findFirst();

        if (!result.isPresent()) {
            throw new IllegalStateException("Unable to find implementing Lambda method on class [" + implementingClass + "]");
        }

        return result.get();
    }

    /**
     * Finds the writeReplace method.
     *
     * @param c target class.
     * @return writeReplace method if found; null otherwise.
     */
    private static Method getWriteReplaceMethod(Class c) {

        try {
            Method writeReplaceMethod = c.getDeclaredMethod("writeReplace");
            return writeReplaceMethod != null ? writeReplaceMethod : null;
        } catch (NoSuchMethodException e) {
            return null;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy