Exemplo n.º 1
1
 public <T> T createProxy(
     ModelElementState state,
     StructSchema<T> viewSchema,
     @Nullable StructSchema<? extends T> delegateSchema,
     TypeConverter typeConverter) {
   try {
     Class<? extends T> generatedClass = getGeneratedImplementation(viewSchema, delegateSchema);
     if (generatedClass == null) {
       throw new IllegalStateException(
           "No managed implementation class available for: " + viewSchema.getType());
     }
     if (delegateSchema == null) {
       Constructor<? extends T> constructor =
           generatedClass.getConstructor(ModelElementState.class, TypeConverter.class);
       return constructor.newInstance(state, typeConverter);
     } else {
       ModelType<? extends T> delegateType = delegateSchema.getType();
       Object delegate = state.getBackingNode().getPrivateData(delegateType);
       Constructor<? extends T> constructor =
           generatedClass.getConstructor(
               ModelElementState.class, TypeConverter.class, delegateType.getConcreteClass());
       return constructor.newInstance(state, typeConverter, delegate);
     }
   } catch (InvocationTargetException e) {
     throw UncheckedException.throwAsUncheckedException(e.getTargetException());
   } catch (Exception e) {
     throw UncheckedException.throwAsUncheckedException(e);
   }
 }
 @Override
 public <T> void extract(ModelSchemaExtractionContext<T> extractionContext) {
   Type type = extractionContext.getType().getType();
   if (!(type instanceof Class)) {
     return;
   }
   Class<?> contractType = (Class<?>) type;
   if (!contractType.isInterface()) {
     return;
   }
   if (contractType.getGenericInterfaces().length != 1) {
     return;
   }
   Type superType = contractType.getGenericInterfaces()[0];
   if (!(superType instanceof ParameterizedType)) {
     return;
   }
   ParameterizedType parameterizedSuperType = (ParameterizedType) superType;
   if (!parameterizedSuperType.getRawType().equals(ModelMap.class)) {
     return;
   }
   ModelType<?> elementType = ModelType.of(parameterizedSuperType.getActualTypeArguments()[0]);
   Class<?> proxyImpl = generator.generate(ModelMapGroovyDecorator.Managed.class, contractType);
   extractionContext.found(
       new SpecializedMapSchema<T>(extractionContext.getType(), elementType, proxyImpl));
 }
 private void generateProxyClass(
     ClassWriter visitor,
     StructSchema<?> viewSchema,
     StructSchema<?> delegateSchema,
     Collection<String> interfacesToImplement,
     Set<Class<?>> typesToDelegate,
     Type generatedType,
     Type superclassType) {
   ModelType<?> viewType = viewSchema.getType();
   Class<?> viewClass = viewType.getConcreteClass();
   declareClass(visitor, interfacesToImplement, generatedType, superclassType);
   declareStateField(visitor);
   declareTypeConverterField(visitor);
   declareManagedTypeField(visitor);
   declareCanCallSettersField(visitor);
   writeStaticConstructor(visitor, generatedType, viewClass);
   writeConstructor(visitor, generatedType, superclassType, delegateSchema);
   writeToString(visitor, generatedType, viewClass, delegateSchema);
   writeManagedInstanceMethods(visitor, generatedType);
   if (delegateSchema != null) {
     declareDelegateField(visitor, delegateSchema);
     writeDelegateMethods(visitor, generatedType, delegateSchema, typesToDelegate);
   }
   writeGroovyMethods(visitor, viewClass);
   writePropertyMethods(visitor, generatedType, viewSchema, delegateSchema);
   writeHashCodeMethod(visitor, generatedType);
   writeEqualsMethod(visitor, generatedType);
   visitor.visitEnd();
 }
Exemplo n.º 4
0
/**
 * Base class that may be used for custom {@link GeneralComponentSpec} implementations. However, it
 * is generally better to use an interface annotated with {@link org.gradle.model.Managed} and not
 * use an implementation class at all.
 */
@Incubating
public class BaseComponentSpec extends DefaultComponentSpec implements GeneralComponentSpec {
  private static final ModelType<BinarySpec> BINARY_SPEC_MODEL_TYPE =
      ModelType.of(BinarySpec.class);
  private static final ModelType<LanguageSourceSet> LANGUAGE_SOURCE_SET_MODEL_TYPE =
      ModelType.of(LanguageSourceSet.class);
  private final MutableModelNode binaries;
  private final MutableModelNode sources;

  public BaseComponentSpec() {
    MutableModelNode modelNode = getInfo().modelNode;
    binaries = ModelMaps.addModelMapNode(modelNode, BINARY_SPEC_MODEL_TYPE, "binaries");
    sources = ModelMaps.addModelMapNode(modelNode, LANGUAGE_SOURCE_SET_MODEL_TYPE, "sources");
  }

  @Override
  public ModelMap<LanguageSourceSet> getSources() {
    return ModelMaps.toView(sources, LANGUAGE_SOURCE_SET_MODEL_TYPE);
  }

