-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Gergely,

Gergely Paljak wrote:
> And it looks like more wrapping than before christmas, but I have never
> taken a close look on JDBC implementations (at least not this close).
> 
> So, i'd be interested in that *super-sexy *class wrapper generator of yours!
> Also in any experience, pitfalls or sources for manuals if you might have
> some ideas!

As with most super-sexy code (!), it comes without documentation and
without warranty. It is fairly readable, though.

Enjoy!
- -chris

import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.Writer;

import java.lang.reflect.*;

import java.util.Arrays;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

public class WrapperGenerator
{
    public static void main(String[] args)
        throws Exception
    {
        String className = args[0];

        Class clazz = Class.forName(className);

        new WrapperGenerator(clazz).generate(System.out);
    }

    private static String INDENT = "  ";
    private final Class _class;
    private final String _bareName;
    public WrapperGenerator(Class clazz)
    {
        if(Modifier.isFinal(clazz.getModifiers()))
            throw new IllegalArgumentException("Cannot wrap "
                                               + clazz.getName() + ":"
                                               + " class is final.");

        _class = clazz;

        _bareName = getShortName(_class);
    }

    public void generate(OutputStream out)
        throws IOException
    {
        this.generate(new OutputStreamWriter(out));
    }

    public void generate(Writer out)
        throws IOException
    {
        PrintWriter pout;

        if(out instanceof PrintWriter)
            pout = (PrintWriter)out;
        else
            pout = new PrintWriter(out);

        generateHeader(pout);
        generateWrapperMethods(pout);
        generateFooter(pout);

        pout.flush();
    }

    private void generateHeader(PrintWriter out)
        throws IOException
    {
        // package declaration
        out.println("// package ;");
        out.println();

        // imports
//         out.print("import ");
//         out.print(_class.getName());
//         out.println(";");
//         out.println();

        // class declaration
        out.println("/**");
        out.print(" * A wrapper class for ");
        out.print(_bareName);
        out.println(" objects.");
        out.println(" */");

        out.print("public ");

        if(Modifier.isStrict(_class.getModifiers()))
            out.print("strictfp ");

        out.print("class ");
        out.print(_bareName);
        out.println("Wrapper");
        out.print(INDENT);

        if(Modifier.isInterface(_class.getModifiers()))
            out.print("implements ");
        else
            out.print("extends ");

        out.println(_class.getName());
        out.println("{");

        // wrapped member
        out.print(INDENT);
        out.println("/**");
        out.print(INDENT);
        out.print(" * The ");
        out.print(_bareName);
        out.println(" being wrapped by this class.");
        out.print(INDENT);
        out.println(" */");

        out.print(INDENT);
        out.print("private ");
        out.print(_class.getName());
        out.println(" _wrapped;");
        out.println();

        out.print(INDENT);
        out.println("/**");
        out.print(INDENT);
        out.print(" * Creates a new ");
        out.print(_bareName);
        out.print("Wrapper with the specified wrapped ");
        out.print(_bareName);
        out.println(".");
        out.print(INDENT);
        out.println(" *");
        out.print(INDENT);
        out.print(" * @param wrapped The ");
        out.print(_bareName);
        out.print(" being wrapped by this");
        out.print("_bareName");
        out.println("Wrapper.");
        out.print(INDENT);
        out.println(" */");

        out.print(INDENT);
        out.print("public ");
        out.print(_bareName);
        out.print("Wrapper(");
        out.print(_class.getName());
        out.println(" wrapped)");
        out.print(INDENT);
        out.println("{");
        out.print(INDENT);
        out.print(INDENT);
        out.println("_wrapped = wrapped;");
        out.print(INDENT);
        out.println("}");
    }

    private void generateWrapperMethods(PrintWriter out)
        throws IOException
    {
        Method[] methods = _class.getDeclaredMethods();

        for(int i=0; i<methods.length; ++i)
            generateMethod(methods[i], out);
    }

