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

org.apache.tapestry.ioc.services.ClassFabUtils Maven / Gradle / Ivy

// Copyright 2006, 2007 The Apache Software Foundation
//
// 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.apache.tapestry.ioc.services;

import org.apache.tapestry.ioc.ObjectCreator;
import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newMap;

import static java.lang.String.format;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Map;

/**
 * Handy method useful when creating new classes using
 * {@link org.apache.tapestry.ioc.services.ClassFab}.
 */
public final class ClassFabUtils
{
    private static long _uid = System.currentTimeMillis();

    private ClassFabUtils()
    {
    }

    /**
     * Generates a unique class name, which will be in the default package.
     */

    public static synchronized String generateClassName(String baseName)
    {
        return "$" + baseName + "_" + Long.toHexString(_uid++);
    }

    /**
     * Returns a class name derived from the provided interfaceClass. The package part of the
     * interface name is stripped out, and the result passed to {@link #generateClassName(String)}.
     */

    public static String generateClassName(Class interfaceClass)
    {
        return generateClassName(interfaceClass.getSimpleName());
    }

    /**
     * Javassist needs the class name to be as it appears in source code, even for arrays. Invoking
     * getName() on a Class instance representing an array returns the internal format (i.e, "[...;"
     * or something). This returns it as it would appear in Java code.
     */
    public static String toJavaClassName(Class inputClass)
    {
        if (inputClass.isArray()) return toJavaClassName(inputClass.getComponentType()) + "[]";

        return inputClass.getName();
    }

    /**
     * Returns true if the method is the standard toString() method. Very few interfaces will ever
     * include this method as part of the interface, but we have to be sure.
     */
    public static boolean isToString(Method method)
    {
        if (!method.getName().equals("toString")) return false;

        if (method.getParameterTypes().length > 0) return false;

        return method.getReturnType().equals(String.class);
    }

    private static class PrimitiveInfo
    {
        private final String _typeCode;

        private final Class _wrapperType;

        private final String _unwrapMethod;

        public PrimitiveInfo(String typeCode, Class wrapperType, String unwrapMethod)
        {
            _typeCode = typeCode;
            _wrapperType = wrapperType;
            _unwrapMethod = unwrapMethod;
        }

        public String getTypeCode()
        {
            return _typeCode;
        }

        public String getUnwrapMethod()
        {
            return _unwrapMethod;
        }

        public Class getWrapperType()
        {
            return _wrapperType;
        }
    }

    private static final Map PRIMITIVE_INFO = newMap();

    static
    {
        add("boolean", "Z", Boolean.class, "booleanValue");
        add("short", "S", Short.class, "shortValue");
        add("int", "I", Integer.class, "intValue");
        add("long", "J", Long.class, "longValue");
        add("float", "F", Float.class, "floatValue");
        add("double", "D", Double.class, "doubleValue");
        add("char", "C", Character.class, "charValue");
        add("byte", "B", Byte.class, "byteValue");
    }

    private static void add(String primitiveType, String typeCode, Class wrapperType,
                            String unwrapMethod)
    {
        PRIMITIVE_INFO.put(primitiveType, new PrimitiveInfo(typeCode, wrapperType, unwrapMethod));
    }

    /**
     * Translates types from standard Java format to Java VM format. For example, java.util.Locale
     * remains java.util.Locale, but int[][] is translated to [[I and java.lang.Object[] to
     * [Ljava.lang.Object;
     */
    public static String toJVMBinaryName(String type)
    {
        // if it is not an array, just return the type itself
        if (!type.endsWith("[]")) return type;

        // if it is an array, convert it to JavaVM-style format
        StringBuilder buffer = new StringBuilder();

        while (type.endsWith("[]"))
        {
            buffer.append("[");
            type = type.substring(0, type.length() - 2);
        }

        PrimitiveInfo pi = PRIMITIVE_INFO.get(type);

        if (pi != null)
            buffer.append(pi.getTypeCode());
        else
        {
            buffer.append("L");
            buffer.append(type);
            buffer.append(";");
        }

        return buffer.toString();
    }

    /**
     * Given one of the primitive types, returns the name of the method that will unwrap the wrapped
     * type to the primitive type.
     */
    public static String getUnwrapMethodName(String primitiveTypeName)
    {
        return PRIMITIVE_INFO.get(primitiveTypeName).getUnwrapMethod();
    }

    /**
     * Given the name of a primitive type, returns the name of the corresponding wrapper class.
     */

    public static String getWrapperTypeName(String primitiveType)
    {
        return PRIMITIVE_INFO.get(primitiveType).getWrapperType().getName();
    }

    /**
     * Given some type (possibly a primitive) returns the corresponding primitive type. For
     * non-primitives, the provided type is returned.
     */
    public static Class getWrapperType(Class primitiveType)
    {
        if (primitiveType.isPrimitive())
            return PRIMITIVE_INFO.get(primitiveType.getName()).getWrapperType();

        return primitiveType; // Not a primitive!
    }

    public static String getTypeCode(Class type)
    {
        if (type.equals(void.class)) return "V";

        if (type.isPrimitive()) return PRIMITIVE_INFO.get(type.getName()).getTypeCode();

        if (type.isArray()) return "[" + getTypeCode(type.getComponentType());

        return "L" + type.getName().replace('.', '/') + ";";
    }

    /**
     * Creates a proxy for a given service interface around an {@link ObjectCreator} that can
     * provide (on demand) an object (implementing the service interface) to delegate to. The
     * ObjectCreator will be invoked on every method invocation ( if it is caching, that should be
     * internal to its implementation).
     *
     * @param 
     * @param classFab         used to create the new class
     * @param serviceInterface the interface the proxy will implement
     * @param creator          the createor which will provide an instance of the interface
     * @param description      description to be returned from the proxy's toString() method
     * @return the instantiated proxy object
     */
    public static  T createObjectCreatorProxy(ClassFab classFab, Class serviceInterface,
                                                 ObjectCreator creator, String description)
    {
        classFab.addField("_creator", Modifier.PRIVATE | Modifier.FINAL, ObjectCreator.class);

        classFab.addConstructor(new Class[]
                {ObjectCreator.class}, null, "_creator = $1;");

        String body = format("return (%s) _creator.createObject();", serviceInterface.getName());

        MethodSignature sig = new MethodSignature(serviceInterface, "_delegate", null, null);

        classFab.addMethod(Modifier.PRIVATE, sig, body);

        classFab.proxyMethodsToDelegate(serviceInterface, "_delegate()", description);
        Class proxyClass = classFab.createClass();

        try
        {
            Object proxy = proxyClass.getConstructors()[0].newInstance(creator);

            return serviceInterface.cast(proxy);
        }
        catch (Exception ex)
        {
            // This should never happen, so we won't go to a lot of trouble
            // reporting it.
            throw new RuntimeException(ex.getMessage(), ex);
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy