    001// Licensed under the Apache License, Version 2.0 (the "License");
    002// you may not use this file except in compliance with the License.
    003// You may obtain a copy of the License at
    004//
    005// http://www.apache.org/licenses/LICENSE-2.0
    006//
    007// Unless required by applicable law or agreed to in writing, software
    008// distributed under the License is distributed on an "AS IS" BASIS,
    009// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    010// See the License for the specific language governing permissions and
    011// limitations under the License.
    012
    013package org.apache.tapestry5.plastic;
    014
    015import org.apache.tapestry5.internal.plastic.PrimitiveType;
    016
    017import java.lang.reflect.Method;
    018import java.util.concurrent.atomic.AtomicLong;
    019
    020/**
    021 * Utilities for user code making use of Plastic.
    022 */
    023public class PlasticUtils
    024{
    025    /**
    026     * The {@code toString()} method inherited from Object.
    027     */
    028    public static final Method TO_STRING = getMethod(Object.class, "toString");
    029
    030    /**
    031     * The MethodDescription version of {@code toString()}.
    032     */
    033    public static final MethodDescription TO_STRING_DESCRIPTION = new MethodDescription(TO_STRING);
    034
    035    private static final AtomicLong UID_GENERATOR = new AtomicLong(System.nanoTime());
    036
    037    /**
    038     * Returns a string that can be used as part of a Java identifier and is unique
    039     * for this JVM. Currently returns a hexadecimal string and initialized by
    040     * System.nanoTime() (but both those details may change in the future).
    041     *
    042     * Note that the returned value may start with a numeric digit, so it should be used as a <em>suffix</em>, not
    043     * <em>prefix</em> of a Java identifier.
    044     *
    045     * @return unique id that can be used as part of a Java identifier
    046     */
    047    public static String nextUID()
    048    {
    049        return Long.toHexString(PlasticUtils.UID_GENERATOR.getAndIncrement());
    050    }
    051
    052    /**
    053     * Converts a type (including array and primitive types) to their type name (the way they are represented in Java
    054     * source files).
    055     */
    056    public static String toTypeName(Class type)
    057    {
    058        if (type.isArray())
    059            return toTypeName(type.getComponentType()) + "[]";
    060
    061        return type.getName();
    062    }
    063
    064    /** Converts a number of types (usually, arguments to a method or constructor) into their type names. */
    065    public static String[] toTypeNames(Class[] types)
    066    {
    067        String[] result = new String[types.length];
    068
    069        for (int i = 0; i < result.length; i++)
    070            result[i] = toTypeName(types[i]);
    071
    072        return result;
    073    }
    074
    075    /**
    076     * Gets the wrapper type for a given type (if primitive)
    077     *
    078     * @param type
    079     *            type to look up
    080     * @return the input type for non-primitive type, or corresponding wrapper type (Boolean.class for boolean.class,
    081     *         etc.)
    082     */
    083    public static Class toWrapperType(Class type)
    084    {
    085        assert type != null;
    086
    087        return type.isPrimitive() ? PrimitiveType.getByPrimitiveType(type).wrapperType : type;
    088    }
    089
    090    /**
    091     * Convenience for getting a method from a class.
    092     *
    093     * @param declaringClass
    094     *            containing class
    095     * @param name
    096     *            name of method
    097     * @param parameterTypes
    098     *            types of parameters
    099     * @return the Method
    100     * @throws RuntimeException
    101     *             if any error (such as method not found)
    102     */
    103    @SuppressWarnings("unchecked")
    104    public static Method getMethod(Class declaringClass, String name, Class... parameterTypes)
    105    {
    106        try
    107        {
    108            return declaringClass.getMethod(name, parameterTypes);
    109        }
    110        catch (Exception ex)
    111        {
    112            throw new RuntimeException(ex);
    113        }
    114    }
    115
    116    /**
    117     * Uses {@link #getMethod(Class, String, Class...)} and wraps the result as a {@link MethodDescription}.
    118     *
    119     * @param declaringClass
    120     *            containing class
    121     * @param name
    122     *            name of method
    123     * @param parameterTypes
    124     *            types of parameters
    125     * @return description for method
    126     * @throws RuntimeException
    127     *             if any error (such as method not found)
    128     */
    129    public static MethodDescription getMethodDescription(Class declaringClass, String name, Class... parameterTypes)
    130    {
    131        return new MethodDescription(getMethod(declaringClass, name, parameterTypes));
    132    }
    133
    134    /**
    135     * Determines if the provided type name is a primitive type.
    136     *
    137     * @param typeName Java type name, such as "boolean" or "java.lang.String"
    138     * @return true if primitive
    139     */
    140    public static boolean isPrimitive(String typeName)
    141    {
    142        return PrimitiveType.getByName(typeName) != null;
    143    }
    144
    145    /**
    146     * If the given class is an inner class, returns the enclosing class.
    147     * Otherwise, returns the class name unchanged.
    148     */
    149    public static String getEnclosingClassName(String className)
    150    {
    151        int index = className.indexOf('$');
    152        return index <= 0 ? className : className.substring(0, index);
    153    }
    154}