    private void generateMethod(Method method, PrintWriter out)
        throws IOException
    {
        // signature
        if(Modifier.isFinal(method.getModifiers())
           && !Modifier.isStatic(method.getModifiers()))
        {
            // Class cannot be extended :(

            out.println("// ===========================");
            out.println("  // Sorry, this class cannot be extended due
to this method:");
            out.print("  // ");
            out.println(method);
            out.println("  // ===========================");
            out.println("}");

            out.flush();

            System.exit(5);
        }

        out.println();

        if(Modifier.isStatic(method.getModifiers())
                || Modifier.isFinal(method.getModifiers()))
        {
            out.print(INDENT);
            out.print("// skipping ");
            out.println(method);

            return;
        }

        if(Modifier.isPrivate(method.getModifiers()))
        {
            out.print(INDENT);
            out.print("// skipping ");
            out.println(method);

            return;
        }

        out.print(INDENT);
        out.println("/**");
        out.print(INDENT);
        out.print(" * Calls ");
        out.print(method.getName());
        out.print(" on the ");
        out.print(_bareName);
        out.println(" being wrapped by this object.");
        out.print(INDENT);
        out.println(" *");
        out.print(INDENT);
        out.print(" * @see ");
        out.print(_class.getName());
        out.print('#');
        out.println(method.getName());
        out.print(INDENT);
        out.println(" */");

        out.print(INDENT);

        if(Modifier.isPublic(method.getModifiers()))
        {
            out.print("public ");
        }
        else if(Modifier.isProtected(method.getModifiers()))
        {
            out.print("protected ");
        }
        // Note that native is okay... the superclass will have a native
method
        // but the subclass's method will not be native.
        else
        {
            out.print(INDENT);
            out.print("// skipping ");
            out.println(method);

            return;
        }

        if(Modifier.isStrict(method.getModifiers()))
        {
            out.print("strictfp ");
        }

        // synchronized keyword is not necessary. if the parent class's
method
        // is synchronized, the subclass's methods will be effectively
        // synchronized as well (because they will pass-through to the
wrapped
        // object's method, which will be synchronized).

        out.print(getDataType(method.getReturnType()));
        out.print(" ");
        out.print(method.getName());
        out.print("(");
        HashSet<String> usedArgNames = new HashSet<String>();
        ArrayList<String> argNames = new ArrayList<String>();
        Class[] argTypes = method.getParameterTypes();
        for(int i=0; i<argTypes.length; ++i)
        {
            out.print(getDataType(argTypes[i]));
            out.print(" ");
            String parameterName = getParameterName(argTypes[i],
usedArgNames);
            argNames.add(parameterName);
            out.print(parameterName);
            if(i < (argTypes.length - 1))
                out.print(", ");
        }
        out.println(")");

        // throws

        Class[] exceptions = method.getExceptionTypes();

        if(0 < exceptions.length)
        {
            out.print(INDENT);
            out.print(INDENT);
            out.print("throws ");

            for(int i=0; i<exceptions.length; ++i)
            {
                out.print(exceptions[i].getName());

                if(i < (exceptions.length - 1))
                    out.print(", ");
            }
            out.println();
        }

        out.print(INDENT);
        out.println("{");

        // body

        out.print(INDENT);
        out.print(INDENT);
        if(!Void.TYPE.equals(method.getReturnType()))
            out.print("return ");
        out.print("_wrapped.");
        out.print(method.getName());
        out.print("(");
        for(Iterator<String> i=argNames.iterator(); i.hasNext(); )
        {
            out.print(i.next());
            if(i.hasNext())
                out.print(", ");
        }
        out.println(");");

        out.print(INDENT);
        out.println("}");
    }

    private String getShortName(Class clazz)
    {
        String className = getDataType(clazz);

        if(className.endsWith("[]"))
            className = className.substring(0, className.indexOf('[')) +
"s";

        int pos = className.lastIndexOf('.');

        if(0 < pos)
            className = className.substring(pos + 1);

        return className;
    }

    private String getDataType(Class clazz)
    {
        if(clazz.isPrimitive())
            return clazz.getName();

        if(clazz.isArray())
            return getDataType(clazz.getComponentType()) + "[]";

        if(null == clazz.getPackage())
            return clazz.getName();

        if("java.lang".equals(clazz.getPackage().getName()))
            return clazz.getName().substring(10);

        return clazz.getName();
    }

    private String getParameterName(Class clazz, Set<String> usedNames)
    {
        String simpleName = getShortName(clazz);

        if(Character.isUpperCase(simpleName.charAt(0)))
            simpleName = Character.toLowerCase(simpleName.charAt(0))
                + simpleName.substring(1);

        String name = simpleName;

        int count = 0;
        while(usedNames.contains(name) || RESERVED_WORDS.contains(name))
            name = simpleName + String.valueOf(count++);

        usedNames.add(name);

        return name;
    }

    private void generateFooter(PrintWriter out)
        throws IOException
    {
        out.println("}");
    }

    private static final Set RESERVED_WORDS
        = Collections
        .unmodifiableSet(new HashSet<String>(Arrays
                                             .asList(
                                                     "abstract",
                                                     "continue",
                                                     "for",
                                                     "new",
                                                     "switch",
                                                     "assert",
                                                     "default",
                                                     "goto",
                                                     "package",
                                                     "synchronized",
                                                     "boolean",
                                                     "do",
                                                     "if",
                                                     "private",
                                                     "this",
                                                     "break",
                                                     "double",
                                                     "implements",
                                                     "protected",
                                                     "throw",
                                                     "byte",
                                                     "else",
                                                     "import",
                                                     "public",
                                                     "throws",
                                                     "case",
                                                     "enum",
                                                     "instanceof",
                                                     "return",
                                                     "transient",
                                                     "catch",
                                                     "extends",
                                                     "int",
                                                     "short",
                                                     "try",
                                                     "char",
                                                     "final",
                                                     "interface",
                                                     "static",
                                                     "void",
                                                     "class",
                                                     "finally",
                                                     "long",
                                                     "strictfp",
                                                     "volatile",
                                                     "const",
                                                     "float",
                                                     "native",
                                                     "super",
                                                     "while")))
        ;
}
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (MingW32)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iEYEARECAAYFAkmCDSAACgkQ9CaO5/Lv0PBtQQCgtyeHwK6QL5OPdMB5mxA0wuTl
ZJUAn0mSdQUCscDGjuzg2PUQcLi/abHf
=qrmx
-----END PGP SIGNATURE-----

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org
For additional commands, e-mail: users-h...@tomcat.apache.org

Reply via email to