Beispiel #1
1
 @Override
 public int hashCode() {
   int result = super.hashCode();
   result = 31 * result + (context != null ? context.hashCode() : 0);
   result = 31 * result + (className != null ? className.hashCode() : 0);
   result = 31 * result + (superClass != null ? superClass.hashCode() : 0);
   result = 31 * result + (interfaces != null ? interfaces.hashCode() : 0);
   result = 31 * result + (scope != null ? scope.hashCode() : 0);
   result = 31 * result + (isArray ? 1 : 0);
   result = 31 * result + dimensions;
   result = 31 * result + (isInterface ? 1 : 0);
   result = 31 * result + (isAbstract ? 1 : 0);
   result = 31 * result + (isFinal ? 1 : 0);
   result = 31 * result + (isStatic ? 1 : 0);
   result = 31 * result + (isInner ? 1 : 0);
   result = 31 * result + (methods != null ? methods.hashCode() : 0);
   result = 31 * result + (fields != null ? fields.hashCode() : 0);
   result = 31 * result + (constructors != null ? constructors.hashCode() : 0);
   result = 31 * result + (typeVariables != null ? typeVariables.hashCode() : 0);
   result = 31 * result + (reifiedFormOf != null ? reifiedFormOf.hashCode() : 0);
   result = 31 * result + (_nameCache != null ? _nameCache.hashCode() : 0);
   result = 31 * result + (_methodsCache != null ? Arrays.hashCode(_methodsCache) : 0);
   result = 31 * result + (_fieldsCache != null ? Arrays.hashCode(_fieldsCache) : 0);
   result = 31 * result + (_constructorsCache != null ? Arrays.hashCode(_constructorsCache) : 0);
   result = 31 * result + (generatedCache != null ? generatedCache.hashCode() : 0);
   return result;
 }
Beispiel #2
0
  @Override
  public Collection<MetaClass> provideTypesToExpose() {
    final Set<MetaClass> types = new HashSet<MetaClass>();
    for (final MetaClass metaClass : ClassScanner.getTypesAnnotatedWith(Remote.class)) {
      for (final MetaMethod method : metaClass.getDeclaredMethods()) {
        if (!method.getReturnType().isVoid()) {
          types.add(method.getReturnType().getErased());
        }
        for (final MetaParameter parameter : method.getParameters()) {
          final MetaClass type = parameter.getType();

          types.add(type.getErased());

          final MetaParameterizedType parameterizedType = type.getParameterizedType();
          if (parameterizedType != null) {
            for (final MetaType tp : parameterizedType.getTypeParameters()) {
              if (tp instanceof MetaClass) {
                types.add(((MetaClass) tp).getErased());
              }
            }
          }
        }
      }
    }
    return types;
  }
 private static List<MetaField> getAllFields(MetaClass c) {
   ArrayList<MetaField> fields = new ArrayList<MetaField>();
   for (; c != null; c = c.getSuperClass()) {
     fields.addAll(Arrays.asList(c.getDeclaredFields()));
   }
   return fields;
 }
Beispiel #4
0
  public static MetaMethod findCaseInsensitiveMatch(
      final MetaClass retType, final MetaClass clazz, final String name, final MetaClass... parms) {
    MetaClass c = clazz;

    do {
      Outer:
      for (final MetaMethod method : c.getDeclaredMethods()) {
        if (name.equalsIgnoreCase(method.getName())) {
          if (parms.length != method.getParameters().length) continue;

          final MetaParameter[] mps = method.getParameters();
          for (int i = 0; i < parms.length; i++) {
            if (!parms[i]
                .getFullyQualifiedName()
                .equals(mps[i].getType().getFullyQualifiedName())) {
              continue Outer;
            }
          }

          if (retType != null
              && !retType
                  .getFullyQualifiedName()
                  .equals(method.getReturnType().getFullyQualifiedName())) {
            continue;
          }

          return method;
        }
      }
    } while ((c = c.getSuperClass()) != null);

    return null;
  }
Beispiel #5
0
 public static BuildMetaClass makeProxy(final MetaClass toProxy,
                                        final String privateAccessorType,
                                        final Map<String, ProxyProperty> proxyProperties,
                                        final Map<MetaMethod, Map<WeaveType, Collection<Statement>>> weavingStatements) {
   return makeProxy(
       PrivateAccessUtil.condensify(toProxy.getPackageName()) + "_" + toProxy.getName() + "_proxy",
       toProxy,
       privateAccessorType, proxyProperties, weavingStatements);
 }
Beispiel #6
0
  public static int getArrayDimensions(final MetaClass type) {
    if (!type.isArray()) return 0;

    final String internalName = type.getInternalName();
    for (int i = 0; i < internalName.length(); i++) {
      if (internalName.charAt(i) != '[') return i;
    }
    return 0;
  }
Beispiel #7
0
  public static boolean canConvert(final MetaClass to, final MetaClass from) {
    try {
      final Class<?> fromClazz = from.asClass();
      final Class<?> toClass = to.asClass();

      return DataConversion.canConvert(toClass, fromClazz);
    } catch (Throwable t) {
      return false;
    }
  }
