Search in sources :

Example 1 with AutoMatter

use of io.norberg.automatter.AutoMatter in project auto-matter by danielnorberg.

the class AutoMatterProcessor method process.

@Override
public boolean process(final Set<? extends TypeElement> annotations, final RoundEnvironment env) {
    final Set<TypeElement> elements = new LinkedHashSet<>();
    // Enqueue new elements for processing
    env.getElementsAnnotatedWith(AutoMatter.class).stream().filter(e -> e instanceof TypeElement).forEach(e -> elements.add((TypeElement) e));
    // Enqueue deferred elements for processing
    final List<Name> previousDeferredTypes = new ArrayList<>(deferredTypes);
    deferredTypes.clear();
    for (Name deferredType : previousDeferredTypes) {
        final TypeElement deferredTypeElement = processingEnv.getElementUtils().getTypeElement(deferredType);
        if (deferredTypeElement == null) {
            deferredTypes.add(deferredType);
        } else {
            elements.add(deferredTypeElement);
        }
    }
    // Process elements and generate files
    for (TypeElement element : elements) {
        try {
            final Descriptor descriptor = process(element);
            processedTypes.put(element.getQualifiedName(), descriptor);
        } catch (UnresolvedTypeException e) {
            // Encountered an unresolved type while processing this type, defer it for a
            // later processing in hope that the type can be resolved in a later round.
            deferredTypes.add(element.getQualifiedName());
        } catch (AutoMatterProcessorException e) {
            e.print(messager);
        } catch (Exception e) {
            messager.printMessage(ERROR, e.getMessage());
        }
    }
    if (env.processingOver()) {
        // This was the last round, complain if some types failed due to unresolved types
        for (Name deferredType : deferredTypes) {
            final TypeElement deferredTypeElement = processingEnv.getElementUtils().getTypeElement(deferredType);
            messager.printMessage(ERROR, "Failed to generate @AutoMatter builder for " + deferredType + " because some fields have unresolved types", deferredTypeElement);
        }
        // Perform validation that can only be done after processing has been completed
        for (Descriptor descriptor : processedTypes.values()) {
            try {
                validate(descriptor);
            } catch (AutoMatterProcessorException e) {
                e.print(messager);
            } catch (Exception e) {
                messager.printMessage(ERROR, e.getMessage());
            }
        }
    }
    return false;
}
Also used : LinkedHashSet(java.util.LinkedHashSet) DECLARED(javax.lang.model.type.TypeKind.DECLARED) Arrays(java.util.Arrays) AbstractProcessor(javax.annotation.processing.AbstractProcessor) ClassName(com.squareup.javapoet.ClassName) TypeElement(javax.lang.model.element.TypeElement) ERROR(javax.tools.Diagnostic.Kind.ERROR) Elements(javax.lang.model.util.Elements) FINAL(javax.lang.model.element.Modifier.FINAL) Map(java.util.Map) Collectors.toSet(java.util.stream.Collectors.toSet) Messager(javax.annotation.processing.Messager) DOUBLE(javax.lang.model.type.TypeKind.DOUBLE) ParameterSpec(com.squareup.javapoet.ParameterSpec) Collection(java.util.Collection) Set(java.util.Set) Element(javax.lang.model.element.Element) Processor(javax.annotation.processing.Processor) Types(javax.lang.model.util.Types) Collectors(java.util.stream.Collectors) JavaFile(com.squareup.javapoet.JavaFile) SourceVersion(javax.lang.model.SourceVersion) List(java.util.List) Stream(java.util.stream.Stream) Filer(javax.annotation.processing.Filer) TypeName(com.squareup.javapoet.TypeName) AutoMatter(io.norberg.automatter.AutoMatter) FieldSpec(com.squareup.javapoet.FieldSpec) DEFAULT(javax.lang.model.element.Modifier.DEFAULT) WildcardTypeName(com.squareup.javapoet.WildcardTypeName) HashMap(java.util.HashMap) TreeSet(java.util.TreeSet) ArrayList(java.util.ArrayList) HashSet(java.util.HashSet) LinkedHashMap(java.util.LinkedHashMap) DeclaredType(javax.lang.model.type.DeclaredType) CodeBlock(com.squareup.javapoet.CodeBlock) LinkedHashSet(java.util.LinkedHashSet) Name(javax.lang.model.element.Name) WildcardTypeName.subtypeOf(com.squareup.javapoet.WildcardTypeName.subtypeOf) PRIVATE(javax.lang.model.element.Modifier.PRIVATE) Iterator(java.util.Iterator) MethodSpec(com.squareup.javapoet.MethodSpec) PUBLIC(javax.lang.model.element.Modifier.PUBLIC) ExecutableElement(javax.lang.model.element.ExecutableElement) Redacted(io.norberg.automatter.AutoMatter.Redacted) ParameterizedTypeName(com.squareup.javapoet.ParameterizedTypeName) IOException(java.io.IOException) TypeSpec(com.squareup.javapoet.TypeSpec) AnnotationMirror(javax.lang.model.element.AnnotationMirror) STATIC(javax.lang.model.element.Modifier.STATIC) ARRAY(javax.lang.model.type.TypeKind.ARRAY) TypeMirror(javax.lang.model.type.TypeMirror) Builder(com.squareup.javapoet.MethodSpec.Builder) TreeMap(java.util.TreeMap) RoundEnvironment(javax.annotation.processing.RoundEnvironment) AutoService(com.google.auto.service.AutoService) AnnotationSpec(com.squareup.javapoet.AnnotationSpec) ProcessingEnvironment(javax.annotation.processing.ProcessingEnvironment) Collections(java.util.Collections) ArrayTypeName(com.squareup.javapoet.ArrayTypeName) TypeElement(javax.lang.model.element.TypeElement) ArrayList(java.util.ArrayList) AutoMatter(io.norberg.automatter.AutoMatter) IOException(java.io.IOException) ClassName(com.squareup.javapoet.ClassName) TypeName(com.squareup.javapoet.TypeName) WildcardTypeName(com.squareup.javapoet.WildcardTypeName) Name(javax.lang.model.element.Name) ParameterizedTypeName(com.squareup.javapoet.ParameterizedTypeName) ArrayTypeName(com.squareup.javapoet.ArrayTypeName)

