/**
  * Checks type and its supertypes for {@link ExtraTypes} annotations.
  *
  * @param type the type to examine
  * @param addModelExtraTypes if {@code true} the contents of the {@link #extraTypes} field will be
  *     added to the returned list.
  */
 private List<EntityProxyModel> checkExtraTypes(JClassType type, boolean addModelExtraTypes)
     throws UnableToCompleteException {
   Set<EntityProxyModel> toReturn = new LinkedHashSet<EntityProxyModel>();
   if (addModelExtraTypes && extraTypes != null) {
     toReturn.addAll(extraTypes);
   }
   for (JClassType toExamine : type.getFlattenedSupertypeHierarchy()) {
     ExtraTypes proxyExtraTypes = toExamine.getAnnotation(ExtraTypes.class);
     if (proxyExtraTypes != null) {
       for (Class<? extends BaseProxy> clazz : proxyExtraTypes.value()) {
         JClassType proxy = oracle.findType(clazz.getCanonicalName());
         if (proxy == null) {
           poison(
               "Unknown class %s in @%s",
               clazz.getCanonicalName(), ExtraTypes.class.getSimpleName());
         } else {
           toReturn.add(getEntityProxyType(proxy));
         }
       }
     }
   }
   if (toReturn.isEmpty()) {
     return Collections.emptyList();
   }
   return new ArrayList<EntityProxyModel>(toReturn);
 }
  /** Examine a RequestContext subtype to populate a ContextMethod. */
  private void buildContextMethod(ContextMethod.Builder contextBuilder, JClassType contextType)
      throws UnableToCompleteException {
    Service serviceAnnotation = contextType.getAnnotation(Service.class);
    ServiceName serviceNameAnnotation = contextType.getAnnotation(ServiceName.class);
    JsonRpcService jsonRpcAnnotation = contextType.getAnnotation(JsonRpcService.class);
    if (serviceAnnotation == null && serviceNameAnnotation == null && jsonRpcAnnotation == null) {
      poison(
          "RequestContext subtype %s is missing a @%s or @%s annotation",
          contextType.getQualifiedSourceName(),
          Service.class.getSimpleName(),
          JsonRpcService.class.getSimpleName());
      return;
    }

    List<RequestMethod> requestMethods = new ArrayList<RequestMethod>();
    for (JMethod method : contextType.getInheritableMethods()) {
      if (method.getEnclosingType().equals(requestContextInterface)) {
        // Ignore methods declared in RequestContext
        continue;
      }

      RequestMethod.Builder methodBuilder = new RequestMethod.Builder();
      methodBuilder.setDeclarationMethod(contextType, method);

      if (!validateContextMethodAndSetDataType(methodBuilder, method, jsonRpcAnnotation != null)) {
        continue;
      }

      requestMethods.add(methodBuilder.build());
    }

    contextBuilder
        .setExtraTypes(checkExtraTypes(contextType, true))
        .setRequestMethods(requestMethods);
  }
 /**
  * Returns {@code true} if the type is assignable to EntityProxy or ValueProxy and has a mapping
  * to a domain type.
  *
  * @see
  *     com.google.web.bindery.requestfactory.server.RequestFactoryInterfaceValidator#shouldAttemptProxyValidation()
  */
 private boolean shouldAttemptProxyValidation(JClassType maybeProxy) {
   if (!entityProxyInterface.isAssignableFrom(maybeProxy)
       && !valueProxyInterface.isAssignableFrom(maybeProxy)) {
     return false;
   }
   if (maybeProxy.getAnnotation(ProxyFor.class) == null
       && maybeProxy.getAnnotation(ProxyForName.class) == null) {
     return false;
   }
   return true;
 }
예제 #4
0
  protected void initializeDataObjects() {
    if (!initialized) {
      dataObjects = new HashMap<String, String>();
      dataObjectIdentifiers = new HashMap<String, String[]>();
      JClassType[] dataObjectTypes;
      try {
        initializeDefaultDataObjects();
        dataObjectTypes = jClassScanner.searchClassesByAnnotation(DataObject.class);
      } catch (Exception e) {
        throw new CruxGeneratorException("Error initializing DataObjects scanner.", e);
      }
      if (dataObjectTypes != null) {
        for (JClassType dataClass : dataObjectTypes) {
          DataObject annot = dataClass.getAnnotation(DataObject.class);
          if (dataObjects.containsKey(annot.value())) {
            throw new CruxGeneratorException(
                "Duplicated alias for DataObject found: [" + annot.value() + "].");
          }

          dataObjects.put(annot.value(), dataClass.getQualifiedSourceName());
          dataObjectIdentifiers.put(annot.value(), extractIdentifiers(dataClass));
        }
      }
      initialized = true;
    }
  }
