Search in sources :

Example 61 with TypeParameterElement

use of javax.lang.model.element.TypeParameterElement in project auto by google.

the class TypeVariables method canAssignStaticMethodResult.

/**
 * Tests whether a given parameter can be given to a static method like {@code
 * ImmutableMap.copyOf} to produce a value that can be assigned to the given target type.
 *
 * <p>For example, suppose we have this method in {@code ImmutableMap}:<br>
 * {@code static <K, V> ImmutableMap<K, V> copyOf(Map<? extends K, ? extends V>)}<br>
 * and we want to know if we can do this:
 *
 * <pre>
 * {@code ImmutableMap<String, Integer> actualParameter = ...;}
 * {@code ImmutableMap<String, Number> target = ImmutableMap.copyOf(actualParameter);}
 * </pre>
 *
 * We will infer {@code K=String}, {@code V=Number} based on the target type, and then rewrite the
 * formal parameter type from<br>
 * {@code Map<? extends K, ? extends V>} to<br>
 * {@code Map<? extends String, ? extends Number>}. Then we can check whether {@code
 * actualParameter} is assignable to that.
 *
 * <p>The logic makes some simplifying assumptions, which are met for the {@code copyOf} and
 * {@code of} methods that we use this for. The method must be static, it must have exactly one
 * parameter, and it must have type parameters without bounds that are the same as the type
 * parameters of its return type. We can see that these assumptions are met for the {@code
 * ImmutableMap.copyOf} example above.
 */
static boolean canAssignStaticMethodResult(ExecutableElement method, TypeMirror actualParameterType, TypeMirror targetType, Types typeUtils) {
    if (!targetType.getKind().equals(TypeKind.DECLARED) || !method.getModifiers().contains(Modifier.STATIC) || method.getParameters().size() != 1) {
        return false;
    }
    List<? extends TypeParameterElement> typeParameters = method.getTypeParameters();
    List<? extends TypeMirror> targetTypeArguments = MoreTypes.asDeclared(targetType).getTypeArguments();
    if (typeParameters.size() != targetTypeArguments.size()) {
        return false;
    }
    Map<Equivalence.Wrapper<TypeVariable>, TypeMirror> typeVariables = new LinkedHashMap<>();
    for (int i = 0; i < typeParameters.size(); i++) {
        TypeVariable v = MoreTypes.asTypeVariable(typeParameters.get(i).asType());
        typeVariables.put(MoreTypes.equivalence().wrap(v), targetTypeArguments.get(i));
    }
    Function<TypeVariable, TypeMirror> substitute = v -> typeVariables.get(MoreTypes.equivalence().wrap(v));
    TypeMirror formalParameterType = method.getParameters().get(0).asType();
    SubstitutionVisitor substitutionVisitor = new SubstitutionVisitor(substitute, typeUtils);
    TypeMirror substitutedParameterType = substitutionVisitor.visit(formalParameterType, null);
    if (substitutedParameterType.getKind().equals(TypeKind.WILDCARD)) {
        // If the target type is Optional<? extends Foo> then <T> T Optional.of(T) will give us
        // ? extends Foo here, and typeUtils.isAssignable will return false. But we can in fact
        // give a Foo as an argument, so we just replace ? extends Foo with Foo.
        WildcardType wildcard = MoreTypes.asWildcard(substitutedParameterType);
        if (wildcard.getExtendsBound() != null) {
            substitutedParameterType = wildcard.getExtendsBound();
        }
    }
    return typeUtils.isAssignable(actualParameterType, substitutedParameterType);
}
Also used : ArrayType(javax.lang.model.type.ArrayType) MoreElements(com.google.auto.common.MoreElements) SimpleTypeVisitor8(javax.lang.model.util.SimpleTypeVisitor8) MoreTypes(com.google.auto.common.MoreTypes) Equivalence(com.google.common.base.Equivalence) ImmutableMap(com.google.common.collect.ImmutableMap) Modifier(javax.lang.model.element.Modifier) Collection(java.util.Collection) ExecutableElement(javax.lang.model.element.ExecutableElement) MoreStreams.toImmutableMap(com.google.auto.common.MoreStreams.toImmutableMap) TypeElement(javax.lang.model.element.TypeElement) Types(javax.lang.model.util.Types) Function(java.util.function.Function) Elements(javax.lang.model.util.Elements) TypeParameterElement(javax.lang.model.element.TypeParameterElement) TypeKind(javax.lang.model.type.TypeKind) LinkedHashMap(java.util.LinkedHashMap) List(java.util.List) TypeMirror(javax.lang.model.type.TypeMirror) Map(java.util.Map) DeclaredType(javax.lang.model.type.DeclaredType) TypeVariable(javax.lang.model.type.TypeVariable) Preconditions(com.google.common.base.Preconditions) WildcardType(javax.lang.model.type.WildcardType) WildcardType(javax.lang.model.type.WildcardType) TypeMirror(javax.lang.model.type.TypeMirror) TypeVariable(javax.lang.model.type.TypeVariable) LinkedHashMap(java.util.LinkedHashMap)

