Package org.jboss.errai.codegen.util

Source Code of org.jboss.errai.codegen.util.PrivateAccessUtil

package org.jboss.errai.codegen.util;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

import org.jboss.errai.codegen.Cast;
import org.jboss.errai.codegen.DefParameters;
import org.jboss.errai.codegen.Modifier;
import org.jboss.errai.codegen.Parameter;
import org.jboss.errai.codegen.Statement;
import org.jboss.errai.codegen.StringStatement;
import org.jboss.errai.codegen.builder.BlockBuilder;
import org.jboss.errai.codegen.builder.CatchBlockBuilder;
import org.jboss.errai.codegen.builder.ClassStructureBuilder;
import org.jboss.errai.codegen.builder.ContextualStatementBuilder;
import org.jboss.errai.codegen.builder.MethodBlockBuilder;
import org.jboss.errai.codegen.builder.MethodCommentBuilder;
import org.jboss.errai.codegen.meta.MetaClass;
import org.jboss.errai.codegen.meta.MetaClassFactory;
import org.jboss.errai.codegen.meta.MetaConstructor;
import org.jboss.errai.codegen.meta.MetaField;
import org.jboss.errai.codegen.meta.MetaMethod;
import org.jboss.errai.codegen.meta.MetaParameter;

/**
* @author Mike Brock
*/
public class PrivateAccessUtil {
  private static final String JAVA_REFL_FLD_UTIL_METH = "_getAccessibleField";
  private static final String JAVA_REFL_METH_UTIL_METH = "_getAccessibleMethod";
  private static final String JAVA_REFL_CONSTRUCTOR_UTIL_METH = "_getAccessibleConstructor";

  public static void createJavaReflectionFieldInitializerUtilMethod(ClassStructureBuilder<?> classBuilder) {

    if (classBuilder.getClassDefinition().getMethod(JAVA_REFL_FLD_UTIL_METH, Class.class, Field.class) != null) {
      return;
    }

    classBuilder.privateMethod(Field.class, JAVA_REFL_FLD_UTIL_METH).modifiers(Modifier.Static)
            .parameters(DefParameters.of(Parameter.of(Class.class, "cls"), Parameter.of(String.class, "name")))
            .body()
            ._(Stmt.try_()
                    ._(Stmt.declareVariable("fld", Stmt.loadVariable("cls").invoke("getDeclaredField",
                            Stmt.loadVariable("name"))))
                    ._(Stmt.loadVariable("fld").invoke("setAccessible", true))
                    ._(Stmt.loadVariable("fld").returnValue())
                    .finish()
                    .catch_(Throwable.class, "e")
                    ._(Stmt.loadVariable("e").invoke("printStackTrace"))
                    ._(Stmt.throw_(RuntimeException.class, Refs.get("e")))
                    .finish())
            .finish();
  }

  public static void createJavaReflectionMethodInitializerUtilMethod(
          ClassStructureBuilder<?> classBuilder) {

    if (classBuilder.getClassDefinition().getMethod(JAVA_REFL_METH_UTIL_METH, Class.class, String.class, Class[].class) != null) {
      return;
    }

    classBuilder.privateMethod(Method.class, JAVA_REFL_METH_UTIL_METH).modifiers(Modifier.Static)
            .parameters(DefParameters.of(Parameter.of(Class.class, "cls"), Parameter.of(String.class, "name"),
                    Parameter.of(Class[].class, "parms")))
            .body()
            ._(Stmt.try_()
                    ._(Stmt.declareVariable("meth", Stmt.loadVariable("cls").invoke("getDeclaredMethod",
                            Stmt.loadVariable("name"), Stmt.loadVariable("parms"))))
                    ._(Stmt.loadVariable("meth").invoke("setAccessible", true))
                    ._(Stmt.loadVariable("meth").returnValue())
                    .finish()
                    .catch_(Throwable.class, "e")
                    ._(Stmt.loadVariable("e").invoke("printStackTrace"))
                    ._(Stmt.throw_(RuntimeException.class, Refs.get("e")))
                    .finish())
            .finish();
  }