  @Override
  public ModelMap<BinarySpec> getBinaries() {
    return ModelMaps.toView(binaries, BINARY_SPEC_MODEL_TYPE);
  }
}
 private <T extends ComponentSpec> void registerImplementation(
     ComponentSpecFactory components, List<ModelView<?>> inputs) {
   ServiceRegistry serviceRegistry =
       ModelViews.assertType(inputs.get(0), ModelType.of(ServiceRegistry.class)).getInstance();
   final Instantiator instantiator = serviceRegistry.get(Instantiator.class);
   final ProjectIdentifier projectIdentifier =
       ModelViews.assertType(inputs.get(1), ModelType.of(ProjectIdentifier.class)).getInstance();
   final ProjectSourceSet projectSourceSet =
       ModelViews.assertType(inputs.get(2), ModelType.of(ProjectSourceSet.class)).getInstance();
   components.registerFactory(
       Cast.<ModelType<ComponentSpec>>uncheckedCast(publicType),
       descriptor,
       new BiFunction<ComponentSpec, String, MutableModelNode>() {
         @Override
         public ComponentSpec apply(String name, MutableModelNode modelNode) {
           ComponentSpecIdentifier id =
               new DefaultComponentSpecIdentifier(projectIdentifier.getPath(), name);
           return BaseComponentSpec.create(
               implementationType.getConcreteClass(),
               id,
               modelNode,
               projectSourceSet,
               instantiator);
         }
       });
   components.registerImplementation(
       Cast.<ModelType<T>>uncheckedCast(publicType),
       descriptor,
       Cast.<ModelType<? extends T>>uncheckedCast(implementationType));
   if (COMPONENT_SPEC_INTERNAL_MODEL_TYPE.isAssignableFrom(implementationType)) {
     components.registerInternalView(publicType, descriptor, COMPONENT_SPEC_INTERNAL_MODEL_TYPE);
   }
 }
 protected void validateElementType(Object o) {
   if (o != null) {
     ModelType<?> obType = ModelType.of(o.getClass());
     if (!obType.equals(elementType)) {
       throw new IllegalArgumentException(
           String.format(
               "Cannot add an element of type %s to a collection of %s", obType, elementType));
     }
   }
 }
 private static void maybeAppendConstructables(
     StringBuffer s, Iterable<ModelType<?>> constructableTypes, int pad) {
   if (!Iterables.isEmpty(constructableTypes)) {
     String padding = pad(pad);
     s.append(String.format("%n%s- or a type which Gradle is capable of constructing:", padding));
     for (ModelType<?> modelType : constructableTypes) {
       s.append(String.format("%n    %s- %s", padding, modelType.getName()));
     }
   }
 }
Exemplo n.º 8
0
  private void validateRuleMethod(
      MethodRuleDefinition<?, ?> ruleDefinition,
      Method ruleMethod,
      ValidationProblemCollector problems) {
    if (Modifier.isPrivate(ruleMethod.getModifiers())) {
      problems.add(ruleMethod, "A rule method cannot be private");
    }
    if (Modifier.isAbstract(ruleMethod.getModifiers())) {
      problems.add(ruleMethod, "A rule method cannot be abstract");
    }

    if (ruleMethod.getTypeParameters().length > 0) {
      problems.add(ruleMethod, "Cannot have type variables (i.e. cannot be a generic method)");
    }

    // TODO validations on method: synthetic, bridge methods, varargs, abstract, native
    ModelType<?> returnType = ModelType.returnType(ruleMethod);
    if (returnType.isRawClassOfParameterizedType()) {
      problems.add(
          ruleMethod,
          "Raw type "
              + returnType
              + " used for return type (all type parameters must be specified of parameterized type)");
    }

    for (int i = 0; i < ruleDefinition.getReferences().size(); i++) {
      ModelReference<?> reference = ruleDefinition.getReferences().get(i);
      if (reference.getType().isRawClassOfParameterizedType()) {
        problems.add(
            ruleMethod,
            "Raw type "
                + reference.getType()
                + " used for parameter "
                + (i + 1)
                + " (all type parameters must be specified of parameterized type)");
      }
      if (reference.getPath() != null) {
        try {
          ModelPath.validatePath(reference.getPath().toString());
        } catch (Exception e) {
          problems.add(
              ruleDefinition,
              "The declared model element path '"
                  + reference.getPath()
                  + "' used for parameter "
                  + (i + 1)
                  + " is not a valid path",
              e);
        }
      }
    }
  }
Exemplo n.º 9
0
 @Nullable
 public ModelType<?> getUpperBound() {
   WildcardWrapper wildcardType = getWildcardType();
   if (wildcardType == null) {
     return null;
   } else {
     ModelType<?> upperBound = Simple.typed(wildcardType.getUpperBound());
     if (upperBound.equals(UNTYPED)) {
       return null;
     }
     return upperBound;
   }
 }
Exemplo n.º 10
0
  public boolean isHasWildcardTypeVariables() {
    if (isWildcard()) {
      return true;
    } else if (isParameterized()) {
      for (ModelType<?> typeVariable : getTypeVariables()) {
        if (typeVariable.isHasWildcardTypeVariables()) {
          return true;
        }
      }
    }

    return false;
  }
Exemplo n.º 11
0
  /**
   * Casts this {@code ModelType} object to represent a subclass of the class represented by the
   * specified class object. Checks that the cast is valid, and throws a {@code ClassCastException}
   * if it is not. If this method succeeds, it always returns a reference to this {@code ModelType}
   * object.
   *
   * @throws ClassCastException if this cannot be cast as the subtype of the given type.
   * @throws IllegalStateException if this is a wildcard.
   * @throws IllegalArgumentException if the given type is a wildcard.
   */
  public <U> ModelType<? extends U> asSubtype(ModelType<U> modelType) {
    if (isWildcard()) {
      throw new IllegalStateException(this + " is a wildcard type");
    }
    if (modelType.isWildcard()) {
      throw new IllegalArgumentException(modelType + " is a wildcard type");
    }

    if (modelType.getRawClass().isAssignableFrom(getRawClass())) {
      return Cast.uncheckedCast(this);
    } else {
      throw new ClassCastException(
          String.format("'%s' cannot be cast as a subtype of '%s'", this, modelType));
    }
  }