Example 62 with TypeParameterElement

use of javax.lang.model.element.TypeParameterElement in project vertx-docgen by vert-x3.

the class Helper method toString.

/**
 * Compute the string representation of a type mirror.
 *
 * @param mirror the type mirror
 * @param buffer the buffer appended with the string representation
 */
static void toString(TypeMirror mirror, StringBuilder buffer) {
    if (mirror instanceof DeclaredType) {
        DeclaredType dt = (DeclaredType) mirror;
        TypeElement elt = (TypeElement) dt.asElement();
        buffer.append(elt.getQualifiedName().toString());
        List<? extends TypeMirror> args = dt.getTypeArguments();
        if (args.size() > 0) {
            buffer.append("<");
            for (int i = 0; i < args.size(); i++) {
                if (i > 0) {
                    buffer.append(",");
                }
                toString(args.get(i), buffer);
            }
            buffer.append(">");
        }
    } else if (mirror instanceof PrimitiveType) {
        PrimitiveType pm = (PrimitiveType) mirror;
        buffer.append(pm.getKind().name().toLowerCase());
    } else if (mirror instanceof javax.lang.model.type.WildcardType) {
        javax.lang.model.type.WildcardType wt = (javax.lang.model.type.WildcardType) mirror;
        buffer.append("?");
        if (wt.getSuperBound() != null) {
            buffer.append(" super ");
            toString(wt.getSuperBound(), buffer);
        } else if (wt.getExtendsBound() != null) {
            buffer.append(" extends ");
            toString(wt.getExtendsBound(), buffer);
        }
    } else if (mirror instanceof javax.lang.model.type.TypeVariable) {
        javax.lang.model.type.TypeVariable tv = (TypeVariable) mirror;
        TypeParameterElement elt = (TypeParameterElement) tv.asElement();
        buffer.append(elt.getSimpleName().toString());
        if (tv.getUpperBound() != null && !tv.getUpperBound().toString().equals("java.lang.Object")) {
            buffer.append(" extends ");
            toString(tv.getUpperBound(), buffer);
        } else if (tv.getLowerBound() != null && tv.getLowerBound().getKind() != TypeKind.NULL) {
            buffer.append(" super ");
            toString(tv.getUpperBound(), buffer);
        }
    } else if (mirror instanceof javax.lang.model.type.ArrayType) {
        javax.lang.model.type.ArrayType at = (ArrayType) mirror;
        toString(at.getComponentType(), buffer);
        buffer.append("[]");
    } else {
        throw new UnsupportedOperationException("todo " + mirror + " " + mirror.getKind());
    }
}
Also used : ArrayType(javax.lang.model.type.ArrayType) TypeElement(javax.lang.model.element.TypeElement) TypeParameterElement(javax.lang.model.element.TypeParameterElement) ArrayType(javax.lang.model.type.ArrayType) TypeVariable(javax.lang.model.type.TypeVariable) TypeVariable(javax.lang.model.type.TypeVariable) PrimitiveType(javax.lang.model.type.PrimitiveType) DeclaredType(javax.lang.model.type.DeclaredType)

Example 63 with TypeParameterElement

use of javax.lang.model.element.TypeParameterElement in project LoganSquare by bluelinelabs.

the class ObjectMapperInjector method getTypeSpec.

