package org.javabuilders.swing.plugin.glazedlists.compiler;
import java.util.Calendar;
import java.util.Comparator;
import java.util.List;
import java.util.Random;
import org.codehaus.janino.ClassBodyEvaluator;
import org.codehaus.janino.CompileException;
import org.codehaus.janino.Parser.ParseException;
import org.codehaus.janino.Scanner.ScanException;
import org.javabuilders.BuildException;
import org.javabuilders.util.PropertyUtils;
public class CompilerUtils {
private static final Random RANDOM = new Random();
/**
* Compiles source code into a class that gets loaded in the current classloader
* @param fullName
* @param classBody
* @return
* @throws ClassNotFoundException
* @throws ScanException
* @throws ParseException
* @throws CompileException
*/
public static Class<?> compile(String className, String classBody, Class<?> type, Class<?>...interfaces) throws Exception {
ClassBodyEvaluator eval = new ClassBodyEvaluator();
eval.setParentClassLoader(Thread.currentThread().getContextClassLoader());
eval.setClassName(className);
eval.setExtendedType(type);
eval.setImplementedTypes(interfaces);
eval.cook(classBody);
return eval.getClazz();
}
/**
* Generates a guaranteed unique class name
* @param baseClass
* @return
*/
public static String generateClassName(Class<?> baseClass) {
//return PACKAGE_NAME + baseClass.getSimpleName() + "_" + Math.random() + "_" + Calendar.getInstance().getTimeInMillis();
return baseClass.getSimpleName() + "_" + Math.abs(RANDOM.nextInt()) + "_" + Calendar.getInstance().getTimeInMillis();
}
/**
* Compiles a new comparator
* @param type Type
* @param fields Fields to be included in comparator
* @return
*/
@SuppressWarnings("unchecked")
public static Comparator newComparator(Class<?> type, List<String> fields) {
return newComparator(type, fields.toArray(new String[fields.size()]));
}
/**
* Compiles a new comparator
* @param rawType Type
* @param fields Fields to be included in comparator
* @return
*/
public static Comparator<?> newComparator(Class<?> rawType, String... fields) {
Comparator<?> c = null;
ClassStringBuilder bld = new ClassStringBuilder();
String name = generateClassName(Comparator.class);
Class<?> type = rawType;
if (type.isPrimitive()) {
if (int.class.equals(type)) {
type = Integer.class;
} else if (long.class.equals(type)) {
type = Long.class;
} else if (short.class.equals(type)) {
type = Short.class;
} else if (double.class.equals(type)) {
type = Double.class;
} else if (float.class.equals(type)) {
type = Float.class;
} else if (boolean.class.equals(type)) {
type = Boolean.class;
}
}
bld.___("public int compare(Object ob1, Object ob2) {")
._____("int compare = 0;")
._____("%1$s o1 = (%1$s)ob1;",type.getName())
._____("%1$s o2 = (%1$s)ob2;",type.getName());
//create the comparison for each column
if (fields.length == 0) {
//build a Comparator against the class itself
bld._____("compare = o1.compareTo(o2);");
} else {
//build a Comparator against the class's fields
for(String col : fields) {
bld._____("if (compare == 0) {");
String getter = PropertyUtils.getGetterName(col);
Class<?> returnType = PropertyUtils.verifyGetter(type, getter,short.class,Short.class,int.class,Integer.class,long.class,Long.class,double.class,
Double.class,String.class,char.class,Character.class,Comparable.class);
if (returnType.isPrimitive()) {
bld._______("compare = o1.%1$s() - o2.%1$s();",getter);
} else {
bld._______("compare = o1.%1$s().compareTo(o2.%1$s());",getter);
}
bld._____("}");
}
}
bld._____("return compare;");
bld.___("}");
try {
Class<?> comparatorClass = compile(name, bld.toString(),Object.class,Comparator.class);
c = (Comparator<?>)comparatorClass.newInstance();
return c;
} catch (Exception e) {
throw new BuildException("Failed to compile Comparator: {0}\n{1}",e.getMessage(),bld.toString());
}
}
}