Exemplo n.º 12
0
  private <T> CachedRuleSource doExtract(final Class<T> source) {
    final ModelType<T> type = ModelType.of(source);
    DefaultMethodModelRuleExtractionContext context =
        new DefaultMethodModelRuleExtractionContext(type, this);

    // TODO - exceptions thrown here should point to some extensive documentation on the concept of
    // class rule sources

    StructSchema<T> schema = getSchema(source, context);
    if (schema == null) {
      throw new InvalidModelRuleDeclarationException(context.problems.format());
    }

    // sort for determinism
    Set<Method> methods = new TreeSet<Method>(Ordering.usingToString());
    methods.addAll(Arrays.asList(source.getDeclaredMethods()));

    ImmutableList.Builder<ModelProperty<?>> implicitInputs = ImmutableList.builder();
    ModelProperty<?> target = null;
    for (ModelProperty<?> property : schema.getProperties()) {
      if (property.isAnnotationPresent(RuleTarget.class)) {
        target = property;
      } else if (property.isAnnotationPresent(RuleInput.class)
          && !(property.getSchema() instanceof ScalarValueSchema)) {
        implicitInputs.add(property);
      }
      for (WeaklyTypeReferencingMethod<?, ?> method : property.getAccessors()) {
        methods.remove(method.getMethod());
      }
    }

    ImmutableList.Builder<ExtractedRuleDetails> rules = ImmutableList.builder();
    for (Method method : methods) {
      MethodRuleDefinition<?, ?> ruleDefinition =
          DefaultMethodRuleDefinition.create(source, method);
      ExtractedModelRule rule = getMethodHandler(ruleDefinition, method, context);
      if (rule != null) {
        rules.add(new ExtractedRuleDetails(ruleDefinition, rule));
      }
    }

    if (context.hasProblems()) {
      throw new InvalidModelRuleDeclarationException(context.problems.format());
    }

    StructBindings<T> bindings = structBindingsStore.getBindings(schema);

    if (schema.getProperties().isEmpty()) {
      return new StatelessRuleSource(
          rules.build(),
          Modifier.isAbstract(source.getModifiers())
              ? new AbstractRuleSourceFactory<T>(schema, bindings, proxyFactory)
              : new ConcreteRuleSourceFactory<T>(type));
    } else {
      return new ParameterizedRuleSource(
          rules.build(), target, implicitInputs.build(), schema, bindings, proxyFactory);
    }
  }
 @Override
 protected void execute(
     MutableModelNode modelNode, ComponentSpecFactory components, List<ModelView<?>> inputs) {
   components.registerPublicType(publicType);
   if (implementationType != null) {
     registerImplementation(components, inputs);
   }
   for (Class<?> internalView : internalViews) {
     components.registerInternalView(publicType, descriptor, ModelType.of(internalView));
   }
 }
    @Override
    public boolean equals(Object o) {
      if (this == o) {
        return true;
      }
      if (o == null || getClass() != o.getClass()) {
        return false;
      }

      ListViewFactory<?> that = (ListViewFactory<?>) o;
      return elementType.equals(that.elementType);
    }
 @Override
 protected <T, E> NodeInitializer extractNodeInitializer(
     ModelCollectionSchema<T, E> schema, NodeInitializerRegistry nodeInitializerRegistry) {
   ModelType<T> type = schema.getType();
   Class<? super T> rawClass = type.getRawClass();
   ModelType<? super T> rawCollectionType = ModelType.of(rawClass);
   if (TYPES.contains(rawCollectionType)) {
     if (schema.getType().getRawClass() == List.class) {
       return new ProjectionOnlyNodeInitializer(
           ScalarCollectionModelProjection.get(
               ModelTypes.list(schema.getElementType()),
               new ListViewFactory<E>(schema.getElementType())));
     } else {
       return new ProjectionOnlyNodeInitializer(
           ScalarCollectionModelProjection.get(
               ModelTypes.set(schema.getElementType()),
               new SetViewFactory<E>(schema.getElementType())));
     }
   }
   return null;
 }
Exemplo n.º 16
0
 @Override
 public T create() {
   Class<T> concreteClass = type.getConcreteClass();
   try {
     Constructor<T> declaredConstructor = concreteClass.getDeclaredConstructor();
     declaredConstructor.setAccessible(true);
     return declaredConstructor.newInstance();
   } catch (InvocationTargetException e) {
     throw UncheckedException.throwAsUncheckedException(e.getTargetException());
   } catch (Exception e) {
     throw UncheckedException.throwAsUncheckedException(e);
   }
 }
Exemplo n.º 17
0
  public <T> ModelSchemaExtractionResult<T> extract(
      ModelSchemaExtractionContext<T> extractionContext,
      ModelSchemaStore store,
      final ModelSchemaCache cache) {
    ModelType<T> type = extractionContext.getType();
    if (MODEL_MAP_MODEL_TYPE.isAssignableFrom(type)) {
      if (!type.getRawClass().equals(ModelMap.class)) {
        throw new InvalidManagedModelElementTypeException(
            extractionContext,
            String.format("subtyping %s is not supported.", ModelMap.class.getName()));
      }
      if (type.isHasWildcardTypeVariables()) {
        throw new InvalidManagedModelElementTypeException(
            extractionContext,
            String.format("type parameter of %s cannot be a wildcard.", ModelMap.class.getName()));
      }

      List<ModelType<?>> typeVariables = type.getTypeVariables();
      if (typeVariables.isEmpty()) {
        throw new InvalidManagedModelElementTypeException(
            extractionContext,
            String.format("type parameter of %s has to be specified.", ModelMap.class.getName()));
      }

      ModelType<?> elementType = typeVariables.get(0);

      if (MODEL_MAP_MODEL_TYPE.isAssignableFrom(elementType)) {
        throw new InvalidManagedModelElementTypeException(
            extractionContext,
            String.format(
                "%1$s cannot be used as type parameter of %1$s.", ModelMap.class.getName()));
      }

      return gettModelSchemaExtractionResult(extractionContext, cache, elementType, store);
    } else {
      return null;
    }
  }
 @Override
 protected <R> ModelSchema<R> createSchema(
     ModelSchemaExtractionContext<R> extractionContext,
     ModelSchemaStore store,
     ModelType<R> type,
     List<ModelProperty<?>> properties,
     List<ModelSchemaAspect> aspects) {
   return new ModelManagedImplStructSchema<R>(
       type,
       properties,
       aspects,
       type.getConcreteClass(),
       delegateType,
       Functions.<NodeInitializer>constant(null));
 }