Beispiel #8
0
 private static void fillInInterfacesAndSuperTypes(
     final Set<MetaClass> set, final MetaClass type) {
   for (final MetaClass iface : type.getInterfaces()) {
     set.add(iface);
     fillInInterfacesAndSuperTypes(set, iface);
   }
   if (type.getSuperClass() != null) {
     fillInInterfacesAndSuperTypes(set, type.getSuperClass());
   }
 }
Beispiel #9
0
 public static Scope scopeOf(final MetaClass clazz) {
   if (clazz.isPublic()) {
     return Scope.Public;
   } else if (clazz.isPrivate()) {
     return Scope.Private;
   } else if (clazz.isProtected()) {
     return Scope.Protected;
   } else {
     return Scope.Package;
   }
 }
Beispiel #10
0
  /**
   * Ensures the provided type is a {@link DataBinder} and throws a {@link GenerationException} in
   * case it's not.
   *
   * @param type the type to check
   */
  private static void assertTypeIsDataBinder(MetaClass type) {
    final MetaClass databinderMetaClass = MetaClassFactory.get(DataBinder.class);

    if (!databinderMetaClass.isAssignableFrom(type)) {
      throw new GenerationException(
          "Type of @AutoBound element must be "
              + DataBinder.class.getName()
              + " but is: "
              + type.getFullyQualifiedName());
    }
  }
Beispiel #11
0
  /**
   * Tries to find a reference for an injected {@link AutoBound} data binder.
   *
   * @return the data binder reference or null if not found.
   */
  private static DataBinderRef lookupAutoBoundBinder(final InjectableInstance<?> inst) {
    Statement dataBinderRef = null;
    MetaClass dataModelType = null;

    InjectUtil.BeanMetric beanMetric =
        InjectUtil.getFilteredBeanMetric(
            inst.getInjectionContext(), inst.getInjector().getInjectedType(), AutoBound.class);

    final Collection<Object> allInjectors = beanMetric.getAllInjectors();
    if (allInjectors.size() > 1) {
      throw new GenerationException(
          "Multiple @AutoBound data binders injected in " + inst.getEnclosingType());
    } else if (allInjectors.size() == 1) {
      final Object injectorElement = allInjectors.iterator().next();

      if (injectorElement instanceof MetaConstructor || injectorElement instanceof MetaMethod) {
        final MetaParameter mp = beanMetric.getConsolidatedMetaParameters().iterator().next();

        assertTypeIsDataBinder(mp.getType());
        dataModelType = (MetaClass) mp.getType().getParameterizedType().getTypeParameters()[0];
        dataBinderRef = inst.getInjectionContext().getInlineBeanReference(mp);
        inst.ensureMemberExposed();
      } else {
        final MetaField field = (MetaField) allInjectors.iterator().next();

        assertTypeIsDataBinder(field.getType());
        dataModelType = (MetaClass) field.getType().getParameterizedType().getTypeParameters()[0];
        dataBinderRef =
            Stmt.invokeStatic(
                inst.getInjectionContext().getProcessingContext().getBootstrapClass(),
                PrivateAccessUtil.getPrivateFieldInjectorName(field),
                Variable.get(inst.getInjector().getInstanceVarName()));
        inst.getInjectionContext().addExposedField(field, PrivateAccessType.Both);
      }
    } else {
      final MetaClass declaringClass = inst.getInjector().getInjectedType();
      for (final MetaField field : declaringClass.getFields()) {
        if (field.isAnnotationPresent(AutoBound.class)) {
          assertTypeIsDataBinder(field.getType());
          dataModelType = (MetaClass) field.getType().getParameterizedType().getTypeParameters()[0];
          dataBinderRef =
              Stmt.invokeStatic(
                  inst.getInjectionContext().getProcessingContext().getBootstrapClass(),
                  PrivateAccessUtil.getPrivateFieldInjectorName(field),
                  Variable.get(inst.getInjector().getInstanceVarName()));
          inst.getInjectionContext().addExposedField(field, PrivateAccessType.Both);
          break;
        }
      }
    }

    return (dataBinderRef != null) ? new DataBinderRef(dataModelType, dataBinderRef) : null;
  }
 private void createValidationError(Collection<MetaClass> pages, Class<?> role) {
   StringBuilder builder = new StringBuilder();
   for (MetaClass mc : pages) {
     builder.append("\n  ").append(mc.getFullyQualifiedName());
   }
   throw new GenerationException(
       "Found more than one @Page with role = '"
           + role
           + "': "
           + builder
           + "\nExactly one @Page class must be designated with this unique role.");
 }
