/* * Copyright 2014 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.gradle.platform.base.internal.registry; import org.gradle.model.ModelMap; import org.gradle.model.internal.core.ModelReference; import org.gradle.model.internal.inspect.AbstractAnnotationDrivenModelRuleExtractor; import org.gradle.model.internal.inspect.MethodRuleDefinition; import org.gradle.model.internal.inspect.RuleSourceValidationProblemCollector; import org.gradle.model.internal.type.ModelType; import java.lang.annotation.Annotation; import java.util.HashMap; import java.util.List; public abstract class AbstractAnnotationDrivenComponentModelRuleExtractor<T extends Annotation> extends AbstractAnnotationDrivenModelRuleExtractor<T> { protected <V> void visitSubject(RuleMethodDataCollector dataCollector, MethodRuleDefinition<?, ?> ruleDefinition, ModelType<V> typeParameter, RuleSourceValidationProblemCollector problems) { if (ruleDefinition.getReferences().size() == 0) { problems.add(ruleDefinition, "A method " + getDescription() + " must have at least two parameters."); return; } ModelType<?> subjectType = ruleDefinition.getSubjectReference().getType(); if (!isModelMap(subjectType)) { problems.add(ruleDefinition, String.format("The first parameter of a method %s must be of type %s.", getDescription(), ModelMap.class.getName())); return; } List<ModelType<?>> typeVariables = subjectType.getTypeVariables(); if (typeVariables.size() != 1) { problems.add(ruleDefinition, String.format("Parameter of type %s must declare a type parameter extending %s.", ModelMap.class.getSimpleName(), typeParameter.getDisplayName())); return; } ModelType<?> elementType = typeVariables.get(0); if (elementType.isWildcard()) { problems.add(ruleDefinition, String.format("%s type %s cannot be a wildcard type (i.e. cannot use ? super, ? extends etc.).", typeParameter.getDisplayName(), elementType.getDisplayName())); return; } dataCollector.parameterTypes.put(typeParameter, elementType); } private boolean isModelMap(ModelType<?> modelType) { return ModelType.of(ModelMap.class).isAssignableFrom(modelType); } protected class RuleMethodDataCollector { private HashMap<ModelType<?>, ModelType<?>> parameterTypes = new HashMap<ModelType<?>, ModelType<?>>(); @SuppressWarnings("unchecked") public <S, R extends S> ModelType<R> getParameterType(ModelType<S> baseClass) { return (ModelType<R>) parameterTypes.get(baseClass); } public <S> void put(ModelType<S> baseClass, ModelType<? extends S> concreteClass) { parameterTypes.put(baseClass, concreteClass); } } protected <S> void visitDependency(RuleMethodDataCollector dataCollector, MethodRuleDefinition<?, ?> ruleDefinition, ModelType<S> expectedDependency, RuleSourceValidationProblemCollector problems) { if (ruleDefinition.getReferences().isEmpty() && problems.hasProblems()) { return; } List<ModelReference<?>> references = ruleDefinition.getReferences(); ModelType<? extends S> dependency = null; for (ModelReference<?> reference : references) { if (expectedDependency.isAssignableFrom(reference.getType())) { if (dependency != null) { problems.add(ruleDefinition, String.format("A method %s must have one parameter extending %s. Found multiple parameter extending %s.", getDescription(), expectedDependency.getDisplayName(), expectedDependency.getDisplayName())); return; } dependency = reference.getType().asSubtype(expectedDependency); } } if (dependency == null) { problems.add(ruleDefinition, String.format("A method %s must have one parameter extending %s. Found no parameter extending %s.", getDescription(), expectedDependency.getDisplayName(), expectedDependency.getDisplayName())); return; } dataCollector.put(expectedDependency, dependency); } }