Exemplo n.º 19
0
  public <T> T getPrivateData(ModelType<T> type) {
    if (privateData == null) {
      return null;
    }

    if (!type.isAssignableFrom(privateDataType)) {
      throw new ClassCastException(
          "Cannot get private data '"
              + privateData
              + "' of type '"
              + privateDataType
              + "' as type '"
              + type);
    }
    return Cast.uncheckedCast(privateData);
  }
Exemplo n.º 20
0
 /** Invoked by transformed DSL creation rules */
 public <T> void create(String modelPathString, Class<T> type, Closure<?> closure) {
   SourceLocation sourceLocation = ruleLocationExtractor.transform(closure);
   ModelPath modelPath = ModelPath.path(modelPathString);
   ModelRuleDescriptor descriptor = toDescriptor(sourceLocation, modelPath);
   try {
     NodeInitializerRegistry nodeInitializerRegistry =
         modelRegistry.realize(
             DefaultNodeInitializerRegistry.DEFAULT_REFERENCE.getPath(),
             DefaultNodeInitializerRegistry.DEFAULT_REFERENCE.getType());
     NodeInitializer nodeInitializer =
         nodeInitializerRegistry.getNodeInitializer(ModelType.of(type));
     modelRegistry.create(
         ModelCreators.of(modelPath, nodeInitializer).descriptor(descriptor).build());
   } catch (ModelTypeInitializationException e) {
     throw new InvalidModelRuleDeclarationException(descriptor, e);
   }
   registerAction(modelPath, type, descriptor, ModelActionRole.Initialize, closure);
 }
 private void addPropertyLinks(
     MutableModelNode modelNode,
     ModelSchemaStore schemaStore,
     NodeInitializerRegistry nodeInitializerRegistry) {
   for (ManagedProperty<?> property : bindings.getManagedProperties().values()) {
     addPropertyLink(modelNode, property, schemaStore, nodeInitializerRegistry);
   }
   if (isNamedType()) {
     // Only initialize "name" child node if the schema has such a managed property.
     // This is not the case for a managed subtype of an unmanaged type that implements Named.
     if (bindings.getManagedProperties().containsKey("name")) {
       MutableModelNode nameLink = modelNode.getLink("name");
       if (nameLink == null) {
         throw new IllegalStateException("expected name node for " + modelNode.getPath());
       }
       nameLink.setPrivateData(ModelType.of(String.class), modelNode.getPath().getName());
     }
   }
 }
Exemplo n.º 22
0
 @Override
 public <T> T getPrivateData(Class<T> type) {
   return getPrivateData(ModelType.of(type));
 }
Exemplo n.º 23
0
 @Override
 public <T> void setPrivateData(Class<? super T> type, T object) {
   setPrivateData(ModelType.of(type), object);
 }
  private static class RegistrationAction
      extends AbstractModelActionWithView<ComponentSpecFactory> {
    private static final ModelType<ComponentSpecInternal> COMPONENT_SPEC_INTERNAL_MODEL_TYPE =
        ModelType.of(ComponentSpecInternal.class);

    private final ModelType<? extends ComponentSpec> publicType;
    private final ModelType<? extends BaseComponentSpec> implementationType;
    private final Set<Class<?>> internalViews;

    public RegistrationAction(
        ModelType<? extends ComponentSpec> publicType,
        ModelType<? extends BaseComponentSpec> implementationType,
        Set<Class<?>> internalViews,
        ModelRuleDescriptor descriptor) {
      super(
          ModelReference.of(ComponentSpecFactory.class),
          descriptor,
          ModelReference.of("serviceRegistry", ServiceRegistry.class),
          ModelReference.of("projectIdentifier", ProjectIdentifier.class),
          ModelReference.of("sources", ProjectSourceSet.class));
      this.publicType = publicType;
      this.implementationType = implementationType;
      this.internalViews = internalViews;
    }

    @Override
    protected void execute(
        MutableModelNode modelNode, ComponentSpecFactory components, List<ModelView<?>> inputs) {
      components.registerPublicType(publicType);
      if (implementationType != null) {
        registerImplementation(components, inputs);
      }
      for (Class<?> internalView : internalViews) {
        components.registerInternalView(publicType, descriptor, ModelType.of(internalView));
      }
    }

    private <T extends ComponentSpec> void registerImplementation(
        ComponentSpecFactory components, List<ModelView<?>> inputs) {
      ServiceRegistry serviceRegistry =
          ModelViews.assertType(inputs.get(0), ModelType.of(ServiceRegistry.class)).getInstance();
      final Instantiator instantiator = serviceRegistry.get(Instantiator.class);
      final ProjectIdentifier projectIdentifier =
          ModelViews.assertType(inputs.get(1), ModelType.of(ProjectIdentifier.class)).getInstance();
      final ProjectSourceSet projectSourceSet =
          ModelViews.assertType(inputs.get(2), ModelType.of(ProjectSourceSet.class)).getInstance();
      components.registerFactory(
          Cast.<ModelType<ComponentSpec>>uncheckedCast(publicType),
          descriptor,
          new BiFunction<ComponentSpec, String, MutableModelNode>() {
            @Override
            public ComponentSpec apply(String name, MutableModelNode modelNode) {
              ComponentSpecIdentifier id =
                  new DefaultComponentSpecIdentifier(projectIdentifier.getPath(), name);
              return BaseComponentSpec.create(
                  implementationType.getConcreteClass(),
                  id,
                  modelNode,
                  projectSourceSet,
                  instantiator);
            }
          });
      components.registerImplementation(
          Cast.<ModelType<T>>uncheckedCast(publicType),
          descriptor,
          Cast.<ModelType<? extends T>>uncheckedCast(implementationType));
      if (COMPONENT_SPEC_INTERNAL_MODEL_TYPE.isAssignableFrom(implementationType)) {
        components.registerInternalView(publicType, descriptor, COMPONENT_SPEC_INTERNAL_MODEL_TYPE);
      }
    }
  }
