Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
play.utils.Java Maven / Gradle / Ivy
package play.utils;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.FutureTask;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.bytecode.SourceFileAttribute;
import play.Play;
import play.classloading.ApplicationClassloaderState;
import play.classloading.enhancers.LocalvariablesNamesEnhancer.LocalVariablesNamesTracer;
import play.data.binding.Binder;
import play.data.binding.ParamNode;
import play.data.binding.RootParamNode;
import play.exceptions.UnexpectedException;
import play.mvc.After;
import play.mvc.Before;
import play.mvc.Finally;
import play.mvc.With;
/**
* Java utils
*/
public class Java {
protected static JavaWithCaching _javaWithCaching = new JavaWithCaching();
protected static ApplicationClassloaderState _lastKnownApplicationClassloaderState = Play.classloader.currentState;
protected static Object _javaWithCachingLock = new Object();
protected static JavaWithCaching getJavaWithCaching() {
synchronized( _javaWithCachingLock ) {
// has the state of the ApplicationClassloader changed?
ApplicationClassloaderState currentApplicationClasloaderState = Play.classloader.currentState;
if( !currentApplicationClasloaderState.equals( _lastKnownApplicationClassloaderState )) {
// it has changed.
// we must drop our current _javaWithCaching and create a new one...
// and start the caching over again.
_lastKnownApplicationClassloaderState = currentApplicationClasloaderState;
_javaWithCaching = new JavaWithCaching();
}
return _javaWithCaching;
}
}
public static String[] extractInfosFromByteCode(byte[] code) {
try {
CtClass ctClass = ClassPool.getDefault().makeClass(new ByteArrayInputStream(code));
String sourceName = ((SourceFileAttribute) ctClass.getClassFile().getAttribute("SourceFile")).getFileName();
return new String[]{ctClass.getName(), sourceName};
} catch (Exception e) {
throw new UnexpectedException("Cannot read a scala generated class using javassist", e);
}
}
/**
* Try to discover what is hidden under a FutureTask (hack)
*/
public static Object extractUnderlyingCallable(FutureTask> futureTask) {
try {
Object callable = null;
// Try to search for the Filed sync first, if not present will try filed callable
try{
Field syncField = FutureTask.class.getDeclaredField("sync");
syncField.setAccessible(true);
Object sync = syncField.get(futureTask);
if (sync != null) {
Field callableField = sync.getClass().getDeclaredField("callable");
callableField.setAccessible(true);
callable = callableField.get(sync);
}
} catch(NoSuchFieldException ex) {
Field callableField = FutureTask.class.getDeclaredField("callable");
callableField.setAccessible(true);
callable = callableField.get(futureTask);
}
if (callable != null && callable.getClass().getSimpleName().equals("RunnableAdapter")) {
Field taskField = callable.getClass().getDeclaredField("task");
taskField.setAccessible(true);
return taskField.get(callable);
}
return callable;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* Find the first public static method of a controller class
* @param name The method name
* @param clazz The class
* @return The method or null
*/
public static Method findActionMethod(String name, Class clazz) {
// We don't want to check the views
while (!clazz.getName().equals("java.lang.Object")) {
for (Method m : clazz.getDeclaredMethods()) {
if (m.getName().equalsIgnoreCase(name) && Modifier.isPublic(m.getModifiers())) {
// Check that it is not an intercepter
if (!m.isAnnotationPresent(Before.class) && !m.isAnnotationPresent(After.class) && !m.isAnnotationPresent(Finally.class)) {
return m;
}
}
}
clazz = clazz.getSuperclass();
}
return null;
}
/**
* Invoke a static method
* @param clazz The class
* @param method The method name
* @return The result
* @throws java.lang.Exception
*/
public static Object invokeStatic(Class> clazz, String method) throws Exception {
return invokeStatic(clazz, method, new Object[0]);
}
public static Object invokeStatic(String clazz, String method) throws Exception {
return invokeStatic(Play.classloader.loadClass(clazz), method, new Object[0]);
}
/**
* Invoke a static method with args
* @param clazz The class
* @param method The method name
* @param args Arguments
* @return The result
* @throws java.lang.Exception
*/
public static Object invokeStatic(Class> clazz, String method, Object... args) throws Exception {
Class[] types = new Class[args.length];
for (int i = 0; i < args.length; i++) {
types[i] = args[i].getClass();
}
Method m = clazz.getDeclaredMethod(method, types);
m.setAccessible(true);
return m.invoke(null, args);
}
public static Object invokeStaticOrParent(Class> clazz, String method, Object... args) throws Exception {
Class[] types = new Class[args.length];
for (int i = 0; i < args.length; i++) {
types[i] = args[i].getClass();
}
Method m = null;
while (!clazz.equals(Object.class) && m == null) {
try {
m = clazz.getDeclaredMethod(method, types);
} catch (Exception e) {
clazz = clazz.getSuperclass();
}
}
if (m != null) {
m.setAccessible(true);
if (Modifier.isStatic(m.getModifiers())) {
return m.invoke(null, args);
} else {
Object instance = m.getDeclaringClass().getDeclaredField("MODULE$").get(null);
return m.invoke(instance, args);
}
}
throw new NoSuchMethodException(method);
}
public static Object invokeChildOrStatic(Class> clazz, String method, Object... args) throws Exception {
Class invokedClass = null;
List assignableClasses = Play.classloader.getAssignableClasses(clazz);
if(assignableClasses.size() == 0)
{
invokedClass = clazz;
}
else
{
invokedClass = assignableClasses.get(0);
}
return Java.invokeStaticOrParent(invokedClass, method, args);
}
public static Object invokeStatic(Method method, Map args) throws Exception {
return method.invoke(null, prepareArgs(method, args));
}
public static Object invokeStatic(Method method, Object[] args) throws Exception {
return method.invoke(null, args);
}
static Object[] prepareArgs(Method method, Map args) throws Exception {
String[] paramsNames = parameterNames(method);
if (paramsNames == null && method.getParameterTypes().length > 0) {
throw new UnexpectedException("Parameter names not found for method " + method);
}
RootParamNode rootParamNode = ParamNode.convert(args);
Object[] rArgs = new Object[method.getParameterTypes().length];
for (int i = 0; i < method.getParameterTypes().length; i++) {
rArgs[i] = Binder.bind(rootParamNode, paramsNames[i], method.getParameterTypes()[i], method.getGenericParameterTypes()[i], method.getParameterAnnotations()[i]);
}
return rArgs;
}
/**
* Retrieve parameter names of a method
*/
public static String[] parameterNames(Method method) throws Exception {
try {
return (String[]) method.getDeclaringClass().getDeclaredField("$" + method.getName() + LocalVariablesNamesTracer.computeMethodHash(method.getParameterTypes())).get(null);
} catch (Exception e) {
throw new UnexpectedException("Cannot read parameter names for " + method);
}
}
public static String rawMethodSignature(Method method) {
StringBuilder sig = new StringBuilder();
sig.append(method.getDeclaringClass().getName());
sig.append(".");
sig.append(method.getName());
sig.append('(');
for (Class clazz : method.getParameterTypes()) {
sig.append(rawJavaType(clazz));
}
sig.append(")");
sig.append(rawJavaType(method.getReturnType()));
return sig.toString();
}
public static String rawJavaType(Class clazz) {
if (clazz.getName().equals("void")) {
return "V";
}
if (clazz.getName().equals("boolean")) {
return "Z";
}
if (clazz.getName().equals("byte")) {
return "B";
}
if (clazz.getName().equals("char")) {
return "C";
}
if (clazz.getName().equals("double")) {
return "D";
}
if (clazz.getName().equals("float")) {
return "F";
}
if (clazz.getName().equals("int")) {
return "I";
}
if (clazz.getName().equals("long")) {
return "J";
}
if (clazz.getName().equals("short")) {
return "S";
}
if (clazz.getName().startsWith("[")) {
return clazz.getName().replace('.', '/');
}
return "L" + (clazz.getName().replace('.', '/')) + ";";
}
/**
* Find all annotated method from a class
* @param clazz The class
* @param annotationType The annotation class
* @return A list of method object
*/
public static List findAllAnnotatedMethods(Class> clazz, Class extends Annotation> annotationType) {
return getJavaWithCaching().findAllAnnotatedMethods(clazz, annotationType);
}
/**
* Find all annotated method from a class
* @param classes The classes
* @param annotationType The annotation class
* @return A list of method object
*/
public static List findAllAnnotatedMethods(List classes, Class extends Annotation> annotationType) {
List methods = new ArrayList();
for (Class clazz : classes) {
methods.addAll(findAllAnnotatedMethods(clazz, annotationType));
}
return methods;
}
public static void findAllFields(Class clazz, Set found) {
Field[] fields = clazz.getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
found.add(fields[i]);
}
Class sClazz = clazz.getSuperclass();
if (sClazz != null && sClazz != Object.class) {
findAllFields(sClazz, found);
}
}
/** cache */
private static Map wrappers = new HashMap();
public static FieldWrapper getFieldWrapper(Field field) {
if (wrappers.get(field) == null) {
FieldWrapper fw = new FieldWrapper(field);
if (play.Logger.isTraceEnabled()) {
play.Logger.trace("caching %s", fw);
}
wrappers.put(field, fw);
}
return wrappers.get(field);
}
public static byte[] serialize(Object o) throws Exception {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oo = new ObjectOutputStream(baos);
oo.writeObject(o);
oo.flush();
oo.close();
return baos.toByteArray();
}
public static Object deserialize(byte[] b) throws Exception {
ByteArrayInputStream bais = new ByteArrayInputStream(b);
ObjectInputStream oi = new ObjectInputStream(bais);
return oi.readObject();
}
/**
* Field accessor
* set and get value for a property, using the getter/setter when it exists or direct access otherwise.
* final, native or static properties are safely ignored
*/
public static class FieldWrapper {
final static int unwritableModifiers = Modifier.FINAL | Modifier.NATIVE | Modifier.STATIC;
private Method setter;
private Method getter;
private Field field;
private boolean writable;
private boolean accessible;
private FieldWrapper(Method setter, Method getter) {
this.setter = setter;
this.getter = getter;
}
private FieldWrapper(Field field) {
this.field = field;
accessible = field.isAccessible();
writable = ((field.getModifiers() & unwritableModifiers) == 0);
String property = field.getName();
try {
String setterMethod = "set" + property.substring(0, 1).toUpperCase() + property.substring(1);
setter = field.getDeclaringClass().getMethod(setterMethod, field.getType());
} catch (Exception ex) {
}
try {
String getterMethod = "get" + property.substring(0, 1).toUpperCase() + property.substring(1);
getter = field.getDeclaringClass().getMethod(getterMethod);
} catch (Exception ex) {
}
}
public boolean isModifiable() {
return writable;
}
public void setValue(Object instance, Object value) {
if (!writable) {
return;
}
try {
if (setter != null) {
if (play.Logger.isTraceEnabled()) {
play.Logger.trace("invoke setter %s on %s with value %s", setter, instance, value);
}
setter.invoke(instance, value);
} else {
if (!accessible) {
field.setAccessible(true);
}
if (play.Logger.isTraceEnabled()) {
play.Logger.trace("field.set(%s, %s)", instance, value);
}
field.set(instance, value);
if (!accessible) {
field.setAccessible(accessible);
}
}
} catch (Exception ex) {
play.Logger.info("ERROR: when setting value for field %s - %s", field, ex);
}
}
public Object getValue(Object instance) {
try {
if (getter != null) {
return getter.invoke(instance);
} else {
return field.get(instance);
}
} catch (Exception ex) {
play.Logger.info("ERROR: when getting value for field %s - %s", field, ex);
}
return null;
}
@Override
public String toString() {
return "FieldWrapper (" + (writable ? "RW" : "R ") + ") for " + field;
}
}
}
/**
* This is an internal class uses only by the Java-class.
* It contains functionality with caching..
*
* The idea is that the Java-objects creates a new instance of JavaWithCaching,
* each time something new is compiled..
*
*/
class JavaWithCaching {
/**
* Class uses as key for storing info about the relation between a Class and an Annotation
*/
private static class ClassAndAnnotation {
private final Class> clazz;
private final Class extends Annotation> annotation;
private ClassAndAnnotation(Class> clazz, Class extends Annotation> annotation) {
this.clazz = clazz;
this.annotation = annotation;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ClassAndAnnotation that = (ClassAndAnnotation) o;
if (annotation != null ? !annotation.equals(that.annotation) : that.annotation != null) return false;
if (clazz != null ? !clazz.equals(that.clazz) : that.clazz != null) return false;
return true;
}
@Override
public int hashCode() {
int result = clazz != null ? clazz.hashCode() : 0;
result = 31 * result + (annotation != null ? annotation.hashCode() : 0);
return result;
}
}
// cache follows..
private final Object classAndAnnotationsLock = new Object();
private final Map> classAndAnnotation2Methods = new HashMap>();
private final Map, List> class2AllMethodsWithAnnotations = new HashMap, List>();
/**
* Find all annotated method from a class
* @param clazz The class
* @param annotationType The annotation class
* @return A list of method object
*/
public List findAllAnnotatedMethods(Class> clazz, Class extends Annotation> annotationType) {
if( clazz == null ) {
return new ArrayList(0);
}
synchronized( classAndAnnotationsLock ) {
// first look in cache
ClassAndAnnotation key = new ClassAndAnnotation(clazz, annotationType);
List methods = classAndAnnotation2Methods.get( key );
if( methods != null ) {
// cache hit
return methods;
}
// have to resolve it.
methods = new ArrayList();
// get list of all annotated methods on this class..
for( Method method : findAllAnnotatedMethods( clazz)) {
if (method.isAnnotationPresent(annotationType)) {
methods.add(method);
}
}
// store it in cache
classAndAnnotation2Methods.put( key, methods);
return methods;
}
}
/**
* Find all annotated method from a class
* @param clazz The class
* @return A list of method object
*/
public List findAllAnnotatedMethods(Class> clazz) {
synchronized( classAndAnnotationsLock ) {
// first check the cache..
List methods = class2AllMethodsWithAnnotations.get(clazz);
if( methods != null ) {
// cache hit
return methods;
}
//have to resolve it..
methods = new ArrayList();
// Clazz can be null if we are looking at an interface / annotation
while (clazz != null && !clazz.equals(Object.class)) {
for (Method method : clazz.getDeclaredMethods()) {
if (method.getAnnotations().length > 0) {
methods.add(method);
}
}
if (clazz.isAnnotationPresent(With.class)) {
for (Class withClass : clazz.getAnnotation(With.class).value()) {
methods.addAll(findAllAnnotatedMethods(withClass ));
}
}
clazz = clazz.getSuperclass();
}
//store it in the cache.
class2AllMethodsWithAnnotations.put(clazz, methods);
return methods;
}
}
}