예제 #5
0
  /**
   * Given a UiBinder interface, return the path to its ui.xml file, suitable for any classloader to
   * find it as a resource.
   */
  private static String deduceTemplateFile(MortalLogger logger, JClassType interfaceType)
      throws UnableToCompleteException {
    String templateName = null;
    UiTemplate annotation = interfaceType.getAnnotation(UiTemplate.class);
    if (annotation == null) {
      // if the interface is defined as a nested class, use the name of the
      // enclosing type
      if (interfaceType.getEnclosingType() != null) {
        interfaceType = interfaceType.getEnclosingType();
      }
      return slashify(interfaceType.getQualifiedBinaryName()) + TEMPLATE_SUFFIX;
    } else {
      templateName = annotation.value();
      if (!templateName.endsWith(TEMPLATE_SUFFIX)) {
        logger.die("Template file name must end with " + TEMPLATE_SUFFIX);
      }

      /*
       * If the template file name (minus suffix) has no dots, make it relative
       * to the binder's package, otherwise slashify the dots
       */
      String unsuffixed = templateName.substring(0, templateName.lastIndexOf(TEMPLATE_SUFFIX));
      if (!unsuffixed.contains(".")) {
        templateName = slashify(interfaceType.getPackage().getName()) + "/" + templateName;
      } else {
        templateName = slashify(unsuffixed) + TEMPLATE_SUFFIX;
      }
    }
    return templateName;
  }
예제 #6
0
  private boolean isIntrospectable(TreeLogger logger, JType type) {
    if (type == null) {
      return false;
    }

    JClassType ct = type.isClassOrInterface();

    if (ct != null) {
      if (ct.getAnnotation(Introspectable.class) != null) {
        return true;
      }

      for (JClassType iface : ct.getImplementedInterfaces()) {
        if (isIntrospectable(logger, iface)) {
          return true;
        }
      }

      if (isIntrospectable(logger, ct.getSuperclass())) {
        return true;
      }
    }

    return false;
  }
 @Override
 public void createDelegates(
     JClassType injectableType, Collection<InjectorCreatorDelegate> delegates) {
   if (injectableType.getAnnotation(Templated.class) != null) {
     delegates.add(new InjectTemplateCreator(injectableType));
   }
 }
예제 #8
0
  protected String getRemoteServiceRelativePath() {
    RemoteServiceRelativePath moduleRelativeURL =
        serviceIntf.getAnnotation(RemoteServiceRelativePath.class);
    if (moduleRelativeURL != null) {
      return "\"" + moduleRelativeURL.value() + "\"";
    }

    return null;
  }
예제 #9
0
  @Override
  public String generate(TreeLogger treeLogger, GeneratorContext generatorContext, String s)
      throws UnableToCompleteException {
    GinjectorGenerator ginjectorGenerator = new GinjectorGenerator();

    JClassType clazz = generatorContext.getTypeOracle().findType(s);
    GinExtension[] ginExtensions = null;
    if (clazz.isAnnotationPresent(GinExtensions.class)) {
      ginExtensions = clazz.getAnnotation(GinExtensions.class).value();
    }
    GeneratorContextWrapper gcw = new GeneratorContextWrapper(generatorContext, ginExtensions);

    return ginjectorGenerator.generate(treeLogger, gcw, s);
  }