public class ScalarCollectionNodeInitializerExtractionStrategy
    extends CollectionNodeInitializerExtractionSupport {
  public static final List<ModelType<?>> TYPES =
      ImmutableList.<ModelType<?>>of(ModelType.of(List.class), ModelType.of(Set.class));

  @Override
  protected <T, E> NodeInitializer extractNodeInitializer(
      ModelCollectionSchema<T, E> schema, NodeInitializerRegistry nodeInitializerRegistry) {
    ModelType<T> type = schema.getType();
    Class<? super T> rawClass = type.getRawClass();
    ModelType<? super T> rawCollectionType = ModelType.of(rawClass);
    if (TYPES.contains(rawCollectionType)) {
      if (schema.getType().getRawClass() == List.class) {
        return new ProjectionOnlyNodeInitializer(
            ScalarCollectionModelProjection.get(
                ModelTypes.list(schema.getElementType()),
                new ListViewFactory<E>(schema.getElementType())));
      } else {
        return new ProjectionOnlyNodeInitializer(
            ScalarCollectionModelProjection.get(
                ModelTypes.set(schema.getElementType()),
                new SetViewFactory<E>(schema.getElementType())));
      }
    }
    return null;
  }

  private static class ScalarCollectionModelProjection<E> extends TypedModelProjection<E> {

    public static <E, U extends Collection<E>> ScalarCollectionModelProjection<U> get(
        ModelType<U> type, ModelViewFactory<U> viewFactory) {
      return new ScalarCollectionModelProjection<U>(type, viewFactory);
    }

    public ScalarCollectionModelProjection(ModelType<E> type, ModelViewFactory<E> viewFactory) {
      super(type, viewFactory, true, true);
    }

    @Override
    public Optional<String> getValueDescription(MutableModelNode modelNodeInternal) {
      Collection<?> values = ScalarCollectionSchema.get(modelNodeInternal);
      if (values == null) {
        return Optional.absent();
      }
      return Optional.of(values.toString());
    }
  }

  public static class ListViewFactory<T> implements ModelViewFactory<List<T>> {
    private final ModelType<T> elementType;

    public ListViewFactory(ModelType<T> elementType) {
      this.elementType = elementType;
    }

    @Override
    public ModelView<List<T>> toView(
        MutableModelNode modelNode, ModelRuleDescriptor ruleDescriptor, boolean writable) {
      ModelType<List<T>> listType = ModelTypes.list(elementType);
      DefaultModelViewState state =
          new DefaultModelViewState(listType, ruleDescriptor, writable, !writable);
      ListBackedCollection<T> list = new ListBackedCollection<T>(modelNode, state, elementType);
      return InstanceModelView.of(modelNode.getPath(), listType, list, state.closer());
    }

    @Override
    public boolean equals(Object o) {
      if (this == o) {
        return true;
      }
      if (o == null || getClass() != o.getClass()) {
        return false;
      }

      ListViewFactory<?> that = (ListViewFactory<?>) o;
      return elementType.equals(that.elementType);
    }

    @Override
    public int hashCode() {
      return elementType.hashCode();
    }
  }

  public static class SetViewFactory<T> implements ModelViewFactory<Set<T>> {
    private final ModelType<T> elementType;

    public SetViewFactory(ModelType<T> elementType) {
      this.elementType = elementType;
    }

    @Override
    public ModelView<Set<T>> toView(
        MutableModelNode modelNode, ModelRuleDescriptor ruleDescriptor, boolean writable) {
      ModelType<Set<T>> setType = ModelTypes.set(elementType);
      DefaultModelViewState state =
          new DefaultModelViewState(setType, ruleDescriptor, writable, !writable);
      SetBackedCollection<T> set = new SetBackedCollection<T>(modelNode, state, elementType);
      return InstanceModelView.of(modelNode.getPath(), setType, set, state.closer());
    }

    @Override
    public boolean equals(Object o) {
      if (this == o) {
        return true;
      }
      if (o == null || getClass() != o.getClass()) {
        return false;
      }

      ListViewFactory<?> that = (ListViewFactory<?>) o;
      return elementType.equals(that.elementType);
    }

    @Override
    public int hashCode() {
      return elementType.hashCode();
    }
  }

  private abstract static class NodeBackedCollection<T, C extends Collection<T>>
      implements Collection<T>, ManagedInstance {
    private final MutableModelNode modelNode;
    private final ModelViewState state;
    private final ModelType<T> elementType;

    public NodeBackedCollection(
        MutableModelNode modelNode, ModelViewState state, ModelType<T> elementType) {
      this.modelNode = modelNode;
      this.state = state;
      this.elementType = elementType;
    }

    protected C getDelegate(boolean write) {
      if (write) {
        state.assertCanMutate();
      }
      Collection<T> delegate = Cast.uncheckedCast(ScalarCollectionSchema.get(modelNode));
      return initialValue(write, delegate);
    }

    protected abstract C createPrivateData(boolean mutable);

    private C initialValue(boolean write, Collection<T> delegate) {
      if (delegate == null) {
        if (write) {
          delegate = createPrivateData(true);
          ScalarCollectionSchema.set(modelNode, delegate);
        } else {
          delegate = createPrivateData(false);
        }
      }
      return Cast.uncheckedCast(delegate);
    }

    @Override
    public MutableModelNode getBackingNode() {
      return modelNode;
    }

    @Override
    public ModelType<?> getManagedType() {
      return ModelType.of(this.getClass());
    }

    protected void validateElementType(Object o) {
      if (o != null) {
        ModelType<?> obType = ModelType.of(o.getClass());
        if (!obType.equals(elementType)) {
          throw new IllegalArgumentException(
              String.format(
                  "Cannot add an element of type %s to a collection of %s", obType, elementType));
        }
      }
    }

    protected void validateCollection(Collection<? extends T> c) {
      for (T element : c) {
        validateElementType(element);
      }
    }

    @Override
    public boolean add(T t) {
      validateElementType(t);
      return getDelegate(true).add(t);
    }

    @Override
    public boolean addAll(Collection<? extends T> c) {
      validateCollection(c);
      return getDelegate(true).addAll(c);
    }

    @Override
    public void clear() {
      getDelegate(true).clear();
    }

    @Override
    public boolean contains(Object o) {
      return getDelegate(false).contains(o);
    }

    @Override
    public boolean containsAll(Collection<?> c) {
      return getDelegate(false).containsAll(c);
    }

    @Override
    public boolean equals(Object o) {
      return getDelegate(false).equals(o);
    }

    @Override
    public int hashCode() {
      return getDelegate(false).hashCode();
    }

    @Override
    public boolean isEmpty() {
      return getDelegate(false).isEmpty();
    }

    @Override
    public Iterator<T> iterator() {
      return new MutationSafeIterator(getDelegate(false).iterator());
    }

    @Override
    public boolean remove(Object o) {
      return getDelegate(true).remove(o);
    }

    @Override
    public boolean removeAll(Collection<?> c) {
      return getDelegate(true).removeAll(c);
    }

    @Override
    public boolean retainAll(Collection<?> c) {
      return getDelegate(true).retainAll(c);
    }

    @Override
    public int size() {
      return getDelegate(false).size();
    }

    @Override
    public Object[] toArray() {
      return getDelegate(false).toArray();
    }

    @Override
    public <T> T[] toArray(T[] a) {
      return getDelegate(false).toArray(a);
    }

    private final class MutationSafeIterator implements Iterator<T> {
      private final Iterator<T> delegate;

      private MutationSafeIterator(Iterator<T> delegate) {
        this.delegate = delegate;
      }

      @Override
      public boolean hasNext() {
        return delegate.hasNext();
      }

      @Override
      public T next() {
        return delegate.next();
      }

      @Override
      public void remove() {
        state.assertCanMutate();
        delegate.remove();
      }
    }
  }

  private static class ListBackedCollection<T> extends NodeBackedCollection<T, List<T>>
      implements List<T> {

    public ListBackedCollection(
        MutableModelNode modelNode, ModelViewState state, ModelType<T> elementType) {
      super(modelNode, state, elementType);
    }

    @Override
    protected List<T> createPrivateData(boolean mutable) {
      if (mutable) {
        return Lists.newArrayList();
      }
      return Collections.emptyList();
    }

    @Override
    public void add(int index, T element) {
      validateElementType(element);
      getDelegate(true).add(index, element);
    }

    @Override
    public boolean addAll(int index, Collection<? extends T> c) {
      validateCollection(c);
      return getDelegate(true).addAll(index, c);
    }

    @Override
    public T get(int index) {
      return getDelegate(false).get(index);
    }

    @Override
    public int indexOf(Object o) {
      return getDelegate(false).indexOf(o);
    }

    @Override
    public int lastIndexOf(Object o) {
      return getDelegate(false).lastIndexOf(o);
    }

    @Override
    public ListIterator<T> listIterator() {
      return getDelegate(false).listIterator();
    }

    @Override
    public ListIterator<T> listIterator(int index) {
      return getDelegate(false).listIterator(index);
    }

    @Override
    public T remove(int index) {
      return getDelegate(true).remove(index);
    }

    @Override
    public List<T> subList(int fromIndex, int toIndex) {
      throw new UnsupportedOperationException();
    }

    @Override
    public T set(int index, T element) {
      validateElementType(element);
      return getDelegate(true).set(index, element);
    }
  }

  private static class SetBackedCollection<T> extends NodeBackedCollection<T, Set<T>>
      implements Set<T> {

    public SetBackedCollection(
        MutableModelNode modelNode, ModelViewState state, ModelType<T> elementType) {
      super(modelNode, state, elementType);
    }

    @Override
    protected Set<T> createPrivateData(boolean mutable) {
      if (mutable) {
        return Sets.newLinkedHashSet();
      } else {
        return Collections.emptySet();
      }
    }
  }
}
 @Override
 public ModelType<?> getManagedType() {
   return ModelType.of(this.getClass());
 }
 @Override
 public int hashCode() {
   return elementType.hashCode();
 }
