org.openrdf.repository.object.composition.CodeBuilder Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of alibaba-composition-object Show documentation
Show all versions of alibaba-composition-object Show documentation
The Object Composition library merges multiple Java objects into a single multi-subject object.
/*
* Copyright (c) 2009, James Leigh All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the openrdf.org nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
package org.openrdf.repository.object.composition;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javassist.CtClass;
import javassist.bytecode.ConstPool;
import javassist.bytecode.Descriptor;
import javassist.bytecode.annotation.ClassMemberValue;
import org.openrdf.repository.object.exceptions.ObjectCompositionException;
/**
* Java code builder that abstracts away from the Java syntax a bit.
*
* @author James Leigh
*
*/
public abstract class CodeBuilder {
private StringBuilder body = new StringBuilder();
private ClassTemplate klass;
private Map>, String>> methodTemplateVars = new HashMap();
private Map methodVars = new HashMap();
private int varCounter;
protected CodeBuilder(ClassTemplate klass) {
super();
this.klass = klass;
}
public CodeBuilder assign(String var) {
body.append(var).append(" = ");
return this;
}
public CodeBuilder castObject(Class> type) {
body.append("(");
if (type.isPrimitive()) {
body.append(getPrimitiveWrapper(type)).append(")");
} else {
body.append(getJavaClassCodeNameOf(type)).append(")");
}
return this;
}
public CodeBuilder valueOf(Class> type) {
if (type.isPrimitive()) {
body.append(getPrimitiveWrapper(type)).append(".valueOf");
} else {
body.append("(");
body.append(getJavaClassCodeNameOf(type)).append(")");
}
return this;
}
public CodeBuilder cast(Class> type) {
body.append("(");
body.append(getJavaClassCodeNameOf(type)).append(")");
return this;
}
public CodeBuilder code(String str) {
body.append(str);
return this;
}
public CodeBuilder codeInstanceof(String field, Class> type) {
body.append(field).append(" instanceof ");
body.append(getJavaClassCodeNameOf(type));
return this;
}
public CodeBuilder codeObject(String field, Class> type) {
if (type.isPrimitive()) {
body.append(getPrimitiveWrapper(type));
body.append(".valueOf(").append(field).append(")");
} else {
body.append(field);
}
return this;
}
public CodeBuilder construct(Class> javaClass, Object... args) {
body.append("new ").append(javaClass.getName()).append("(");
for (int i = 0; i < args.length; i++) {
if (i > 0) {
code(",");
}
insert(args[i]);
}
body.append(")");
return this;
}
public CodeBuilder staticInvoke(Method method, Object... args) {
code(method.getDeclaringClass().getName());
code(".").code(method.getName()).code("(");
for (int i = 0; i < args.length; i++) {
if (i > 0) {
code(",");
}
insert(args[i]);
}
code(")");
return this;
}
public CodeBuilder declareObject(Class> type, String var) {
code(getJavaClassCodeNameOf(type));
return code(" ").assign(var);
}
public CodeBuilder declareWrapper(Class> type, String var) {
if (type.isPrimitive()) {
code(getPrimitiveWrapper(type));
} else {
code(getJavaClassCodeNameOf(type));
}
return code(" ").assign(var);
}
public abstract CodeBuilder end();
public CodeBuilder insert(boolean b) {
body.append(b);
return this;
}
public CodeBuilder insert(char c) {
body.append("'").append(c).append("'");
return this;
}
public CodeBuilder insert(Class> javaClass) {
return insert(klass.get(javaClass));
}
public CodeBuilder insertObjectClass(String className) {
body.append(ClassFactory.class.getName());
body.append(".classForName(\"");
body.append(className);
body.append("\", ").append(Class.class.getName());
body.append(".forName(\"").append(klass.getName()).append("\")");
body.append(".getClassLoader())");
return this;
}
public CodeBuilder insert(double d) {
body.append(d);
return this;
}
public CodeBuilder insert(float f) {
body.append(f);
return this;
}
public CodeBuilder insert(int i) {
body.append(i);
return this;
}
public CodeBuilder insert(long lng) {
body.append(lng);
return this;
}
public CodeBuilder insert(Method method) {
Class> declaringClass = method.getDeclaringClass();
String name = method.getName();
Class>[] params = method.getParameterTypes();
CodeBuilder cb = klass.getCodeBuilder();
String var = cb.methodVars.get(method);
if (var == null) {
var = cb.getVarName("Method");
} else {
body.append(var);
return this;
}
String before = toString();
clear();
String parameterTypes = declareVar(params, cb);
CodeBuilder field = klass.assignStaticField(Method.class, var);
field.insert(declaringClass);
field.code(".getDeclaredMethod(").insert(name);
field.code(", ").code(parameterTypes).code(")").end();
cb.methodVars.put(method, var);
code(before);
body.append(var);
return this;
}
public CodeBuilder insert(Object o) {
if (o == null) {
body.append("null");
} else {
visit(o, o.getClass());
}
return this;
}
public CodeBuilder insert(String str) {
if (str == null) {
body.append("null");
} else {
body.append("\"").append(str).append("\"");
}
return this;
}
public CodeBuilder insert(Class>[] params) {
CodeBuilder cb = klass.getCodeBuilder();
String parameterTypes = declareVar(params, cb);
String var = cb.getVarName("Classes");
CodeBuilder field = klass.assignStaticField(params.getClass(), var);
field.code(parameterTypes).end();
body.append(var);
return this;
}
public CodeBuilder insertMethod(String name, Class>[] params) {
CtClass cc = klass.getCtClass();
String className = Descriptor.toJavaName(Descriptor.toJvmName(cc));
List> list = Arrays.asList(params);
CodeBuilder cb = klass.getCodeBuilder();
Map>, String> map = cb.methodTemplateVars.get(name);
if (map == null) {
cb.methodTemplateVars.put(name, map = new HashMap());
} else {
if (map.containsKey(list)) {
body.append(map.get(list));
return this;
}
}
String parameterTypes = declareVar(params, cb);
String var = cb.getVarName("Method");
CodeBuilder field = klass.assignStaticField(Method.class, var);
field.insertObjectClass(className);
field.code(".getDeclaredMethod(").insert(name);
field.code(", ").code(parameterTypes).code(")").end();
map.put(list, var);
body.append(var);
return this;
}
public int length() {
return body.length();
}
public CodeBuilder semi() {
body.append(";\n");
return this;
}
@Override
public String toString() {
return body.toString();
}
protected void clear() {
body.delete(0, length());
}
protected ClassMemberValue createClassMemberValue(Class> type, ConstPool cp) {
int idx = cp.addUtf8Info(descriptor(type));
return new ClassMemberValue(idx, cp);
}
public static String descriptor(Class> type) {
if (type.isArray())
return "[" + descriptor(type.getComponentType());
if (Void.TYPE.equals(type))
return "V";
if (Integer.TYPE.equals(type))
return "I";
if (Byte.TYPE.equals(type))
return "B";
if (Long.TYPE.equals(type))
return "J";
if (Double.TYPE.equals(type))
return "D";
if (Float.TYPE.equals(type))
return "F";
if (Character.TYPE.equals(type))
return "C";
if (Short.TYPE.equals(type))
return "S";
if (Boolean.TYPE.equals(type))
return "Z";
return "L" + type.getName().replace('.', '/') + ";";
}
private String declareVar(Class>[] classes, CodeBuilder cb) {
String var = cb.getVarName("Classes");
cb.code("java.lang.Class[] ").code(var);
cb.code(" = ").code("new java.lang.Class[");
cb.insert(classes.length).code("]").code(";\n");
for (int i = 0; i < classes.length; i++) {
cb.code(var).code("[").insert(i).code("]");
cb.code(" = ");
cb.insert(classes[i]);
cb.code(";\n");
}
return var;
}
private String getJavaClassCodeNameOf(Class> type) {
return klass.get(type).getName();
}
private Class> getPrimitiveJavaClassWrapper(CtClass cc) {
if (cc.equals(CtClass.booleanType))
return Boolean.class;
if (cc.equals(CtClass.byteType))
return Byte.class;
if (cc.equals(CtClass.charType))
return Character.class;
if (cc.equals(CtClass.doubleType))
return Double.class;
if (cc.equals(CtClass.floatType))
return Float.class;
if (cc.equals(CtClass.intType))
return Integer.class;
if (cc.equals(CtClass.longType))
return Long.class;
if (cc.equals(CtClass.shortType))
return Short.class;
throw new AssertionError();
}
private String getPrimitiveWrapper(Class> type) {
String wrap;
if (boolean.class.equals(type)) {
wrap = Boolean.class.getName();
} else if (char.class.equals(type)) {
wrap = Character.class.getName();
} else if (int.class.equals(type)) {
wrap = Integer.class.getName();
} else {
String prim = type.getName();
wrap = Character.toUpperCase(prim.charAt(0)) + prim.substring(1);
}
return wrap;
}
private String getVarName(String type) {
return "_$" + type + varCounter++;
}
private CodeBuilder insert(CtClass cc) {
if (cc.isPrimitive()) {
body.append(getPrimitiveJavaClassWrapper(cc).getName())
.append(".TYPE");
return this;
}
return insertObjectClass(Descriptor.toJavaName(Descriptor.toJvmName(cc)));
}
private boolean visit(Object o, Class oc) {
try {
Class c = getClass();
Class[] args = new Class[] { oc };
Method m = c.getMethod("insert", args);
m.invoke(this, o);
return true;
} catch (NoSuchMethodException e) {
Class sc = oc.getSuperclass();
if (sc != null && !Object.class.equals(sc)) {
if (visit(o, sc))
return true;
}
for (Class face : oc.getInterfaces()) {
if (visit(o, face))
return true;
}
return false;
} catch (IllegalArgumentException e) {
throw new ObjectCompositionException(e);
} catch (IllegalAccessException e) {
throw new ObjectCompositionException(e);
} catch (InvocationTargetException e) {
throw new ObjectCompositionException(e);
}
}
}