  public static void createJavaReflectionConstructorInitializerUtilMethod(
      ClassStructureBuilder<?> classBuilder) {

    if (classBuilder.getClassDefinition().getMethod(JAVA_REFL_CONSTRUCTOR_UTIL_METH, Class.class,
        Class[].class) != null) {
      return;
    }

    classBuilder.privateMethod(Constructor.class, JAVA_REFL_CONSTRUCTOR_UTIL_METH).modifiers(Modifier.Static)
        .parameters(DefParameters.of(Parameter.of(Class.class, "cls"), Parameter.of(Class[].class, "parms")))
        .body()
        ._(Stmt.try_()
                ._(Stmt.declareVariable("cons", Stmt.loadVariable("cls").invoke("getDeclaredConstructor",
                    Stmt.loadVariable("parms"))))
                ._(Stmt.loadVariable("cons").invoke("setAccessible", true))
                ._(Stmt.loadVariable("cons").returnValue())
                .finish()
                .catch_(Throwable.class, "e")
                ._(Stmt.loadVariable("e").invoke("printStackTrace"))
                ._(Stmt.throw_(RuntimeException.class, Refs.get("e")))
                .finish())
        .finish();
  }

  public static String initCachedField(ClassStructureBuilder<?> classBuilder, MetaField f) {
    createJavaReflectionFieldInitializerUtilMethod(classBuilder);

    String fieldName = getPrivateFieldInjectorName(f) + "_fld";

    classBuilder.privateField(fieldName, Field.class).modifiers(Modifier.Static)
            .initializesWith(Stmt.invokeStatic(classBuilder.getClassDefinition(), JAVA_REFL_FLD_UTIL_METH,
                    f.getDeclaringClass(), f.getName())).finish();

    return fieldName;
  }

  public static String initCachedMethod(ClassStructureBuilder<?> classBuilder, MetaMethod m) {
    createJavaReflectionMethodInitializerUtilMethod(classBuilder);

    String fieldName = getPrivateMethodName(m) + "_meth";

    classBuilder.privateField(fieldName, Method.class).modifiers(Modifier.Static)
            .initializesWith(Stmt.invokeStatic(classBuilder.getClassDefinition(), JAVA_REFL_METH_UTIL_METH,
                    m.getDeclaringClass(), m.getName(), MetaClassFactory.asClassArray(m.getParameters()))).finish();

    return fieldName;
  }

  public static String initCachedMethod(ClassStructureBuilder<?> classBuilder, MetaConstructor c) {
    createJavaReflectionConstructorInitializerUtilMethod(classBuilder);

    String fieldName = getPrivateMethodName(c) + "_meth";

    classBuilder.privateField(fieldName, Constructor.class).modifiers(Modifier.Static)
            .initializesWith(Stmt.invokeStatic(classBuilder.getClassDefinition(), JAVA_REFL_CONSTRUCTOR_UTIL_METH,
                    c.getDeclaringClass(), MetaClassFactory.asClassArray(c.getParameters()))).finish();

    return fieldName;
  }

  public static void addPrivateAccessStubs(boolean useJSNIStubs,
                                           ClassStructureBuilder<?> classBuilder,
                                           MetaField f) {
    addPrivateAccessStubs(PrivateAccessType.Both, useJSNIStubs, classBuilder, f);
  }