Example 2 with AutoMatter

use of io.norberg.automatter.AutoMatter in project auto-matter by danielnorberg.

the class AutoMatterTypeAdapterFactory method create.

@SuppressWarnings("unchecked")
@Override
public <T> TypeAdapter<T> create(final Gson gson, final TypeToken<T> type) {
    final TypeAdapter<T> materialized;
    final AutoMatter annotation = type.getRawType().getAnnotation(AutoMatter.class);
    if (annotation != null) {
        if (!type.getRawType().isInterface()) {
            // Only handle interface style @AutoMatter types.
            return null;
        }
        // We are now the proud owners of an AutoMatter annotated interface.
        // Return the cached type, if present.
        final TypeAdapter<T> cached = (TypeAdapter<T>) adapters.get(type);
        if (cached != null) {
            return cached;
        }
        // Look up and instantiate the value class
        final String name = type.getRawType().getName();
        final int lastDollar = name.lastIndexOf("$");
        final String valueName;
        if (lastDollar > -1) {
            final int lastDot = name.lastIndexOf(".");
            valueName = name.substring(0, lastDot + 1).concat(name.substring(lastDollar + 1)) + VALUE_SUFFIX;
        } else {
            valueName = name + VALUE_SUFFIX;
        }
        final Class<T> cls;
        try {
            cls = (Class<T>) Class.forName(valueName);
        } catch (ClassNotFoundException e) {
            throw new IllegalArgumentException("No builder found for @AutoMatter type: " + name, e);
        }
        // Find those magic remapping-of-name-annotations (SerializedName)
        final Map<String, List<String>> serializedNameMethods = getSerializedNameMethods(gson, type.getRawType(), cls);
        // If the interface passed to us didn't have any SerializedName annotations, go the fast path
        // and just pass it on the type adapter chain,
        // it will most likely end up in the ReflectiveTypeAdapterFactory, good riddance!
        // If it was annotated, we create a TypeAdapter that knows how to poke the json into
        // Java world submission.
        materialized = serializedNameMethods.isEmpty() ? gson.getAdapter(cls) : createForInterface(gson, cls, serializedNameMethods);
    } else {
        // Maybe a value class with SerializedName annotations?
        final Map<String, List<String>> serializedNameMethodsbuilder = new HashMap<>();
        // Since AutoMatter supports inheritance we need to walk through all of the interfaces with
        // AutoMatter annotations.
        final Class<? super T> valueClass = type.getRawType();
        for (Class<?> itf : valueClass.getInterfaces()) {
            if (itf.getAnnotation(AutoMatter.class) != null) {
                serializedNameMethodsbuilder.putAll(getSerializedNameMethods(gson, itf, valueClass));
            }
        }
        final Map<String, List<String>> serializedNameMethods = serializedNameMethodsbuilder;
        // applicable. Bye, bye! This should be the fast path.
        if (serializedNameMethods.isEmpty()) {
            return null;
        }
        // We create a TypeAdapter that knows how to read between the lines (A.K.A is annotation
        // aware)
        // and can translate the restricted Java world names to beautiful free form json fields. Nom!
        materialized = createForValue(gson, this, type, serializedNameMethods);
    }
    // Cache the materialized type before returning
    final TypeAdapter<T> existing = (TypeAdapter<T>) adapters.putIfAbsent(type, materialized);
    return (existing != null) ? existing : materialized;
}
Also used : ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) HashMap(java.util.HashMap) AutoMatter(io.norberg.automatter.AutoMatter) TypeAdapter(com.google.gson.TypeAdapter) ArrayList(java.util.ArrayList) List(java.util.List) Arrays.asList(java.util.Arrays.asList)

Aggregations

AutoMatter (io.norberg.automatter.AutoMatter)2 ArrayList (java.util.ArrayList)2 HashMap (java.util.HashMap)2 List (java.util.List)2 AutoService (com.google.auto.service.AutoService)1 TypeAdapter (com.google.gson.TypeAdapter)1 AnnotationSpec (com.squareup.javapoet.AnnotationSpec)1 ArrayTypeName (com.squareup.javapoet.ArrayTypeName)1 ClassName (com.squareup.javapoet.ClassName)1 CodeBlock (com.squareup.javapoet.CodeBlock)1 FieldSpec (com.squareup.javapoet.FieldSpec)1 JavaFile (com.squareup.javapoet.JavaFile)1 MethodSpec (com.squareup.javapoet.MethodSpec)1 Builder (com.squareup.javapoet.MethodSpec.Builder)1 ParameterSpec (com.squareup.javapoet.ParameterSpec)1 ParameterizedTypeName (com.squareup.javapoet.ParameterizedTypeName)1 TypeName (com.squareup.javapoet.TypeName)1 TypeSpec (com.squareup.javapoet.TypeSpec)1 WildcardTypeName (com.squareup.javapoet.WildcardTypeName)1 WildcardTypeName.subtypeOf (com.squareup.javapoet.WildcardTypeName.subtypeOf)1