359 lines
13 KiB
Java
359 lines
13 KiB
Java
/*
|
|
* Copyright (C) 2014 The Dagger 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 dagger.internal.codegen.binding;
|
|
|
|
import com.google.common.base.Joiner;
|
|
import com.google.common.collect.ImmutableMap;
|
|
import dagger.internal.codegen.base.ComponentAnnotation;
|
|
import java.util.Set;
|
|
import java.util.function.Function;
|
|
import java.util.function.UnaryOperator;
|
|
import javax.lang.model.element.ExecutableElement;
|
|
import javax.lang.model.element.TypeElement;
|
|
import javax.lang.model.type.TypeMirror;
|
|
|
|
/** The collection of error messages to be reported back to users. */
|
|
public final class ErrorMessages {
|
|
|
|
private static final UnaryOperator<String> PRODUCTION =
|
|
s ->
|
|
s.replace("component", "production component")
|
|
.replace("Component", "ProductionComponent");
|
|
|
|
private static final UnaryOperator<String> SUBCOMPONENT =
|
|
s -> s.replace("component", "subcomponent").replace("Component", "Subcomponent");
|
|
|
|
private static final UnaryOperator<String> FACTORY = s -> s.replace("Builder", "Factory");
|
|
|
|
private static final ImmutableMap<ComponentKind, Function<String, String>>
|
|
COMPONENT_TRANSFORMATIONS =
|
|
ImmutableMap.of(
|
|
ComponentKind.COMPONENT, UnaryOperator.identity(),
|
|
ComponentKind.SUBCOMPONENT, SUBCOMPONENT,
|
|
ComponentKind.PRODUCTION_COMPONENT, PRODUCTION,
|
|
ComponentKind.PRODUCTION_SUBCOMPONENT, PRODUCTION.andThen(SUBCOMPONENT));
|
|
|
|
public static ComponentMessages componentMessagesFor(ComponentKind componentKind) {
|
|
return new ComponentMessages(COMPONENT_TRANSFORMATIONS.get(componentKind));
|
|
}
|
|
|
|
public static ComponentMessages componentMessagesFor(ComponentAnnotation componentAnnotation) {
|
|
return new ComponentMessages(
|
|
transformation(componentAnnotation.isProduction(), componentAnnotation.isSubcomponent()));
|
|
}
|
|
|
|
public static ComponentCreatorMessages creatorMessagesFor(
|
|
ComponentCreatorAnnotation creatorAnnotation) {
|
|
Function<String, String> transformation =
|
|
transformation(
|
|
creatorAnnotation.isProductionCreatorAnnotation(),
|
|
creatorAnnotation.isSubcomponentCreatorAnnotation());
|
|
switch (creatorAnnotation.creatorKind()) {
|
|
case BUILDER:
|
|
return new BuilderMessages(transformation);
|
|
case FACTORY:
|
|
return new FactoryMessages(transformation);
|
|
}
|
|
throw new AssertionError(creatorAnnotation);
|
|
}
|
|
|
|
private static Function<String, String> transformation(
|
|
boolean isProduction, boolean isSubcomponent) {
|
|
Function<String, String> transformation = isProduction ? PRODUCTION : UnaryOperator.identity();
|
|
return isSubcomponent ? transformation.andThen(SUBCOMPONENT) : transformation;
|
|
}
|
|
|
|
private abstract static class Messages {
|
|
private final Function<String, String> transformation;
|
|
|
|
Messages(Function<String, String> transformation) {
|
|
this.transformation = transformation;
|
|
}
|
|
|
|
protected final String process(String s) {
|
|
return transformation.apply(s);
|
|
}
|
|
}
|
|
|
|
/** Errors for components. */
|
|
public static final class ComponentMessages extends Messages {
|
|
ComponentMessages(Function<String, String> transformation) {
|
|
super(transformation);
|
|
}
|
|
|
|
public final String moreThanOne() {
|
|
return process("@Component has more than one @Component.Builder or @Component.Factory: %s");
|
|
}
|
|
}
|
|
|
|
/** Errors for component creators. */
|
|
public abstract static class ComponentCreatorMessages extends Messages {
|
|
ComponentCreatorMessages(Function<String, String> transformation) {
|
|
super(transformation);
|
|
}
|
|
|
|
public static String builderMethodRequiresNoArgs() {
|
|
return "Methods returning a @Component.Builder must have no arguments";
|
|
}
|
|
|
|
public static String moreThanOneRefToSubcomponent() {
|
|
return "Only one method can create a given subcomponent. %s is created by: %s";
|
|
}
|
|
|
|
public final String invalidConstructor() {
|
|
return process("@Component.Builder classes must have exactly one constructor,"
|
|
+ " and it must not be private or have any parameters");
|
|
}
|
|
|
|
public final String generics() {
|
|
return process("@Component.Builder types must not have any generic types");
|
|
}
|
|
|
|
public final String mustBeInComponent() {
|
|
return process("@Component.Builder types must be nested within a @Component");
|
|
}
|
|
|
|
public final String mustBeClassOrInterface() {
|
|
return process("@Component.Builder types must be abstract classes or interfaces");
|
|
}
|
|
|
|
public final String isPrivate() {
|
|
return process("@Component.Builder types must not be private");
|
|
}
|
|
|
|
public final String mustBeStatic() {
|
|
return process("@Component.Builder types must be static");
|
|
}
|
|
|
|
public final String mustBeAbstract() {
|
|
return process("@Component.Builder types must be abstract");
|
|
}
|
|
|
|
public abstract String missingFactoryMethod();
|
|
|
|
public abstract String multipleSettersForModuleOrDependencyType();
|
|
|
|
public abstract String extraSetters();
|
|
|
|
public abstract String missingSetters();
|
|
|
|
public abstract String twoFactoryMethods();
|
|
|
|
public abstract String inheritedTwoFactoryMethods();
|
|
|
|
public abstract String factoryMethodMustReturnComponentType();
|
|
|
|
public final String inheritedFactoryMethodMustReturnComponentType() {
|
|
return factoryMethodMustReturnComponentType() + ". Inherited method: %s";
|
|
}
|
|
|
|
public abstract String factoryMethodMayNotBeAnnotatedWithBindsInstance();
|
|
|
|
public final String inheritedFactoryMethodMayNotBeAnnotatedWithBindsInstance() {
|
|
return factoryMethodMayNotBeAnnotatedWithBindsInstance() + ". Inherited method: %s";
|
|
}
|
|
|
|
public final String setterMethodsMustTakeOneArg() {
|
|
return process("@Component.Builder methods must not have more than one argument");
|
|
}
|
|
|
|
public final String inheritedSetterMethodsMustTakeOneArg() {
|
|
return setterMethodsMustTakeOneArg() + ". Inherited method: %s";
|
|
}
|
|
|
|
public final String setterMethodsMustReturnVoidOrBuilder() {
|
|
return process("@Component.Builder setter methods must return void, the builder,"
|
|
+ " or a supertype of the builder");
|
|
}
|
|
|
|
public final String inheritedSetterMethodsMustReturnVoidOrBuilder() {
|
|
return setterMethodsMustReturnVoidOrBuilder() + ". Inherited method: %s";
|
|
}
|
|
|
|
public final String methodsMayNotHaveTypeParameters() {
|
|
return process("@Component.Builder methods must not have type parameters");
|
|
}
|
|
|
|
public final String inheritedMethodsMayNotHaveTypeParameters() {
|
|
return methodsMayNotHaveTypeParameters() + ". Inherited method: %s";
|
|
}
|
|
|
|
public abstract String nonBindsInstanceParametersMayNotBePrimitives();
|
|
|
|
public final String inheritedNonBindsInstanceParametersMayNotBePrimitives() {
|
|
return nonBindsInstanceParametersMayNotBePrimitives() + ". Inherited method: %s";
|
|
}
|
|
|
|
public final String factoryMethodReturnsSupertypeWithMissingMethods(
|
|
TypeElement component,
|
|
TypeElement componentBuilder,
|
|
TypeMirror returnType,
|
|
ExecutableElement buildMethod,
|
|
Set<ExecutableElement> additionalMethods) {
|
|
return String.format(
|
|
"%1$s.%2$s() returns %3$s, but %4$s declares additional component method(s): %5$s. In "
|
|
+ "order to provide type-safe access to these methods, override %2$s() to return "
|
|
+ "%4$s",
|
|
componentBuilder.getQualifiedName(),
|
|
buildMethod.getSimpleName(),
|
|
returnType,
|
|
component.getQualifiedName(),
|
|
Joiner.on(", ").join(additionalMethods));
|
|
}
|
|
|
|
public final String bindsInstanceNotAllowedOnBothSetterMethodAndParameter() {
|
|
return process("@Component.Builder setter methods may not have @BindsInstance on both the "
|
|
+ "method and its parameter; choose one or the other");
|
|
}
|
|
|
|
public final String inheritedBindsInstanceNotAllowedOnBothSetterMethodAndParameter() {
|
|
return bindsInstanceNotAllowedOnBothSetterMethodAndParameter() + ". Inherited method: %s";
|
|
}
|
|
}
|
|
|
|
private static final class BuilderMessages extends ComponentCreatorMessages {
|
|
BuilderMessages(Function<String, String> transformation) {
|
|
super(transformation);
|
|
}
|
|
|
|
@Override
|
|
public String missingFactoryMethod() {
|
|
return process(
|
|
"@Component.Builder types must have exactly one no-args method that "
|
|
+ " returns the @Component type");
|
|
}
|
|
|
|
@Override
|
|
public String multipleSettersForModuleOrDependencyType() {
|
|
return process(
|
|
"@Component.Builder types must not have more than one setter method per module or "
|
|
+ "dependency, but %s is set by %s");
|
|
}
|
|
|
|
@Override
|
|
public String extraSetters() {
|
|
return process(
|
|
"@Component.Builder has setters for modules or components that aren't required: %s");
|
|
}
|
|
|
|
@Override
|
|
public String missingSetters() {
|
|
return process(
|
|
"@Component.Builder is missing setters for required modules or components: %s");
|
|
}
|
|
|
|
@Override
|
|
public String twoFactoryMethods() {
|
|
return process(
|
|
"@Component.Builder types must have exactly one zero-arg method, and that"
|
|
+ " method must return the @Component type. Already found: %s");
|
|
}
|
|
|
|
@Override
|
|
public String inheritedTwoFactoryMethods() {
|
|
return process(
|
|
"@Component.Builder types must have exactly one zero-arg method, and that"
|
|
+ " method must return the @Component type. Found %s and %s");
|
|
}
|
|
|
|
@Override
|
|
public String factoryMethodMustReturnComponentType() {
|
|
return process(
|
|
"@Component.Builder methods that have no arguments must return the @Component type or a "
|
|
+ "supertype of the @Component");
|
|
}
|
|
|
|
@Override
|
|
public String factoryMethodMayNotBeAnnotatedWithBindsInstance() {
|
|
return process(
|
|
"@Component.Builder no-arg build methods may not be annotated with @BindsInstance");
|
|
}
|
|
|
|
@Override
|
|
public String nonBindsInstanceParametersMayNotBePrimitives() {
|
|
return process(
|
|
"@Component.Builder methods that are not annotated with @BindsInstance "
|
|
+ "must take either a module or a component dependency, not a primitive");
|
|
}
|
|
}
|
|
|
|
private static final class FactoryMessages extends ComponentCreatorMessages {
|
|
FactoryMessages(Function<String, String> transformation) {
|
|
super(transformation.andThen(FACTORY));
|
|
}
|
|
|
|
@Override
|
|
public String missingFactoryMethod() {
|
|
return process(
|
|
"@Component.Factory types must have exactly one method that "
|
|
+ "returns the @Component type");
|
|
}
|
|
|
|
@Override
|
|
public String multipleSettersForModuleOrDependencyType() {
|
|
return process(
|
|
"@Component.Factory methods must not have more than one parameter per module or "
|
|
+ "dependency, but %s is set by %s");
|
|
}
|
|
|
|
@Override
|
|
public String extraSetters() {
|
|
return process(
|
|
"@Component.Factory method has parameters for modules or components that aren't "
|
|
+ "required: %s");
|
|
}
|
|
|
|
@Override
|
|
public String missingSetters() {
|
|
return process(
|
|
"@Component.Factory method is missing parameters for required modules or components: %s");
|
|
}
|
|
|
|
@Override
|
|
public String twoFactoryMethods() {
|
|
return process(
|
|
"@Component.Factory types must have exactly one abstract method. Already found: %s");
|
|
}
|
|
|
|
@Override
|
|
public String inheritedTwoFactoryMethods() {
|
|
return twoFactoryMethods();
|
|
}
|
|
|
|
@Override
|
|
public String factoryMethodMustReturnComponentType() {
|
|
return process(
|
|
"@Component.Factory abstract methods must return the @Component type or a "
|
|
+ "supertype of the @Component");
|
|
}
|
|
|
|
@Override
|
|
public String factoryMethodMayNotBeAnnotatedWithBindsInstance() {
|
|
return process("@Component.Factory method may not be annotated with @BindsInstance");
|
|
}
|
|
|
|
@Override
|
|
public String nonBindsInstanceParametersMayNotBePrimitives() {
|
|
return process(
|
|
"@Component.Factory method parameters that are not annotated with @BindsInstance "
|
|
+ "must be either a module or a component dependency, not a primitive");
|
|
}
|
|
}
|
|
|
|
private ErrorMessages() {}
|
|
}
|