Exemplo n.º 28
0
/**
 * A type token, representing a resolved type.
 *
 * <p>Importantly, instances do not hold strong references to class objects.
 *
 * <p>Construct a type via one of the public static methods, or by creating an AIC…
 *
 * <pre>{@code
 * ModelType<List<String>> type = new ModelType<List<String>>() {};
 * }</pre>
 */
@ThreadSafe
public abstract class ModelType<T> {

  public static final ModelType<Object> UNTYPED = ModelType.of(Object.class);

  private final TypeWrapper wrapper;

  private ModelType(TypeWrapper wrapper) {
    this.wrapper = wrapper;
  }

  protected ModelType() {
    this.wrapper = wrap(new TypeToken<T>(getClass()) {}.getType());
  }

  public static <T> ModelType<T> of(Class<T> clazz) {
    return new Simple<T>(clazz);
  }

  public static <T> ModelType<T> returnType(Method method) {
    return new Simple<T>(method.getGenericReturnType());
  }

  public static <T> ModelType<T> declaringType(Method method) {
    return new Simple<T>(method.getDeclaringClass());
  }

  @Nullable
  public static <T> ModelType<T> paramType(Method method, int i) {
    Type[] parameterTypes = method.getGenericParameterTypes();
    if (i < parameterTypes.length) {
      return new Simple<T>(parameterTypes[i]);
    } else {
      return null;
    }
  }

  public static <T> ModelType<T> typeOf(T instance) {
    // TODO: should validate that clazz is of a non parameterized type
    @SuppressWarnings("unchecked")
    Class<T> clazz = (Class<T>) instance.getClass();
    return of(clazz);
  }

  public static ModelType<?> of(Type type) {
    return Simple.typed(type);
  }

  /** Returns true if this type represents a class. */
  public boolean isClass() {
    return wrapper instanceof ClassTypeWrapper;
  }

