2016-11-14 44 views
2

我有一個註釋處理器需要一個註解類,並試圖創建它的一個子類:如何查找TypeMirror的邊界並將它們轉換爲JavaPoet TypeSpec?

package test; 

import com.squareup.javapoet.ClassName; 
import com.squareup.javapoet.JavaFile; 
import com.squareup.javapoet.TypeSpec; 

import java.io.IOException; 
import java.util.Set; 

import javax.annotation.processing.AbstractProcessor; 
import javax.annotation.processing.ProcessingEnvironment; 
import javax.annotation.processing.RoundEnvironment; 
import javax.annotation.processing.SupportedAnnotationTypes; 
import javax.annotation.processing.SupportedSourceVersion; 
import javax.lang.model.SourceVersion; 
import javax.lang.model.element.Element; 
import javax.lang.model.element.Modifier; 
import javax.lang.model.element.TypeElement; 

@SupportedAnnotationTypes("java.lang.SuppressWarnings") 
@SupportedSourceVersion(SourceVersion.RELEASE_7) 
public class BSProcessor extends AbstractProcessor { 
    @Override 
    public synchronized void init(ProcessingEnvironment processingEnv) { 
     super.init(processingEnv); 
    } 

    @Override 
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnvironment) { 
     for (TypeElement baseClassAnnotation : annotations) { 
      for (Element annotatedElement : roundEnvironment.getElementsAnnotatedWith(baseClassAnnotation)) { 
       handleAnnotatedTypeElement((TypeElement) annotatedElement); 
      } 
     } 
     return true; 
    } 

    private void handleAnnotatedTypeElement(TypeElement annotatedTypeElement) { 
     try { 
      javaFile(annotatedTypeElement).writeTo(System.out); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
    } 

    private JavaFile javaFile(TypeElement annotatedTypeElement) { 
     return JavaFile.builder(packageName(annotatedTypeElement), typeSpec(annotatedTypeElement)) 
       .build(); 
    } 

    private TypeSpec typeSpec(TypeElement annotatedTypeElement) { 
     return TypeSpec.classBuilder(className(annotatedTypeElement)) 
       .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT) 
       .build(); 
    } 

    private ClassName className(TypeElement annotatedTypeElement) { 
     return ClassName.get(packageName(annotatedTypeElement), String.format("AutoGenerated_%s", 
       annotatedTypeElement.getSimpleName())); 
    } 

    private String packageName(TypeElement annotatedTypeElement) { 
     return annotatedTypeElement.getEnclosingElement().toString(); 
    } 
} 

這適用於類中,無類型參數,但我不知道如何與他們這樣做。在類型變量上執行toString將只給出變量名稱,而不是邊界。任何想法如何做到這一點?

回答

1

TypeElement的型號參數可以通過調用getTypeParameters()進行檢索,可以通過調用getBounds()獲得 s來獲取其邊界。我假設,你對以下步驟感到困惑 - 應該將哪些具體類型傳遞給這些類型參數以滿足這些邊界。

不幸的是,這是一個問題,不能輕易解決任意類型(這是你似乎以後)。例如,看這個類型:

public abstract class Recursive<UU extends Callable<UU>> { 
} 

您可以直觀地得出結論,認爲它可以通過這樣一個類實現:

public class Solution extends Recursive<Solution> implements Callable<Solution> { 
    @Override 
    public Solution call() throws Exception { 
    return new Solution(); 
    } 
} 

但是這不平凡的自動化,而你(可能)不想在代碼中包含所需的機器。

,而不是試圖自己解決這個問題,我建議你利用類型擦除,讓編譯器爲你解決這個問題:

// returns something like "Map<K, V>", this is NOT what you want! 
DeclaredType classType = (DeclaredType) typeElement.asType(); 

Types types = processingEnvironment.getTypeUtils(); 
Elements elements = processingEnvironment.getElementUtils(); 

// this obtains raw type (plain "Map"), with all methods type-erased, 
// the compiler is much better at solving type riddles than you! 
DeclaredType rawType = types.getDeclaredType(typeElement); 

final Collection<? extends ExecutableElement> methods = 
    ElementFilter.methodsIn(elements.getAllMembers(typeElement)); 

// To create a MethodSpec, suitable for the raw type, you should 
// call 3-parameter MethodSpec#overriding with type-erased raw class type 
// as second parameter and javax.lang.model.util.Types instance as third 
MethodSpec newMethod = MethodSpec.overriding(methods.get(0), rawType, types); 

因此,回答您的具體問題是「唐將任何類型參數傳遞給JavaPoet,使用原始類型「。

+0

謝謝。幫了很多! –

相關問題