private TypeSpec getTypeSpec() {
    TypeSpec.Builder builder = TypeSpec.classBuilder(mJsonObjectHolder.injectedClassName).addModifiers(Modifier.PUBLIC, Modifier.FINAL);
    builder.addAnnotation(AnnotationSpec.builder(SuppressWarnings.class).addMember("value", "\"unsafe,unchecked\"").build());
    builder.superclass(ParameterizedTypeName.get(ClassName.get(JsonMapper.class), mJsonObjectHolder.objectTypeName));
    for (TypeParameterElement typeParameterElement : mJsonObjectHolder.typeParameters) {
        builder.addTypeVariable(TypeVariableName.get((TypeVariable) typeParameterElement.asType()));
    }
    if (mJsonObjectHolder.hasParentClass()) {
        FieldSpec.Builder parentMapperBuilder;
        if (mJsonObjectHolder.parentTypeParameters.size() == 0) {
            parentMapperBuilder = FieldSpec.builder(ParameterizedTypeName.get(ClassName.get(JsonMapper.class), mJsonObjectHolder.parentTypeName), PARENT_OBJECT_MAPPER_VARIABLE_NAME).addModifiers(Modifier.PRIVATE, Modifier.STATIC, Modifier.FINAL).initializer("$T.mapperFor($T.class)", LoganSquare.class, mJsonObjectHolder.parentTypeName);
        } else {
            parentMapperBuilder = FieldSpec.builder(ParameterizedTypeName.get(ClassName.get(JsonMapper.class), mJsonObjectHolder.getParameterizedParentTypeName()), PARENT_OBJECT_MAPPER_VARIABLE_NAME).addModifiers(Modifier.PRIVATE);
            if (mJsonObjectHolder.typeParameters.size() == 0) {
                parentMapperBuilder.initializer("$T.mapperFor(new $T<$T>() { })", LoganSquare.class, ParameterizedType.class, mJsonObjectHolder.getParameterizedParentTypeName());
            }
        }
        builder.addField(parentMapperBuilder.build());
    }
    // TypeConverters could be expensive to create, so just use one per class
    Set<ClassName> typeConvertersUsed = new HashSet<>();
    for (JsonFieldHolder fieldHolder : mJsonObjectHolder.fieldMap.values()) {
        if (fieldHolder.type instanceof TypeConverterFieldType) {
            typeConvertersUsed.add(((TypeConverterFieldType) fieldHolder.type).getTypeConverterClassName());
        }
    }
    for (ClassName typeConverter : typeConvertersUsed) {
        builder.addField(FieldSpec.builder(typeConverter, getStaticFinalTypeConverterVariableName(typeConverter)).addModifiers(Modifier.PROTECTED, Modifier.STATIC, Modifier.FINAL).initializer("new $T()", typeConverter).build());
    }
    MethodSpec.Builder constructorBuilder = MethodSpec.constructorBuilder().addModifiers(Modifier.PUBLIC);
    List<String> createdJsonMappers = new ArrayList<>();
    if (mJsonObjectHolder.typeParameters.size() > 0) {
        constructorBuilder.addParameter(ClassName.get(ParameterizedType.class), "type");
        constructorBuilder.addStatement("partialMappers.put(type, this)");
        for (TypeParameterElement typeParameterElement : mJsonObjectHolder.typeParameters) {
            final String typeName = typeParameterElement.getSimpleName().toString();
            final String typeArgumentName = typeName + "Type";
            final String jsonMapperVariableName = getJsonMapperVariableNameForTypeParameter(typeName);
            if (!createdJsonMappers.contains(jsonMapperVariableName)) {
                createdJsonMappers.add(jsonMapperVariableName);
                // Add a JsonMapper reference
                builder.addField(FieldSpec.builder(ParameterizedTypeName.get(ClassName.get(JsonMapper.class), TypeVariableName.get(typeName)), jsonMapperVariableName).addModifiers(Modifier.PRIVATE, Modifier.FINAL).build());
                constructorBuilder.addParameter(ClassName.get(ParameterizedType.class), typeArgumentName);
                constructorBuilder.addStatement("$L = $T.mapperFor($L, partialMappers)", jsonMapperVariableName, LoganSquare.class, typeArgumentName);
            }
        }
        constructorBuilder.addParameter(ParameterizedTypeName.get(ClassName.get(SimpleArrayMap.class), ClassName.get(ParameterizedType.class), ClassName.get(JsonMapper.class)), "partialMappers");
    }
    for (JsonFieldHolder jsonFieldHolder : mJsonObjectHolder.fieldMap.values()) {
        if (jsonFieldHolder.type instanceof ParameterizedTypeField) {
            final String jsonMapperVariableName = getJsonMapperVariableNameForTypeParameter(((ParameterizedTypeField) jsonFieldHolder.type).getParameterName());
            if (!createdJsonMappers.contains(jsonMapperVariableName)) {
                ParameterizedTypeName parameterizedType = ParameterizedTypeName.get(ClassName.get(JsonMapper.class), jsonFieldHolder.type.getTypeName());
                createdJsonMappers.add(jsonMapperVariableName);
                builder.addField(FieldSpec.builder(parameterizedType, jsonMapperVariableName).addModifiers(Modifier.PRIVATE, Modifier.FINAL).build());
                String typeName = jsonMapperVariableName + "Type";
                constructorBuilder.addStatement("$T $L = new $T<$T>() { }", ParameterizedType.class, typeName, ParameterizedType.class, jsonFieldHolder.type.getTypeName());
                if (mJsonObjectHolder.typeParameters.size() > 0) {
                    constructorBuilder.beginControlFlow("if ($L.equals(type))", typeName);
                    constructorBuilder.addStatement("$L = ($T)this", jsonMapperVariableName, JsonMapper.class);
                    constructorBuilder.nextControlFlow("else");
                    constructorBuilder.addStatement("$L = $T.mapperFor($L, partialMappers)", jsonMapperVariableName, LoganSquare.class, typeName);
                    constructorBuilder.endControlFlow();
                } else {
                    constructorBuilder.addStatement("$L = $T.mapperFor($L)", jsonMapperVariableName, LoganSquare.class, typeName);
                }
            }
        }
    }
    if (createdJsonMappers.size() > 0) {
        if (mJsonObjectHolder.hasParentClass()) {
            constructorBuilder.addStatement("$L = $T.mapperFor(new $T<$T>() { })", PARENT_OBJECT_MAPPER_VARIABLE_NAME, LoganSquare.class, ParameterizedType.class, mJsonObjectHolder.getParameterizedParentTypeName());
        }
        builder.addMethod(constructorBuilder.build());
    }
    builder.addMethod(getParseMethod());
    builder.addMethod(getParseFieldMethod());
    builder.addMethod(getSerializeMethod());
    addUsedJsonMapperVariables(builder);
    addUsedTypeConverterMethods(builder);
    return builder.build();
}
Also used : MethodSpec(com.squareup.javapoet.MethodSpec) ParameterizedTypeField(com.bluelinelabs.logansquare.processor.type.field.ParameterizedTypeField) ArrayList(java.util.ArrayList) FieldSpec(com.squareup.javapoet.FieldSpec) TypeParameterElement(javax.lang.model.element.TypeParameterElement) JsonMapper(com.bluelinelabs.logansquare.JsonMapper) ParameterizedType(com.bluelinelabs.logansquare.ParameterizedType) TypeConverterFieldType(com.bluelinelabs.logansquare.processor.type.field.TypeConverterFieldType) TypeVariable(javax.lang.model.type.TypeVariable) LoganSquare(com.bluelinelabs.logansquare.LoganSquare) ClassName(com.squareup.javapoet.ClassName) TypeSpec(com.squareup.javapoet.TypeSpec) HashSet(java.util.HashSet) ParameterizedTypeName(com.squareup.javapoet.ParameterizedTypeName)

