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

com.github.jknack.handlebars.helper.MethodHelper Maven / Gradle / Ivy

There is a newer version: 2024.11.18751.20241128T090041Z-241100
Show newest version
/**
 * Copyright (c) 2012-2015 Edgar Espina
 *
 * This file is part of Handlebars.java.
 *
 * 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 com.github.jknack.handlebars.helper;

import static org.apache.commons.lang3.Validate.notNull;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import com.github.jknack.handlebars.Handlebars;
import com.github.jknack.handlebars.Helper;
import com.github.jknack.handlebars.Options;

/**
 *  Wrap a method as Handlebars helper.
 *
 *  @author edgar.espina
 *  @see Handlebars#registerHelpers(Object)
 *  @see Handlebars#registerHelpers(Class)
 *
 * @deprecated com.github.jknack.handlebars.helper package is deprecated and marked for removal in subsequent releases which will involve removal of the handlebars dependency in AEM.
 */
@Deprecated(since = "2024-07-10")
public class MethodHelper implements Helper {

    /**
     * No args.
     */
    private static final Object[] NO_ARGS = new Object[0];

    /**
     * The source or instance object. Might be null.
     */
    private Object source;

    /**
     * The method to invoke. Required.
     */
    private Method method;

    /**
     * Creates a new {@link MethodHelper}.
     *
     * @param method The method to invoke. Required.
     * @param source The source or instance object. Might be null.
     */
    public MethodHelper(final Method method, final Object source) {
        this.method = notNull(method, "A helper method is required.");
        this.source = source;
    }

    @Override
    public Object apply(final Object context, final Options options) throws IOException {
        try {
            Class[] paramTypes = method.getParameterTypes();
            Object[] args = NO_ARGS;
            if (paramTypes.length > 0) {
                args = new Object[paramTypes.length];
                args[0] = paramTypes[0] == Options.class ? options : context;
                for (int i = 1; i < args.length; i++) {
                    if (paramTypes[i] == Options.class) {
                        args[i] = options;
                    } else {
                        args[i] = options.param(i - 1, null);
                    }
                }
            }
            return method.invoke(source, args);
        } catch (ArrayIndexOutOfBoundsException ex) {
            throw new IllegalArgumentException("could not execute helper: " + toString(method) + ", with the given arguments: " + toString(options.params), ex);
        } catch (InvocationTargetException ex) {
            throw launderThrowable(ex.getCause());
        } catch (IllegalAccessException ex) {
            throw new IllegalStateException("could not execute helper: " + toString(method), ex);
        }
    }

    /**
     * Describe params.
     *
     * @param params Params to describe.
     * @return ToString of params
     */
    private String toString(final Object[] params) {
        StringBuilder buff = new StringBuilder();
        buff.append("[");
        for (Object param : params) {
            buff.append(param == null ? "null" : param.getClass().getSimpleName()).append(", ");
        }
        if (buff.length() > 1) {
            buff.setLength(buff.length() - 2);
        }
        return buff.append("]").toString();
    }

    /**
     * Describes method.
     *
     * @param method Method to describe.
     * @return ToString of method.
     */
    private String toString(final Method method) {
        return method.getName() + "(" + toString(method.getParameterTypes()) + ")";
    }

    /**
     * Describe types.
     *
     * @param types Types to describe.
     * @return ToString of types.
     */
    private String toString(final Class[] types) {
        StringBuilder buff = new StringBuilder();
        for (Class type : types) {
            buff.append(type.getSimpleName()).append(", ");
        }
        if (buff.length() > 0) {
            buff.setLength(buff.length() - 2);
        }
        return buff.toString();
    }

    /**
     * Return a runtime exception or throw an {@link IOException}.
     *
     * @param cause The invocation cause.
     * @return A runtime exception or throw an {@link IOException}.
     * @throws IOException If the cause is an {@link IOException}.
     */
    private RuntimeException launderThrowable(final Throwable cause) throws IOException {
        if (cause instanceof RuntimeException) {
            return (RuntimeException) cause;
        }
        if (cause instanceof IOException) {
            throw (IOException) cause;
        }
        return new IllegalStateException("could not execute helper: " + method.getName(), cause);
    }
}