  public static void addPrivateAccessStubs(PrivateAccessType accessType,
                                           boolean useJSNIStubs,
                                           ClassStructureBuilder<?> classBuilder,
                                           MetaField f) {
    MetaClass type = f.getType();
    if (type.getCanonicalName().equals("long")) {
      type = type.asBoxed();
    }

    boolean read = accessType == PrivateAccessType.Read || accessType == PrivateAccessType.Both;
    boolean write = accessType == PrivateAccessType.Write || accessType == PrivateAccessType.Both;

    if (useJSNIStubs) {
      if (write) {
        final MethodCommentBuilder<? extends ClassStructureBuilder<?>> methodBuilder =
            classBuilder.privateMethod(void.class, getPrivateFieldInjectorName(f));

        if (!f.isStatic()) {
          methodBuilder
                  .parameters(DefParameters.fromParameters(Parameter.of(f.getDeclaringClass(), "instance"),
                          Parameter.of(type, "value")));
        }

        methodBuilder.modifiers(Modifier.Static, Modifier.JSNI)
                .body()
                ._(new StringStatement(JSNIUtil.fieldAccess(f) + " = value"))
                .finish();
      }

      if (read) {
        MethodBlockBuilder<? extends ClassStructureBuilder<?>> instance =
            classBuilder.privateMethod(type, getPrivateFieldInjectorName(f));

        if (!f.isStatic()) {
          instance.parameters(DefParameters.fromParameters(Parameter.of(f.getDeclaringClass(), "instance")));
        }

        instance.modifiers(Modifier.Static, Modifier.JSNI)
                .body()
                ._(new StringStatement("return " + JSNIUtil.fieldAccess(f)))
                .finish();
      }
    }
    else {
      /**
       * Reflection stubs
       */

      String cachedField = initCachedField(classBuilder, f);
      String setterName = _getReflectionFieldMethSetName(f);

      if (write) {
        MethodCommentBuilder<? extends ClassStructureBuilder<?>> methodBuilder =
            classBuilder.privateMethod(void.class, getPrivateFieldInjectorName(f));

        if (!f.isStatic()) {
          methodBuilder
                  .parameters(DefParameters.fromParameters(Parameter.of(f.getDeclaringClass(), "instance"),
                          Parameter.of(f.getType(), "value")));
        }

        methodBuilder.modifiers(Modifier.Static)
                .body()
                ._(Stmt.try_()
                        ._(Stmt.loadVariable(cachedField).invoke(setterName, Refs.get("instance"), Refs.get("value")))
                        .finish()
                        .catch_(Throwable.class, "e")
                        ._(Stmt.loadVariable("e").invoke("printStackTrace"))
                        ._(Stmt.throw_(RuntimeException.class, Refs.get("e")))
                        .finish())
                .finish();
      }

      String getterName = _getReflectionFieldMethGetName(f);

      if (read) {
        MethodCommentBuilder<? extends ClassStructureBuilder<?>> methodBuilder =
            classBuilder.privateMethod(f.getType(), getPrivateFieldInjectorName(f));

        if (!f.isStatic()) {
          methodBuilder
                  .parameters(DefParameters.fromParameters(Parameter.of(f.getDeclaringClass(), "instance")));
        }

        methodBuilder.modifiers(Modifier.Static)
                .body()
                ._(Stmt.try_()
                        ._(Stmt.nestedCall(Cast.to(f.getType(), Stmt.loadVariable(cachedField)
                                .invoke(getterName, f.isStatic() ? null : Refs.get("instance")))).returnValue())
                        .finish()
                        .catch_(Throwable.class, "e")
                        ._(Stmt.loadVariable("e").invoke("printStackTrace"))
                        ._(Stmt.throw_(RuntimeException.class, Refs.get("e")))
                        .finish())
                .finish();
      }
    }
  }

  public static void addPrivateAccessStubs(boolean useJSNIStubs, ClassStructureBuilder<?> classBuilder,
      MetaConstructor m) {
    DefParameters methodDefParms = DefParameters.from(m);

    if (useJSNIStubs) {
      classBuilder.publicMethod(m.getReturnType(), getPrivateMethodName(m))
              .parameters(methodDefParms)
              .modifiers(Modifier.Static, Modifier.JSNI)
              .body()
              ._(new StringStatement(JSNIUtil.methodAccess(m)))
              .finish();
    }
    else {
      String cachedMethod = initCachedMethod(classBuilder, m);
      Object[] args = new Object[methodDefParms.getParameters().size()];
      int i = 0;
      for (Parameter p : methodDefParms.getParameters()) {
        args[i++] = Refs.get(p.getName());
      }

      BlockBuilder<? extends ClassStructureBuilder> body = classBuilder.publicMethod(m.getReturnType(),
              getPrivateMethodName(m))
              .parameters(methodDefParms)
              .modifiers(Modifier.Static)
              .body();

      Statement tryBuilder =
          Stmt.try_()
              .append(
                  Stmt.nestedCall(
                      Stmt.castTo(m.getReturnType(), Stmt.loadVariable(cachedMethod).invoke("newInstance",
                          (Object) args))).returnValue())
              .finish()
              .catch_(Throwable.class, "e")
              .append(Stmt.loadVariable("e").invoke("printStackTrace"))
              .append(Stmt.throw_(RuntimeException.class, Refs.get("e")))
              .finish();

      ClassStructureBuilder finished = body.append(tryBuilder).finish();
    }
  }