Beispiel #13
0
 public static int scoreInterface(final MetaClass parm, final MetaClass arg) {
   if (parm.isInterface()) {
     final MetaClass[] iface = arg.getInterfaces();
     if (iface != null) {
       for (final MetaClass c : iface) {
         if (c == parm) return 1;
         else if (parm.isAssignableFrom(c)) return scoreInterface(parm, arg.getSuperClass());
       }
     }
   }
   return 0;
 }
  /**
   * Renders the page-to-page navigation graph into the file {@code navgraph.gv} in the {@code
   * .errai} cache directory.
   */
  private void renderNavigationToDotFile(BiMap<String, MetaClass> pages) {
    final File dotFile = new File(RebindUtils.getErraiCacheDir().getAbsolutePath(), "navgraph.gv");
    PrintWriter out = null;
    try {
      out = new PrintWriter(dotFile);
      out.println("digraph Navigation {");
      final MetaClass transitionToType = MetaClassFactory.get(TransitionTo.class);
      final MetaClass transitionAnchorType = MetaClassFactory.get(TransitionAnchor.class);
      final MetaClass transitionAnchorFactoryType =
          MetaClassFactory.get(TransitionAnchorFactory.class);
      for (Map.Entry<String, MetaClass> entry : pages.entrySet()) {
        String pageName = entry.getKey();
        MetaClass pageClass = entry.getValue();

        // entry for the node itself
        out.print("\"" + pageName + "\"");

        Page pageAnnotation = pageClass.getAnnotation(Page.class);
        List<Class<? extends PageRole>> roles = Arrays.asList(pageAnnotation.role());
        if (roles.contains(DefaultPage.class)) {
          out.print(" [penwidth=3]");
        }
        out.println();

        for (MetaField field : getAllFields(pageClass)) {
          if (field.getType().getErased().equals(transitionToType)
              || field.getType().getErased().equals(transitionAnchorType)
              || field.getType().getErased().equals(transitionAnchorFactoryType)) {
            MetaType targetPageType = field.getType().getParameterizedType().getTypeParameters()[0];
            String targetPageName = pages.inverse().get(targetPageType);

            // entry for the link between nodes
            out.println(
                "\""
                    + pageName
                    + "\" -> \""
                    + targetPageName
                    + "\" [label=\""
                    + field.getName()
                    + "\"]");
          }
        }
      }
      out.println("}");
    } catch (FileNotFoundException e) {
      throw new RuntimeException(e);
    } finally {
      if (out != null) {
        out.close();
      }
    }
  }
 private Statement defaultValueStatement(MetaClass type) {
   if (type.isPrimitive()) {
     if (type.asBoxed().isAssignableTo(Number.class)) {
       return Stmt.castTo(type, Stmt.load(0));
     } else if (type.isAssignableTo(boolean.class)) {
       return Stmt.load(false);
     } else {
       throw new UnsupportedOperationException(
           "Don't know how to make a default value for @PageState field of type "
               + type.getFullyQualifiedName());
     }
   } else {
     return Stmt.load(null);
   }
 }
Beispiel #16
0
  public static Statement convert(final Context context, Object input, final MetaClass targetType) {
    try {
      if (input instanceof Statement) {
        if (input instanceof LiteralValue<?>) {
          input = ((LiteralValue<?>) input).getValue();
        } else {
          if ("null".equals(((Statement) input).generate(context))) {
            return (Statement) input;
          }

          assertAssignableTypes(context, ((Statement) input).getType(), targetType);
          return (Statement) input;
        }
      }

      if (input != null
          && MetaClassFactory.get(input.getClass())
              .getOuterComponentType()
              .getFullyQualifiedName()
              .equals(MetaClass.class.getName())) {
        return generate(context, input);
      }

      if (Object.class.getName().equals(targetType.getFullyQualifiedName())) {
        return generate(context, input);
      }

      Class<?> inputClass = input == null ? Object.class : input.getClass();

      if (MetaClass.class.isAssignableFrom(inputClass)) {
        inputClass = Class.class;
      }

      final Class<?> targetClass = targetType.asBoxed().asClass();
      if (NullType.class.getName().equals(targetClass.getName())) {
        return generate(context, input);
      }

      if (!targetClass.isAssignableFrom(inputClass)
          && DataConversion.canConvert(targetClass, inputClass)) {
        return generate(context, DataConversion.convert(input, targetClass));
      } else {
        return generate(context, input);
      }
    } catch (NumberFormatException nfe) {
      throw new InvalidTypeException(nfe);
    }
  }
Beispiel #17
0
  @Override
  public MetaMethod[] getMethods() {
    if (_methodsCache != null) return _methodsCache;

    MetaMethod[] methodArray = methods.toArray(new MetaMethod[methods.size()]);
    MetaMethod[] outputMethods;

    if (superClass != null) {
      List<MetaMethod> methodList = new ArrayList<MetaMethod>();
      for (MetaMethod m : superClass.getMethods()) {
        if (_getMethod(methodArray, m.getName(), GenUtil.fromParameters(m.getParameters()))
            == null) {
          methodList.add(m);
        }
      }

      methodList.addAll(Arrays.asList(methodArray));

      outputMethods = methodList.toArray(new MetaMethod[methodList.size()]);
    } else {
      outputMethods = methodArray;
    }

    return _methodsCache = outputMethods;
  }
  private static Statement paramFromStringStatement(MetaClass toType, Statement stringValue) {

    // make sure it's really a string
    stringValue = Stmt.castTo(String.class, stringValue);

    if (toType.isAssignableTo(String.class)) {
      return stringValue;
    } else if (toType.asBoxed().isAssignableTo(Number.class)) {
      return Stmt.invokeStatic(toType.asBoxed(), "valueOf", stringValue);
    } else if (toType.asBoxed().isAssignableTo(Boolean.class)) {
      return Stmt.invokeStatic(Boolean.class, "valueOf", stringValue);
    } else {
      throw new UnsupportedOperationException(
          "@PageState fields of type " + toType.getFullyQualifiedName() + " are not supported");
    }
  }