Example 64 with TypeParameterElement

use of javax.lang.model.element.TypeParameterElement in project glide by bumptech.

the class RequestOptionsGenerator method generateStaticMethodEquivalentForRequestOptionsStaticMethod.

private MethodAndStaticVar generateStaticMethodEquivalentForRequestOptionsStaticMethod(ExecutableElement staticMethod) {
    boolean memoize = memoizeStaticMethodFromArguments(staticMethod);
    String staticMethodName = staticMethod.getSimpleName().toString();
    String equivalentInstanceMethodName = getInstanceMethodNameFromStaticMethodName(staticMethodName);
    MethodSpec.Builder methodSpecBuilder = MethodSpec.methodBuilder(staticMethodName).addModifiers(Modifier.PUBLIC, Modifier.STATIC).addJavadoc(processorUtil.generateSeeMethodJavadoc(staticMethod)).returns(glideOptionsName);
    StringBuilder createNewOptionAndCall = createNewOptionAndCall(memoize, methodSpecBuilder, "new $T().$N(", ProcessorUtil.getParameters(staticMethod));
    FieldSpec requiredStaticField = null;
    if (memoize) {
        // Generates code that looks like:
        // if (GlideOptions.<methodName> == null) {
        // GlideOptions.<methodName> = new GlideOptions().<methodName>().autoClone()
        // }
        // Mix in an incrementing unique id to handle method overloading.
        String staticVariableName = staticMethodName + nextStaticFieldUniqueId++;
        requiredStaticField = FieldSpec.builder(glideOptionsName, staticVariableName).addModifiers(Modifier.PRIVATE, Modifier.STATIC).build();
        methodSpecBuilder.beginControlFlow("if ($T.$N == null)", glideOptionsName, staticVariableName).addStatement("$T.$N =\n" + createNewOptionAndCall + ".$N", glideOptionsName, staticVariableName, glideOptionsName, equivalentInstanceMethodName, "autoClone()").endControlFlow().addStatement("return $T.$N", glideOptionsName, staticVariableName);
    } else {
        // Generates code that looks like:
        // return new GlideOptions().<methodName>()
        methodSpecBuilder.addStatement("return " + createNewOptionAndCall, glideOptionsName, equivalentInstanceMethodName);
    }
    List<? extends TypeParameterElement> typeParameters = staticMethod.getTypeParameters();
    for (TypeParameterElement typeParameterElement : typeParameters) {
        methodSpecBuilder.addTypeVariable(TypeVariableName.get(typeParameterElement.getSimpleName().toString()));
    }
    methodSpecBuilder.addAnnotation(AnnotationSpec.builder(CHECK_RESULT_CLASS_NAME).build()).addAnnotation(nonNull());
    return new MethodAndStaticVar(methodSpecBuilder.build(), requiredStaticField);
}
Also used : MethodSpec(com.squareup.javapoet.MethodSpec) FieldSpec(com.squareup.javapoet.FieldSpec) TypeParameterElement(javax.lang.model.element.TypeParameterElement)