예제 #10
0
  /**
   * Find an annotation on a type or on one of its superclasses or superinterfaces.
   *
   * <p>This provides semantics similar to that of {@link java.lang.annotation.Inherited} except
   * that it checks all types to which this type is assignable. {@code @Inherited} only works on
   * superclasses, not superinterfaces.
   *
   * <p>Annotations present on the superclass chain will be returned preferentially over those found
   * in the superinterface hierarchy. Note that the annotation does not need to be tagged with
   * {@code @Inherited} in order to be returned from the superclass chain.
   *
   * @param annotationType the type of the annotation to look for
   * @return the desired annotation or <code>null</code> if the annotation is not present in the
   *     type's type hierarchy
   */
  public <T extends Annotation> T findAnnotationInTypeHierarchy(Class<T> annotationType) {

    // Remember what we've seen to avoid loops
    Set<JClassType> seen = new HashSet<JClassType>();

    // Work queue
    List<JClassType> searchTypes = new LinkedList<JClassType>();
    searchTypes.add(this);

    T toReturn = null;

    while (!searchTypes.isEmpty()) {
      JClassType current = searchTypes.remove(0);

      if (!seen.add(current)) {
        continue;
      }

      toReturn = current.getAnnotation(annotationType);
      if (toReturn != null) {
        /*
         * First one wins. It might be desirable at some point to have a
         * variation that can return more than one instance of the annotation if
         * it is present on multiple supertypes.
         */
        break;
      }

      if (current.getSuperclass() != null) {
        // Add the superclass at the front of the list
        searchTypes.add(0, current.getSuperclass());
      }

      // Superinterfaces
      Collections.addAll(searchTypes, current.getImplementedInterfaces());
    }

    return toReturn;
  }
  /** @return */
  protected void initializeController(View view) {
    controllerName =
        templateParser.getTemplateController(view, baseIntf.getQualifiedSourceName(), device);
    String controllerClassName = ClientControllers.getController(controllerName, device);
    if (controllerClassName == null) {
      throw new CruxGeneratorException(
          "Error generating invoker. Controller [" + controllerName + "] not found.");
    }

    controllerClass = context.getTypeOracle().findType(controllerClassName);
    if (controllerClass == null) {
      String message =
          "Controller class ["
              + controllerName
              + "] , declared on view ["
              + view.getId()
              + "], could not be loaded. "
              + "\n Possible causes:"
              + "\n\t 1. Check if any type or subtype used by controller refers to another module and if this module is inherited in the .gwt.xml file."
              + "\n\t 2. Check if your controller or its members belongs to a client package."
              + "\n\t 3. Check the versions of all your modules.";

      throw new CruxGeneratorException(message);
    }
    Controller controllerAnnot = controllerClass.getAnnotation(Controller.class);
    if (controllerAnnot == null) {
      throw new CruxGeneratorException(
          "DeviceAdaptive implementation class ["
              + controllerClass.getQualifiedSourceName()
              + "] is not a valid Controller. It must be annotated with @Controller annotation.");
    }

    if (!controllerClass.isAssignableTo(deviceAdaptiveControllerClass)) {
      throw new CruxGeneratorException(
          "DeviceAdaptive implementation class ["
              + controllerClass.getQualifiedSourceName()
              + "] must externds the base class DeviceAdaptiveController.");
    }
  }