Beispiel #19
0
  @Override
  public boolean equals(Object o) {
    if (this == o) return true;
    if (!(o instanceof BuildMetaClass)) return false;
    if (!super.equals(o)) return false;

    BuildMetaClass that = (BuildMetaClass) o;

    if (dimensions != that.dimensions) return false;
    if (isAbstract != that.isAbstract) return false;
    if (isArray != that.isArray) return false;
    if (isFinal != that.isFinal) return false;
    if (isInner != that.isInner) return false;
    if (isInterface != that.isInterface) return false;
    if (isStatic != that.isStatic) return false;
    if (!Arrays.equals(_constructorsCache, that._constructorsCache)) return false;
    if (!Arrays.equals(_fieldsCache, that._fieldsCache)) return false;
    if (!Arrays.equals(_methodsCache, that._methodsCache)) return false;
    if (_nameCache != null ? !_nameCache.equals(that._nameCache) : that._nameCache != null)
      return false;
    if (className != null ? !className.equals(that.className) : that.className != null)
      return false;
    if (constructors != null ? !constructors.equals(that.constructors) : that.constructors != null)
      return false;
    if (context != null ? !context.equals(that.context) : that.context != null) return false;
    if (fields != null ? !fields.equals(that.fields) : that.fields != null) return false;
    if (generatedCache != null
        ? !generatedCache.equals(that.generatedCache)
        : that.generatedCache != null) return false;
    if (interfaces != null ? !interfaces.equals(that.interfaces) : that.interfaces != null)
      return false;
    if (methods != null ? !methods.equals(that.methods) : that.methods != null) return false;
    if (reifiedFormOf != null
        ? !reifiedFormOf.equals(that.reifiedFormOf)
        : that.reifiedFormOf != null) return false;
    if (scope != that.scope) return false;
    if (superClass != null ? !superClass.equals(that.superClass) : that.superClass != null)
      return false;
    if (typeVariables != null
        ? !typeVariables.equals(that.typeVariables)
        : that.typeVariables != null) return false;

    return true;
  }
Beispiel #20
0
  @Override
  public MetaClassMember getReadingMember() {
    if (readingMember != null) {
      return readingMember;
    }

    MetaMethod meth = toMap.getMethod(getterMethod, new MetaClass[0]);

    meth.asMethod().setAccessible(true);

    readingMember = meth;

    if (readingMember == null) {
      throw new RuntimeException(
          "no such getter method: " + toMap.getFullyQualifiedName() + "." + getterMethod);
    }

    return readingMember;
  }
  /**
   * Appends the method that calls the {@code @PageHidden} method of the widget.
   *
   * @param pageImplBuilder The class builder for the implementation of PageNode we are adding the
   *     method to.
   * @param pageClass The "content type" (Widget subclass) of the page. This is the type the user
   *     annotated with {@code @Page}.
   */
  private void appendPageHiddenMethod(
      AnonymousClassStructureBuilder pageImplBuilder, MetaClass pageClass) {
    BlockBuilder<?> method =
        pageImplBuilder
            .publicMethod(
                void.class,
                createMethodNameFromAnnotation(PageHidden.class),
                Parameter.of(pageClass, "widget"))
            .body();
    checkMethodAndAddPrivateAccessors(
        pageImplBuilder, method, pageClass, PageHidden.class, HistoryToken.class, "state");

    if (pageClass.getAnnotation(Singleton.class) == null
        && pageClass.getAnnotation(ApplicationScoped.class) == null
        && pageClass.getAnnotation(EntryPoint.class) == null) {
      method.append(Stmt.loadVariable("bm").invoke("destroyBean", Stmt.loadVariable("widget")));
    }
    method.finish();
  }