  public Class<? super T> getRawClass() {
    return Cast.uncheckedCast(wrapper.getRawClass());
  }

  public Class<T> getConcreteClass() {
    return Cast.uncheckedCast(wrapper.getRawClass());
  }

  public boolean isRawClassOfParameterizedType() {
    return wrapper instanceof ClassTypeWrapper
        && ((ClassTypeWrapper) wrapper).unwrap().getTypeParameters().length > 0;
  }

  public static ModelType<Object> untyped() {
    return UNTYPED;
  }

  public boolean isParameterized() {
    return wrapper instanceof ParameterizedTypeWrapper;
  }

  public List<ModelType<?>> getTypeVariables() {
    if (isParameterized()) {
      TypeWrapper[] typeArguments = ((ParameterizedTypeWrapper) wrapper).getActualTypeArguments();
      ImmutableList.Builder<ModelType<?>> builder = ImmutableList.builder();
      for (TypeWrapper typeArgument : typeArguments) {
        builder.add(Simple.typed(typeArgument));
      }
      return builder.build();
    } else {
      return Collections.emptyList();
    }
  }

  /**
   * Casts this {@code ModelType} object to represent a subclass of the class represented by the
   * specified class object. Checks that the cast is valid, and throws a {@code ClassCastException}
   * if it is not. If this method succeeds, it always returns a reference to this {@code ModelType}
   * object.
   *
   * @throws ClassCastException if this cannot be cast as the subtype of the given type.
   * @throws IllegalStateException if this is a wildcard.
   * @throws IllegalArgumentException if the given type is a wildcard.
   */
  public <U> ModelType<? extends U> asSubtype(ModelType<U> modelType) {
    if (isWildcard()) {
      throw new IllegalStateException(this + " is a wildcard type");
    }
    if (modelType.isWildcard()) {
      throw new IllegalArgumentException(modelType + " is a wildcard type");
    }

    if (modelType.getRawClass().isAssignableFrom(getRawClass())) {
      return Cast.uncheckedCast(this);
    } else {
      throw new ClassCastException(
          String.format("'%s' cannot be cast as a subtype of '%s'", this, modelType));
    }
  }

  public boolean isAssignableFrom(ModelType<?> modelType) {
    return modelType == this || wrapper.isAssignableFrom(modelType.wrapper);
  }

  public boolean isAnnotationPresent(Class<? extends Annotation> annotation) {
    return getRawClass().isAnnotationPresent(annotation);
  }

  public boolean isWildcard() {
    return getWildcardType() != null;
  }

  @Nullable
  public ModelType<?> getUpperBound() {
    WildcardWrapper wildcardType = getWildcardType();
    if (wildcardType == null) {
      return null;
    } else {
      ModelType<?> upperBound = Simple.typed(wildcardType.getUpperBound());
      if (upperBound.equals(UNTYPED)) {
        return null;
      }
      return upperBound;
    }
  }

  @Nullable
  public ModelType<?> getLowerBound() {
    WildcardWrapper wildcardType = getWildcardType();
    if (wildcardType == null) {
      return null;
    } else {
      TypeWrapper lowerBound = wildcardType.getLowerBound();
      if (lowerBound == null) {
        return null;
      }
      return Simple.typed(lowerBound);
    }
  }

  private WildcardWrapper getWildcardType() {
    if (wrapper instanceof WildcardWrapper) {
      return (WildcardWrapper) wrapper;
    }
    return null;
  }

  public boolean isHasWildcardTypeVariables() {
    if (isWildcard()) {
      return true;
    } else if (isParameterized()) {
      for (ModelType<?> typeVariable : getTypeVariables()) {
        if (typeVariable.isHasWildcardTypeVariables()) {
          return true;
        }
      }
    }

    return false;
  }

  public List<Class<?>> getAllClasses() {
    ImmutableList.Builder<Class<?>> builder = ImmutableList.builder();
    wrapper.collectClasses(builder);
    return builder.build();
  }

  public String getName() {
    return wrapper.getRepresentation(true);
  }

  /** Returns a human-readable name for the type. */
  public String getDisplayName() {
    return wrapper.getRepresentation(false);
  }

  public String toString() {
    return wrapper.getRepresentation(true);
  }

  @Override
  public boolean equals(Object o) {
    if (this == o) {
      return true;
    }
    if (!(o instanceof ModelType)) {
      return false;
    }

    ModelType<?> modelType = (ModelType<?>) o;

    return wrapper.equals(modelType.wrapper);
  }

  @Override
  public int hashCode() {
    return wrapper.hashCode();
  }

  public abstract static class Builder<T> {
    private ParameterizedTypeWrapper wrapper;

    public Builder() {
      wrapper = (ParameterizedTypeWrapper) wrap(new TypeToken<T>(getClass()) {}.getType());
    }

    @SuppressWarnings("unchecked")
    public <I> Builder<T> where(Parameter<I> parameter, ModelType<I> type) {
      wrapper = wrapper.substitute(parameter.typeVariable, type.wrapper);
      return this;
    }

    public ModelType<T> build() {
      return Simple.typed((TypeWrapper) wrapper);
    }
  }

  @SuppressWarnings("UnusedDeclaration")
  public abstract static class Parameter<T> {
    private final TypeVariable<?> typeVariable;

    public Parameter() {
      Type type = new TypeToken<T>(getClass()) {}.getType();
      if (type instanceof TypeVariable<?>) {
        this.typeVariable = (TypeVariable<?>) type;
      } else {
        throw new IllegalStateException("T for Parameter<T> MUST be a type variable");
      }
    }
  }

  private static final TypeWrapper[] EMPTY_TYPE_WRAPPER_ARRAY = new TypeWrapper[0];