Example 65 with TypeParameterElement

use of javax.lang.model.element.TypeParameterElement in project glide by bumptech.

the class ProcessorUtil method overriding.

static MethodSpec.Builder overriding(ExecutableElement method) {
    String methodName = method.getSimpleName().toString();
    MethodSpec.Builder builder = MethodSpec.methodBuilder(methodName).addAnnotation(Override.class);
    Set<Modifier> modifiers = method.getModifiers();
    modifiers = new LinkedHashSet<>(modifiers);
    modifiers.remove(Modifier.ABSTRACT);
    Modifier defaultModifier = null;
    // Modifier.DEFAULT doesn't exist until Java 8.
    try {
        defaultModifier = Modifier.valueOf("DEFAULT");
    } catch (IllegalArgumentException e) {
    // Ignored.
    }
    modifiers.remove(defaultModifier);
    builder = builder.addModifiers(modifiers);
    for (TypeParameterElement typeParameterElement : method.getTypeParameters()) {
        TypeVariable var = (TypeVariable) typeParameterElement.asType();
        builder = builder.addTypeVariable(TypeVariableName.get(var));
    }
    builder = builder.returns(TypeName.get(method.getReturnType())).addParameters(getParameters(method)).varargs(method.isVarArgs());
    for (TypeMirror thrownType : method.getThrownTypes()) {
        builder = builder.addException(TypeName.get(thrownType));
    }
    return builder;
}
Also used : MethodSpec(com.squareup.javapoet.MethodSpec) TypeVariable(javax.lang.model.type.TypeVariable) TypeMirror(javax.lang.model.type.TypeMirror) Modifier(javax.lang.model.element.Modifier) TypeParameterElement(javax.lang.model.element.TypeParameterElement)

Aggregations

TypeParameterElement (javax.lang.model.element.TypeParameterElement)66 TypeElement (javax.lang.model.element.TypeElement)30 TypeMirror (javax.lang.model.type.TypeMirror)26 Test (org.junit.Test)18 ExecutableElement (javax.lang.model.element.ExecutableElement)13 TypeVariable (javax.lang.model.type.TypeVariable)13 Element (javax.lang.model.element.Element)10 VariableElement (javax.lang.model.element.VariableElement)9 ArrayList (java.util.ArrayList)7 LinkedHashMap (java.util.LinkedHashMap)7 List (java.util.List)7 DeclaredType (javax.lang.model.type.DeclaredType)7 MethodSpec (com.squareup.javapoet.MethodSpec)6 Map (java.util.Map)6 FieldSpec (com.squareup.javapoet.FieldSpec)5 HashSet (java.util.HashSet)4 Modifier (javax.lang.model.element.Modifier)4 ArrayType (javax.lang.model.type.ArrayType)4 Types (javax.lang.model.util.Types)4 MoreElements (com.google.auto.common.MoreElements)3