Beispiel #22
0
  public static MetaMethod getBestCandidate(
      final MetaClass[] arguments,
      final String method,
      final MetaClass decl,
      MetaMethod[] methods,
      final boolean classTarget) {
    if (methods == null || methods.length == 0) {
      return null;
    }

    MetaParameter[] parmTypes;
    MetaMethod bestCandidate = null;
    int bestScore = 0;
    int score;
    boolean retry = false;

    do {
      for (final MetaMethod meth : methods) {
        if (classTarget && (meth.isStatic())) continue;

        if (method.equals(meth.getName())) {
          final boolean isVarArgs = meth.isVarArgs();
          if ((parmTypes = meth.getParameters()).length != arguments.length && !isVarArgs) {
            continue;
          } else if (arguments.length == 0 && parmTypes.length == 0) {
            bestCandidate = meth;
            break;
          }

          score = scoreMethods(arguments, parmTypes, isVarArgs);

          if (score != 0 && score > bestScore) {
            bestCandidate = meth;
            bestScore = score;
          }
        }
      }

      if (!retry && bestCandidate == null && decl.isInterface()) {
        final MetaMethod[] objMethods = Object_MetaClass.getMethods();
        final MetaMethod[] nMethods = new MetaMethod[methods.length + objMethods.length];
        System.arraycopy(methods, 0, nMethods, 0, methods.length);
        System.arraycopy(objMethods, 0, nMethods, methods.length, objMethods.length);
        methods = nMethods;

        retry = true;
      } else {
        break;
      }
    } while (true);

    return bestCandidate;
  }
Beispiel #23
0
  public static void assertAssignableTypes(
      final Context context, final MetaClass from, final MetaClass to) {
    if (!to.asBoxed().isAssignableFrom(from.asBoxed())) {
      if (to.isArray()
          && from.isArray()
          && GenUtil.getArrayDimensions(to) == GenUtil.getArrayDimensions(from)
          && to.getOuterComponentType().isAssignableFrom(from.getOuterComponentType())) {
        return;
      }

      if (!context.isPermissiveMode()) {
        if (classAliases.contains(from.getFullyQualifiedName())
            && classAliases.contains(to.getFullyQualifiedName())) {
          // handle convertibility between MetaClass API and java Class reference.
          return;
        }

        throw new InvalidTypeException(
            to.getFullyQualifiedName() + " is not assignable from " + from.getFullyQualifiedName());
      }
    }
  }
Beispiel #24
0
  public static boolean isNumericallyCoercible(final MetaClass target, final MetaClass parm) {
    MetaClass boxedTarget = target.isPrimitive() ? target.asBoxed() : target;

    if (boxedTarget != null && Number_MetaClass.isAssignableFrom(target)) {
      if ((boxedTarget = parm.isPrimitive() ? parm.asBoxed() : parm) != null) {
        return Number_MetaClass.isAssignableFrom(boxedTarget);
      }
    }
    return false;
  }
Beispiel #25
0
 public static boolean isPrimitiveWrapper(final MetaClass clazz) {
   return Integer.class.getName().equals(clazz.getFullyQualifiedName())
       || Boolean.class.getName().equals(clazz.getFullyQualifiedName())
       || Long.class.getName().equals(clazz.getFullyQualifiedName())
       || Double.class.getName().equals(clazz.getFullyQualifiedName())
       || Float.class.getName().equals(clazz.getFullyQualifiedName())
       || Short.class.getName().equals(clazz.getFullyQualifiedName())
       || Character.class.getName().equals(clazz.getFullyQualifiedName())
       || Byte.class.getName().equals(clazz.getFullyQualifiedName());
 }
Beispiel #26
0
 public static MetaClass getPrimitiveWrapper(final MetaClass clazz) {
   if (clazz.isPrimitive()) {
     if ("int".equals(clazz.getCanonicalName())) {
       return MetaClassFactory.get(Integer.class);
     } else if ("boolean".equals(clazz.getCanonicalName())) {
       return MetaClassFactory.get(Boolean.class);
     } else if ("long".equals(clazz.getCanonicalName())) {
       return MetaClassFactory.get(Long.class);
     } else if ("double".equals(clazz.getCanonicalName())) {
       return MetaClassFactory.get(Double.class);
     } else if ("float".equals(clazz.getCanonicalName())) {
       return MetaClassFactory.get(Float.class);
     } else if ("short".equals(clazz.getCanonicalName())) {
       return MetaClassFactory.get(Short.class);
     } else if ("char".equals(clazz.getCanonicalName())) {
       return MetaClassFactory.get(Character.class);
     } else if ("byte".equals(clazz.getCanonicalName())) {
       return MetaClassFactory.get(Byte.class);
     }
   }
   return clazz;
 }
Beispiel #27
0
 public static MetaClass getUnboxedFromWrapper(final MetaClass clazz) {
   if (Integer.class.getName().equals(clazz.getFullyQualifiedName())) {
     return MetaClassFactory.get(int.class);
   } else if (Boolean.class.getName().equals(clazz.getFullyQualifiedName())) {
     return MetaClassFactory.get(boolean.class);
   } else if (Long.class.getName().equals(clazz.getFullyQualifiedName())) {
     return MetaClassFactory.get(long.class);
   } else if (Double.class.getName().equals(clazz.getFullyQualifiedName())) {
     return MetaClassFactory.get(double.class);
   } else if (Float.class.getName().equals(clazz.getFullyQualifiedName())) {
     return MetaClassFactory.get(float.class);
   } else if (Short.class.getName().equals(clazz.getFullyQualifiedName())) {
     return MetaClassFactory.get(short.class);
   } else if (Character.class.getName().equals(clazz.getFullyQualifiedName())) {
     return MetaClassFactory.get(char.class);
   } else if (Byte.class.getName().equals(clazz.getFullyQualifiedName())) {
     return MetaClassFactory.get(byte.class);
   }
   return clazz;
 }