  public static void addPrivateAccessStubs(boolean useJSNIStubs, ClassStructureBuilder<?> classBuilder, MetaMethod m) {
    List<Parameter> wrapperDefParms = new ArrayList<Parameter>();

    if (!m.isStatic()) {
      wrapperDefParms.add(Parameter.of(m.getDeclaringClass().getErased(), "instance"));
    }

    List<Parameter> methodDefParms = DefParameters.from(m).getParameters();
    wrapperDefParms.addAll(methodDefParms);

    if (useJSNIStubs) {
      classBuilder.publicMethod(m.getReturnType(), getPrivateMethodName(m))
              .parameters(DefParameters.fromParameters(wrapperDefParms))
              .modifiers(Modifier.Static, Modifier.JSNI)
              .body()
              ._(new StringStatement(JSNIUtil.methodAccess(m)))
              .finish();
    }
    else {
      String cachedMethod = initCachedMethod(classBuilder, m);

      Object[] args = new Object[methodDefParms.size()];

      int i = 0;
      for (Parameter p : methodDefParms) {
        args[i++] = Refs.get(p.getName());
      }

      BlockBuilder<? extends ClassStructureBuilder> body = classBuilder.publicMethod(m.getReturnType(),
              getPrivateMethodName(m))
              .parameters(DefParameters.fromParameters(wrapperDefParms))
              .modifiers(Modifier.Static)
              .body();

      BlockBuilder<CatchBlockBuilder> tryBuilder = Stmt.try_();

      ContextualStatementBuilder statementBuilder = Stmt.loadVariable(cachedMethod)
              .invoke("invoke", m.isStatic() ? null : Refs.get("instance"), args);

      if (m.getReturnType().isVoid()) {
        tryBuilder._(statementBuilder);
      }
      else {
        tryBuilder._(statementBuilder.returnValue());
      }

      ClassStructureBuilder finished = body._(tryBuilder
              .finish()
              .catch_(Throwable.class, "e")
              ._(Stmt.loadVariable("e").invoke("printStackTrace"))
              ._(Stmt.throw_(RuntimeException.class, Refs.get("e")))
              .finish())
              .finish();
    }
  }

  public static String getPrivateFieldInjectorName(MetaField field) {
    return field.getDeclaringClass()
            .getFullyQualifiedName().replaceAll("\\.", "_") + "_" + field.getName();
  }

  public static String getPrivateMethodName(MetaMethod method) {
    StringBuilder buf = new StringBuilder(method.getDeclaringClass()
            .getFullyQualifiedName().replaceAll("\\.", "_") + "_" + method.getName());

    for (MetaParameter parm : method.getParameters()) {
      buf.append('_').append(parm.getType().getFullyQualifiedName().replaceAll("\\.", "_"));
    }

    return buf.toString();
  }

  private static String _getReflectionFieldMethGetName(MetaField f) {
    MetaClass t = f.getType();

    if (!t.isPrimitive()) {
      return "get";
    }
    else if (t.getFullyQualifiedName().equals("int")) {
      return "getInt";
    }
    else if (t.getFullyQualifiedName().equals("short")) {
      return "getShort";
    }
    else if (t.getFullyQualifiedName().equals("boolean")) {
      return "getBoolean";
    }
    else if (t.getFullyQualifiedName().equals("double")) {
      return "getDouble";
    }
    else if (t.getFullyQualifiedName().equals("float")) {
      return "getFloat";
    }
    else if (t.getFullyQualifiedName().equals("byte")) {
      return "getByte";
    }
    else if (t.getFullyQualifiedName().equals("long")) {
      return "getLong";
    }
    else if (t.getFullyQualifiedName().equals("char")) {
      return "getChar";
    }
    return null;
  }

  private static String _getReflectionFieldMethSetName(MetaField f) {
    MetaClass t = f.getType();

    if (!t.isPrimitive()) {
      return "set";
    }
    else if (t.getFullyQualifiedName().equals("int")) {
      return "setInt";
    }
    else if (t.getFullyQualifiedName().equals("short")) {
      return "setShort";
    }
    else if (t.getFullyQualifiedName().equals("boolean")) {
      return "setBoolean";
    }
    else if (t.getFullyQualifiedName().equals("double")) {
      return "setDouble";
    }
    else if (t.getFullyQualifiedName().equals("float")) {
      return "setFloat";
    }
    else if (t.getFullyQualifiedName().equals("byte")) {
      return "setByte";
    }
    else if (t.getFullyQualifiedName().equals("long")) {
      return "setLong";
    }
    else if (t.getFullyQualifiedName().equals("char")) {
      return "setChar";
    }
    return null;
  }
}
TOP

Related Classes of org.jboss.errai.codegen.util.PrivateAccessUtil

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.