package org.realityforge.arez.processor;

import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeVariableName;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.Nonnull;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.type.TypeVariable;

@SuppressWarnings( "Duplicates" )
final class ProcessorUtil
{
  private ProcessorUtil()
  {
  }

  @Nonnull
  static List<TypeVariableName> getTypeArgumentsAsNames( @Nonnull final DeclaredType declaredType )
  {
    final List<TypeVariableName> variables = new ArrayList<>();
    for ( final TypeMirror argument : declaredType.getTypeArguments() )
    {
      variables.add( TypeVariableName.get( (TypeVariable) argument ) );
    }
    return variables;
  }

  @Nonnull
  static TypeName[] getTypeArgumentsAsTypeNames( @Nonnull final DeclaredType declaredType )
  {
    final List<TypeVariableName> variables = getTypeArgumentsAsNames( declaredType );
    return variables.toArray( new TypeName[ variables.size() ] );
  }

  @Nonnull
  static List<ExecutableElement> getMethods( @Nonnull final TypeElement element )
  {
    final Map<String, ExecutableElement> methodMap = new LinkedHashMap<>();
    enumerateMethods( element, methodMap );
    return new ArrayList<>( methodMap.values() );
  }

  private static void enumerateMethods( @Nonnull final TypeElement element,
                                        @Nonnull final Map<String, ExecutableElement> methods )
  {
    for ( final TypeMirror interfaceType : element.getInterfaces() )
    {
      final TypeElement interfaceElement = (TypeElement) ( (DeclaredType) interfaceType ).asElement();
      enumerateMethods( interfaceElement, methods );
    }
    for ( final Element member : element.getEnclosedElements() )
    {
      if ( member.getKind() == ElementKind.METHOD )
      {
        methods.put( member.getSimpleName().toString(), (ExecutableElement) member );
      }
    }
  }
}

@@ -64,24 +64,193 @@
 avapoet.
-TypeName
+AnnotationSpec;%0Aimport com.squareup.javapoet.MethodSpec;%0Aimport com.squareup.javapoet.ParameterSpec;%0Aimport com.squareup.javapoet.TypeName;%0Aimport com.squareup.javapoet.TypeSpec
 ;%0Aimport
@@ -286,24 +286,64 @@
 riableName;%0A
+import java.lang.annotation.Documented;%0A
 import java.
@@ -431,24 +431,60 @@
 a.util.Map;%0A
+import java.util.stream.Collectors;%0A
 import javax
@@ -504,16 +504,110 @@
 onnull;%0A
+import javax.lang.model.AnnotatedConstruct;%0Aimport javax.lang.model.element.AnnotationMirror;%0A
 import j
@@ -727,32 +727,74 @@
 cutableElement;%0A
+import javax.lang.model.element.Modifier;%0A
 import javax.lan

Update imports