Beispiel #28
0
  public ProxyInjector(final IOCProcessingContext context,
                       final MetaClass proxiedType,
                       final QualifyingMetadata metadata) {

    Assert.notNull(proxiedType);
    Assert.notNull(metadata);

    this.proxiedType = proxiedType;
    this.varName = InjectUtil.getNewInjectorName() + "_proxy";
    this.qualifyingMetadata = AbstractInjector.getMetadataWithAny(metadata);
    final String proxyClassName = proxiedType.getName() + "_" + varName;

    this.closeStatements = new ArrayList<Statement>();

    this.proxyClass = ProxyMaker.makeProxy(proxyClassName, proxiedType, context.isGwtTarget() ? "jsni" : "reflection");
    this.proxyClass.setStatic(true);
    this.proxyClass.setScope(Scope.Package);

    context.getBootstrapClass()
            .addInnerClass(new InnerClass(proxyClass));
  }
Beispiel #29
0
  BuildMetaClass make(final String proxyClassName,
                      final MetaClass toProxy,
                      final String privateAccessorType) {
    final ClassStructureBuilder builder;



    final boolean renderEqualsAndHash;
    if (!toProxy.isInterface()) {
      renderEqualsAndHash = true;
      if (toProxy.isFinal()) {
        throw new UnproxyableClassException(toProxy, toProxy.getFullyQualifiedName()
            + " is an unproxiable class because it is final");
      }
      if (!toProxy.isDefaultInstantiable()) {
        throw new UnproxyableClassException(toProxy, toProxy.getFullyQualifiedName() + " must have a default " +
            "no-arg constructor");
      }

      builder = ClassBuilder.define(proxyClassName, toProxy).publicScope().body();
    }
    else {
      renderEqualsAndHash = false;
      builder = ClassBuilder.define(proxyClassName).publicScope().implementsInterface(toProxy).body();
    }

    final String proxyVar = "$$_proxy_$$";

    final Set<String> renderedMethods = new HashSet<String>();

    final Map<String, MetaType> typeVariableMap = new HashMap<String, MetaType>();
    final MetaParameterizedType metaParameterizedType = toProxy.getParameterizedType();

    if (metaParameterizedType != null) {
      int i = 0;
      for (final MetaTypeVariable metaTypeVariable : toProxy.getTypeParameters()) {
        typeVariableMap.put(metaTypeVariable.getName(), metaParameterizedType.getTypeParameters()[i++]);
      }
    }

    builder.privateField(proxyVar, toProxy).finish();

    final Set<Map.Entry<String, ProxyProperty>> entries = proxyProperties.entrySet();
    for (final Map.Entry<String, ProxyProperty> entry : entries) {
      builder.privateField(entry.getValue().getEncodedProperty(), entry.getValue().getType()).finish();
      builder.packageMethod(void.class, "$set_" + entry.getKey(), Parameter.of(entry.getValue().getType(), "o"))
          .append(Stmt.loadVariable(entry.getValue().getEncodedProperty()).assignValue(Refs.get("o")))
          .finish();
    }

    for (final MetaMethod method : toProxy.getMethods()) {
      final String methodString = GenUtil.getMethodString(method);
      if (renderedMethods.contains(methodString) || method.getName().equals("hashCode")
          || (method.getName().equals("equals") && method.getParameters().length == 1
          && method.getParameters()[0].getType().getFullyQualifiedName().equals(Object.class.getName()))) continue;

      renderedMethods.add(methodString);

      if ((!method.isPublic() && !method.isProtected()) ||
          method.isSynthetic() ||
          method.isFinal() ||
          method.isStatic() ||
          method.getDeclaringClass().getFullyQualifiedName().equals(Object.class.getName()))
        continue;

      final List<Parameter> methodParms = new ArrayList<Parameter>();
      final MetaParameter[] parameters = method.getParameters();

      for (int i = 0; i < parameters.length; i++) {
        methodParms.add(Parameter.of(parameters[i].getType().getErased(), "a" + i));
      }

      final DefParameters defParameters = DefParameters.fromParameters(methodParms);
      final BlockBuilder methBody = builder.publicMethod(method.getReturnType(), method.getName())
          .annotatedWith(OVERRIDE_ANNOTATION)
          .parameters(defParameters)
          .throws_(method.getCheckedExceptions());

      methBody.appendAll(getAroundInvokeStatements(method));
      methBody.appendAll(getBeforeStatements(method));

      final List<Parameter> parms = defParameters.getParameters();

      final Statement[] statementVars = new Statement[parms.size()];
      for (int i = 0; i < parms.size(); i++) {
        statementVars[i] = loadVariable(parms.get(i).getName());
      }

      if (!method.isPublic()) {
        PrivateAccessUtil.addPrivateAccessStubs(privateAccessorType, builder, method, new Modifier[0]);

        final Statement[] privateAccessStmts = new Statement[statementVars.length + 1];
        privateAccessStmts[0] = Refs.get(proxyVar);
        System.arraycopy(statementVars, 0, privateAccessStmts, 1, statementVars.length);

        if (method.getReturnType().isVoid()) {
          methBody._(loadVariable("this").invoke(PrivateAccessUtil.getPrivateMethodName(method), privateAccessStmts));
        }
        else {
          methBody._(loadVariable("this").invoke(PrivateAccessUtil.getPrivateMethodName(method), privateAccessStmts).returnValue());
        }
      }
      else {
        if (method.getReturnType().isVoid()) {
          methBody._(loadVariable(proxyVar).invoke(method, statementVars));
        }
        else {
          methBody._(loadVariable(proxyVar).invoke(method, statementVars).returnValue());
        }
      }

      methBody.appendAll(getAfterStatements(method));
      methBody.appendAll(getAroundInvokeStatements(method));

      methBody.finish();
    }

    if (renderEqualsAndHash) {
      // implement hashCode()
      builder.publicMethod(int.class, "hashCode")
          .annotatedWith(OVERRIDE_ANNOTATION)
          .body()
          ._(
              If.isNull(loadVariable(proxyVar))
                  ._(throw_(IllegalStateException.class, "call to hashCode() on an unclosed proxy."))
                  .finish()
                  .else_()
                  ._(Stmt.loadVariable(proxyVar).invoke("hashCode").returnValue())
                  .finish()
          )
          .finish();

      // implements equals()
      builder.publicMethod(boolean.class, "equals", Parameter.of(Object.class, "o"))
          .annotatedWith(OVERRIDE_ANNOTATION)
          .body()
          ._(
              If.isNull(loadVariable(proxyVar))
                  ._(throw_(IllegalStateException.class, "call to equals() on an unclosed proxy."))
                  .finish()
                  .else_()
                  ._(Stmt.loadVariable(proxyVar).invoke("equals", Refs.get("o")).returnValue())
                  .finish()
          )
          .finish();
    }

    builder.publicMethod(void.class, PROXY_BIND_METHOD).parameters(DefParameters.of(Parameter.of(toProxy, "proxy")))
        ._(loadVariable(proxyVar).assignValue(loadVariable("proxy"))).finish();

    return builder.getClassDefinition();
  }