  @Nullable
  private static TypeWrapper wrap(Type type) {
    if (type == null) {
      return null;
    } else if (type instanceof Class) {
      return new ClassTypeWrapper((Class<?>) type);
    } else if (type instanceof ParameterizedType) {
      ParameterizedType parameterizedType = (ParameterizedType) type;
      return new ParameterizedTypeWrapper(
          toWrappers(parameterizedType.getActualTypeArguments()),
          (ClassTypeWrapper) wrap(parameterizedType.getRawType()),
          wrap(parameterizedType.getOwnerType()));
    } else if (type instanceof WildcardType) {
      WildcardType wildcardType = (WildcardType) type;
      return new WildcardTypeWrapper(
          toWrappers(wildcardType.getUpperBounds()),
          toWrappers(wildcardType.getLowerBounds()),
          type.hashCode());
    } else if (type instanceof TypeVariable) {
      TypeVariable<?> typeVariable = (TypeVariable<?>) type;
      return new TypeVariableTypeWrapper(
          typeVariable.getName(), toWrappers(typeVariable.getBounds()), type.hashCode());
    } else if (type instanceof GenericArrayType) {
      GenericArrayType genericArrayType = (GenericArrayType) type;
      return new GenericArrayTypeWrapper(
          wrap(genericArrayType.getGenericComponentType()), type.hashCode());
    } else {
      throw new IllegalArgumentException("cannot wrap type of type " + type.getClass());
    }
  }

  static TypeWrapper[] toWrappers(Type[] types) {
    if (types.length == 0) {
      return EMPTY_TYPE_WRAPPER_ARRAY;
    } else {
      TypeWrapper[] wrappers = new TypeWrapper[types.length];
      int i = 0;
      for (Type type : types) {
        wrappers[i++] = wrap(type);
      }
      return wrappers;
    }
  }

  private static class Simple<T> extends ModelType<T> {
    public static <T> ModelType<T> typed(Type type) {
      return new Simple<T>(type);
    }

    public static <T> ModelType<T> typed(TypeWrapper wrapper) {
      return new Simple<T>(wrapper);
    }

    public Simple(Type type) {
      super(wrap(type));
    }

    public Simple(TypeWrapper type) {
      super(type);
    }
  }
}
Exemplo n.º 29
0
  /**
   * Generates an implementation of the given managed type.
   *
   * <p>The generated class will implement/extend the managed type and will:
   *
   * <ul>
   *   <li>provide implementations for abstract getters and setters that delegate to model nodes
   *   <li>provide a `toString()` implementation
   *   <li>mix-in implementation of {@link ManagedInstance}
   *   <li>provide a constructor that accepts a {@link ModelElementState}, which will be used to
   *       implement the above.
   * </ul>
   *
   * In case a delegate schema is supplied, the generated class will also have:
   *
   * <ul>
   *   <li>a constructor that also takes a delegate instance
   *   <li>methods that call through to the delegate instance
   * </ul>
   */
  public <T, M extends T, D extends T> Class<? extends M> generate(
      StructSchema<M> viewSchema, @Nullable StructSchema<D> delegateSchema) {
    if (delegateSchema != null
        && Modifier.isAbstract(delegateSchema.getType().getConcreteClass().getModifiers())) {
      throw new IllegalArgumentException("Delegate type must be null or a non-abstract type");
    }
    ClassWriter visitor = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);

    ModelType<M> viewType = viewSchema.getType();

    StringBuilder generatedTypeNameBuilder = new StringBuilder(viewType.getName());
    if (delegateSchema != null) {
      generatedTypeNameBuilder
          .append("$BackedBy_")
          .append(delegateSchema.getType().getName().replaceAll("\\.", "_"));
    } else {
      generatedTypeNameBuilder.append("$Impl");
    }

    String generatedTypeName = generatedTypeNameBuilder.toString();
    Type generatedType = Type.getType("L" + generatedTypeName.replaceAll("\\.", "/") + ";");

    Class<M> viewClass = viewType.getConcreteClass();
    Class<?> superclass;
    final ImmutableSet.Builder<String> interfacesToImplement = ImmutableSet.builder();
    final ImmutableSet.Builder<Class<?>> typesToDelegate = ImmutableSet.builder();
    typesToDelegate.add(viewClass);
    interfacesToImplement.add(MANAGED_INSTANCE_TYPE);
    if (viewClass.isInterface()) {
      superclass = Object.class;
      interfacesToImplement.add(Type.getInternalName(viewClass));
    } else {
      superclass = viewClass;
    }
    // TODO:LPTR This should be removed once BinaryContainer is a ModelMap
    // We need to also implement all the interfaces of the delegate type because otherwise
    // BinaryContainer won't recognize managed binaries as BinarySpecInternal
    if (delegateSchema != null) {
      ModelSchemaUtils.walkTypeHierarchy(
          delegateSchema.getType().getConcreteClass(),
          new ModelSchemaUtils.TypeVisitor<D>() {
            @Override
            public void visitType(Class<? super D> type) {
              if (type.isInterface()) {
                typesToDelegate.add(type);
                interfacesToImplement.add(Type.getInternalName(type));
              }
            }
          });
    }

    generateProxyClass(
        visitor,
        viewSchema,
        delegateSchema,
        interfacesToImplement.build(),
        typesToDelegate.build(),
        generatedType,
        Type.getType(superclass));

    ClassLoader targetClassLoader = viewClass.getClassLoader();
    if (delegateSchema != null) {
      // TODO - remove this once the above is removed
      try {
        viewClass.getClassLoader().loadClass(delegateSchema.getType().getConcreteClass().getName());
      } catch (ClassNotFoundException e) {
        // Delegate class is not visible to managed view type -> view type is more general than
        // delegate type, so use the delegate classloader instead
        targetClassLoader = delegateSchema.getType().getConcreteClass().getClassLoader();
      }
    }

    return defineClass(visitor, targetClassLoader, generatedTypeName);
  }
 private static boolean isManagedCollection(ModelType<?> type) {
   Class<?> concreteClass = type.getConcreteClass();
   return concreteClass.equals(ModelMap.class) || concreteClass.equals(ModelSet.class);
 }