-----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: [email protected]
For additional commands, e-mail: [email protected]