Beispiel #30
0
  /**
   * Implementation for the same-named public methods.
   *
   * @param o The object to snapshot.
   * @param typeToSnapshot The type to read the snapshot attributes from. Must be a superclass of o
   *     or an interface implemented by o, and methods not supplied by {@code methodBodyCallback}
   *     must meed the requirements laid out in the class-level SnapshotMaker documentation.
   * @param typeToExtend The type of the snapshot to produce. Must be a subclass or subinterface of
   *     typeToSnapshot, and the additional methods present in typeToExtend vs. typeToSnapshot must
   *     be provided by the MethodMaker callback, since they can't be generated from o.
   * @param typesToRecurseOn Types for which this method should be called recursively.
   * @param methodBodyCallback A callback that can provide method bodies, preventing the standard
   *     snapshot behaviour for those methods. This callback is optional; null is acceptable as "no
   *     callback."
   * @param existingSnapshots Object instances for which a snapshot has already been completed.
   *     Bootstrap this with an empty IdentityHashMap.
   * @param unfinishedSnapshots Object instances for which a partially-completed snapshot exists. If
   *     one of these objects is returned by a method in {@code o}, this causes a
   *     CyclicalObjectGraphException.
   * @return A Statement of type {@code typeToExtend} that represents the current publicly visible
   *     state of {@code o}.
   */
  private static Statement makeSnapshotAsSubclass(
      final Object o,
      final MetaClass typeToSnapshot,
      final MetaClass typeToExtend,
      final MethodBodyCallback methodBodyCallback,
      final Set<MetaClass> typesToRecurseOn,
      final IdentityHashMap<Object, Statement> existingSnapshots,
      final Set<Object> unfinishedSnapshots) {

    if (o == null) {
      return NullLiteral.INSTANCE;
    }

    if (!typeToSnapshot.isAssignableFrom(o.getClass())) {
      throw new IllegalArgumentException(
          "Given object (of type "
              + o.getClass().getName()
              + ") is not an instance of requested type to snapshot "
              + typeToSnapshot.getName());
    }

    if (logger.isDebugEnabled()) {
      logger.debug("** Making snapshot of " + o);
      logger.debug("   Existing snapshots: " + existingSnapshots);
    }

    final List<MetaMethod> sortedMethods = Arrays.asList(typeToExtend.getMethods());
    Collections.sort(
        sortedMethods,
        new Comparator<MetaMethod>() {
          @Override
          public int compare(MetaMethod m1, MetaMethod m2) {
            return m1.getName().compareTo(m2.getName());
          }
        });

    logger.debug("   Creating a new statement");
    return new Statement() {
      String generatedCache;

      /**
       * We retain a mapping of return values to the methods that returned them, in case we need to
       * provide diagnostic information when an exception is thrown.
       */
      IdentityHashMap<Object, MetaMethod> methodReturnVals =
          new IdentityHashMap<Object, MetaMethod>();

      @Override
      public String generate(Context context) {
        if (logger.isDebugEnabled()) {
          logger.debug("++ Statement.generate() for " + o);
        }

        if (generatedCache != null) return generatedCache;

        // create a subcontext and record the types we will allow the LiteralFactory to create
        // automatic
        // snapshots for.
        final Context subContext = Context.create(context);
        subContext.addLiteralizableMetaClasses(typesToRecurseOn);

        final AnonymousClassStructureBuilder builder =
            ObjectBuilder.newInstanceOf(typeToExtend.getErased(), context).extend();
        unfinishedSnapshots.add(o);
        for (MetaMethod method : sortedMethods) {
          if (method.isFinal() || method.getName().equals("toString")) continue;

          if (logger.isDebugEnabled()) {
            logger.debug("  method " + method.getName());
            logger.debug("    return type " + method.getReturnType());
          }

          if (methodBodyCallback != null) {
            Statement providedMethod = methodBodyCallback.generateMethodBody(method, o, builder);
            if (providedMethod != null) {
              logger.debug("    body provided by callback");
              builder
                  .publicOverridesMethod(method.getName(), Parameter.of(method.getParameters()))
                  .append(providedMethod)
                  .finish();
              continue;
            }
          }

          if (method.getName().equals("equals")
              || method.getName().equals("hashCode")
              || method.getName().equals("clone")
              || method.getName().equals("finalize")) {
            // we skip these if not provided by the callback
            if (logger.isDebugEnabled()) {
              logger.debug("    skipping special-case method " + method.getName());
            }
            continue;
          }

          if (method.getParameters().length > 0) {
            throw new GenerationException(
                "Method "
                    + method
                    + " in "
                    + typeToSnapshot
                    + " takes parameters. Such methods must be handled by the MethodBodyCallback,"
                    + " because they cannot be snapshotted.");
          }

          if (method.getReturnType().equals(void.class)) {
            builder.publicOverridesMethod(method.getName()).finish();
            if (logger.isDebugEnabled()) {
              logger.debug("  finished method " + method.getName());
            }
            continue;
          }
          try {

            final Object retval = typeToExtend.asClass().getMethod(method.getName()).invoke(o);
            methodReturnVals.put(retval, method);

            if (logger.isDebugEnabled()) {
              logger.debug("    retval=" + retval);
            }

            Statement methodBody;
            if (existingSnapshots.containsKey(retval)) {
              logger.debug("    using existing snapshot");
              methodBody = existingSnapshots.get(retval);
            } else if (subContext.isLiteralizableClass(method.getReturnType().getErased())) {
              if (unfinishedSnapshots.contains(retval)) {
                throw new CyclicalObjectGraphException(unfinishedSnapshots);
              }

              // use Stmt.create(context) to pass the context along.
              if (logger.isDebugEnabled()) {
                logger.debug("    >> recursing for " + retval);
              }

              methodBody =
                  Stmt.create(subContext)
                      .nestedCall(
                          makeSnapshotAsSubclass(
                              retval,
                              method.getReturnType(),
                              method.getReturnType(),
                              methodBodyCallback,
                              typesToRecurseOn,
                              existingSnapshots,
                              unfinishedSnapshots))
                      .returnValue();
            } else {
              logger.debug("    relying on literal factory");
              methodBody = Stmt.load(retval).returnValue();
            }

            if (logger.isDebugEnabled()) {
              logger.debug("  finished method " + method.getName());
            }

            builder.publicOverridesMethod(method.getName()).append(methodBody).finish();
            existingSnapshots.put(retval, methodBody);
          } catch (GenerationException e) {
            e.appendFailureInfo(
                "In attempt to snapshot return value of "
                    + typeToExtend.getFullyQualifiedName()
                    + "."
                    + method.getName()
                    + "()");
            throw e;
          } catch (RuntimeException e) {
            throw e;
          } catch (Exception e) {
            throw new GenerationException("Failed to extract value for snapshot", e);
          }
        }

        if (logger.isDebugEnabled()) {
          logger.debug("    finished: " + builder);
        }

        try {
          generatedCache = prettyPrintJava(builder.finish().toJavaString());
        } catch (NotLiteralizableException e) {
          MetaMethod m = methodReturnVals.get(e.getNonLiteralizableObject());
          if (m != null) {
            e.appendFailureInfo(
                "This value came from method "
                    + m.getDeclaringClass().getFullyQualifiedNameWithTypeParms()
                    + "."
                    + m.getName()
                    + ", which has return type "
                    + m.getReturnType());
          }
          throw e;
        } catch (GenerationException e) {
          e.appendFailureInfo(
              "While generating a snapshot of "
                  + o.toString()
                  + " (actual type: "
                  + o.getClass().getName()
                  + "; type to extend: "
                  + typeToExtend.getFullyQualifiedName()
                  + ")");
          throw e;
        }
        unfinishedSnapshots.remove(o);
        return generatedCache;
      }

      @Override
      public MetaClass getType() {
        return typeToExtend;
      }
    };
  }