예제 #12
0
  public void build(
      TreeLogger logger, SourceBuilder<ModelMagic> builder, GeneratorContext ctx, JClassType type)
      throws UnableToCompleteException {

    ModelMagic models = builder.getPayload();
    ModelGenerator generator = new ModelGenerator(builder);
    // Step one; determine if we already have a concrete type or not.
    // TODO if JClassType is final, we need to wrap it using a delegate model.
    JClassType concrete;
    //    ClassBuffer cb = builder.getClassBuffer();
    JClassType root = models.getRootType(logger, ctx);
    if (type.isInterface() == null && type != root) {
      concrete = type;
      generator.setSuperClass(type.getQualifiedSourceName());
    } else {
      // We have an interface on our hands; search for an existing or
      // buildable model.
      // search for a supertype to inherit. Anything that extends Model,
      // does not implement any method we do implement, preferred type
      // being the one that implements the most interfaces possible
      final JClassType model;
      try {
        model = ctx.getTypeOracle().getType(Model.class.getName());
      } catch (NotFoundException e) {
        logger.log(
            Type.ERROR,
            "Cannot load "
                + Model.class.getName()
                + "; "
                + "make sure you have xapi-gwt-model:sources.jar on classpath.");
        throw new UnableToCompleteException();
      }
      concrete = model;
      for (JClassType supertype : concrete.getFlattenedSupertypeHierarchy()) {
        // Only interfaces explicitly extending Model become concrete.
        if (ModelGeneratorGwt.canBeSupertype(type, supertype)) {
          // prefer the concrete type with the most methods in common.
          concrete = supertype;
        }
      }
      if (concrete == null || concrete == model) {
        concrete = models.getRootType(logger, ctx);
        generator.setSuperClass(concrete.getQualifiedSourceName());
      } else {
        // We have to make sure this concrete supertype is created.
        if (!models.hasModel(concrete.getQualifiedSourceName())) {
          // Concrete type is not cached.  Build it now.
          RebindResult result =
              ModelGeneratorGwt.execImpl(logger, ctx, concrete.getQualifiedSourceName());
          generator.setSuperClass(result.getResultTypeName());
        }
      }
    }

    // This will probably become jsni, if we can avoid jso interface sickness...
    generator.createFactory(type.getQualifiedSourceName());

    HasModelFields fieldMap = new HasModelFields();
    fieldMap.setDefaultSerializable(type.getAnnotation(Serializable.class));

    for (JMethod method : methods.keySet()) {
      if (!toGenerate.contains(ModelGeneratorGwt.toSignature(method))) {
        logger.log(
            Type.TRACE, "Skipping method defined in supertype: " + method.getJsniSignature());
        continue;
      }

      Annotation[] annos = methods.get(method);
      String methodName = method.getName();
      String returnType = method.getReturnType().getQualifiedSourceName();
      String params = ModelGeneratorGwt.typeToParameterString(method.getParameterTypes());

      // TODO: check imports if we are safe to use simple name.
      returnType = method.getReturnType().getSimpleSourceName();
      IsType returns = X_Source.binaryToSource(method.getReturnType().getQualifiedBinaryName());
      IsType[] parameters = ModelGeneratorGwt.toTypes(method.getParameterTypes());

      GetterFor getter = method.getAnnotation(GetterFor.class);
      if (getter != null) {
        String name = getter.value();
        if (name.length() == 0) {
          name = ModelUtil.stripGetter(method.getName());
        }
        ModelField field = fieldMap.getOrMakeField(name);
        field.setType(returnType);
        assert parameters.length == 0
            : "A getter method cannot have parameters. "
                + "Generated code requires using getter methods without args.  You provided "
                + method.getJsniSignature();
        grabAnnotations(logger, models, fieldMap, method, annos, type);
        field.addGetter(returns, methodName);
        continue;
      }
      SetterFor setter = method.getAnnotation(SetterFor.class);
      if (setter != null) {
        String name = setter.value();
        if (name.length() == 0) name = ModelUtil.stripSetter(method.getName());
        grabAnnotations(logger, models, fieldMap, method, annos, type);
        continue;
      }

      if (method.getAnnotation(DeleterFor.class) != null) {
        implementAction(logger, generator, method, models, annos);
        continue;
      }

      // No annotation.  We have to guess the type.

      boolean isVoid = method.getReturnType().isPrimitive() == JPrimitiveType.VOID;
      boolean isGetter =
          methodName.startsWith("get")
              || methodName.startsWith("is")
              || methodName.startsWith("has");
      boolean isSetter, isAction;
      if (isGetter) {
        assert !isVoid
            : "Cannot have a void return type with method name "
                + methodName
                + "; getter prefixes get(), is() and has() must return a type.";
        isSetter = false;
        isAction = false;
      } else {
        isSetter =
            methodName.startsWith("set")
                || methodName.startsWith("add")
                || methodName.startsWith("put")
                || methodName.startsWith("rem")
                || methodName.startsWith("remove");
        if (isSetter) {
          isAction = false;
        } else {
          isAction = true;
        }
      }

      if (isVoid) {
        // definitely a setter / action method.
        if (isSetter) {
          MethodBuffer mb = generator.createMethod(returnType, methodName, params);
          implementSetter(logger, mb, method, models, fieldMap, annos);
        } else if (isAction) {
          implementAction(logger, generator, method, models, annos);
        } else {
          MethodBuffer mb = generator.createMethod(returnType, methodName, params);
          implementException(logger, mb, method);
        }
      } else {
        if (isGetter) {
          String name = ModelUtil.stripGetter(method.getName());
          ModelField field = fieldMap.getOrMakeField(name);
          field.setType(returnType);
          field.addGetter(returns, methodName);
          grabAnnotations(logger, models, fieldMap, method, annos, type);
        } else if (isSetter) {
          MethodBuffer mb = generator.createMethod(returnType, methodName, params);
          implementSetter(logger, mb, method, models, fieldMap, annos);
        } else if (isAction) {
          implementAction(logger, generator, method, models, annos);
        } else {
          MethodBuffer mb = generator.createMethod(returnType, methodName, params);
          implementException(logger, mb, method);
        }
      }
    }
    generator.generateModel(
        X_Source.toType(builder.getPackage(), builder.getClassBuffer().getSimpleName()), fieldMap);
  }
  private EntityProxyModel getEntityProxyType(JClassType entityProxyType)
      throws UnableToCompleteException {
    entityProxyType = ModelUtils.ensureBaseType(entityProxyType);
    EntityProxyModel toReturn = peers.get(entityProxyType);
    if (toReturn == null) {
      EntityProxyModel.Builder inProgress = peerBuilders.get(entityProxyType);
      if (inProgress != null) {
        toReturn = inProgress.peek();
      }
    }
    if (toReturn == null) {
      EntityProxyModel.Builder builder = new EntityProxyModel.Builder();
      peerBuilders.put(entityProxyType, builder);

      // Validate possible super-proxy types first
      for (JClassType supertype : entityProxyType.getFlattenedSupertypeHierarchy()) {
        List<EntityProxyModel> superTypes = new ArrayList<EntityProxyModel>();
        if (supertype != entityProxyType && shouldAttemptProxyValidation(supertype)) {
          superTypes.add(getEntityProxyType(supertype));
        }
        builder.setSuperProxyTypes(superTypes);
      }

      builder.setQualifiedBinaryName(ModelUtils.getQualifiedBaseBinaryName(entityProxyType));
      builder.setQualifiedSourceName(ModelUtils.getQualifiedBaseSourceName(entityProxyType));
      if (entityProxyInterface.isAssignableFrom(entityProxyType)) {
        builder.setType(Type.ENTITY);
      } else if (valueProxyInterface.isAssignableFrom(entityProxyType)) {
        builder.setType(Type.VALUE);
      } else {
        poison(
            "The type %s is not assignable to either %s or %s",
            entityProxyInterface.getQualifiedSourceName(),
            valueProxyInterface.getQualifiedSourceName());
        // Cannot continue, since knowing the behavior is crucial
        die(poisonedMessage());
      }

      // Get the server domain object type
      ProxyFor proxyFor = entityProxyType.getAnnotation(ProxyFor.class);
      ProxyForName proxyForName = entityProxyType.getAnnotation(ProxyForName.class);
      JsonRpcProxy jsonRpcProxy = entityProxyType.getAnnotation(JsonRpcProxy.class);
      if (proxyFor == null && proxyForName == null && jsonRpcProxy == null) {
        poison(
            "The %s type does not have a @%s, @%s, or @%s annotation",
            entityProxyType.getQualifiedSourceName(),
            ProxyFor.class.getSimpleName(),
            ProxyForName.class.getSimpleName(),
            JsonRpcProxy.class.getSimpleName());
      }

      // Look at the methods declared on the EntityProxy
      List<RequestMethod> requestMethods = new ArrayList<RequestMethod>();
      Map<String, JMethod> duplicatePropertyGetters = new HashMap<String, JMethod>();
      for (JMethod method : entityProxyType.getInheritableMethods()) {
        if (method.getEnclosingType().equals(entityProxyInterface)) {
          // Ignore methods on EntityProxy
          continue;
        }
        RequestMethod.Builder methodBuilder = new RequestMethod.Builder();
        methodBuilder.setDeclarationMethod(entityProxyType, method);

        JType transportedType;
        String name = method.getName();
        if (JBeanMethod.GET.matches(method)) {
          transportedType = method.getReturnType();
          String propertyName = JBeanMethod.GET.inferName(method);
          JMethod previouslySeen = duplicatePropertyGetters.get(propertyName);
          if (previouslySeen == null) {
            duplicatePropertyGetters.put(propertyName, method);
          } else {
            poison(
                "Duplicate accessors for property %s: %s() and %s()",
                propertyName, previouslySeen.getName(), method.getName());
          }

        } else if (JBeanMethod.SET.matches(method) || JBeanMethod.SET_BUILDER.matches(method)) {
          transportedType = method.getParameters()[0].getType();

        } else if (name.equals("stableId") && method.getParameters().length == 0) {
          // Ignore any overload of stableId
          continue;
        } else {
          poison("The method %s is neither a getter nor a setter", method.getReadableDeclaration());
          continue;
        }
        validateTransportableType(methodBuilder, transportedType, false);
        RequestMethod requestMethod = methodBuilder.build();
        requestMethods.add(requestMethod);
      }
      builder
          .setExtraTypes(checkExtraTypes(entityProxyType, false))
          .setRequestMethods(requestMethods);

      toReturn = builder.build();
      peers.put(entityProxyType, toReturn);
      peerBuilders.remove(entityProxyType);
    }
    return toReturn;
  }