1

I would like to generate a class from an interface. My interface is:

@Annotation
interface Object {
    String getName();
}

I would expect this:

public final class ObjectGenerated implements Object {
  public String getName() {
    return "my code";
  }
}

The class processor is:

@AutoService(Processor.class)
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class Processor extends AbstractProcessor {

    @Override
    public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {

        for (Element element : roundEnvironment.getElementsAnnotatedWith(Annotation.class)) {

            if (element.getKind() != ElementKind.INTERFACE) {
                messager.printMessage(Diagnostic.Kind.ERROR, "Can be applied to class.");
                return false;
            }

            generateClass(element);
        }

        return true;
    }

    private void generateClass(Element element) {

        try {
            String className = element.getSimpleName().toString();
            String pack = processingEnv.getElementUtils().getPackageOf(element).toString();
            String fileName = className + "Generated";

            TypeSpec.Builder classBuilder = TypeSpec
                    .classBuilder(fileName)
                    .addModifiers(Modifier.PUBLIC, Modifier.FINAL)
                    .addSuperinterface(ClassName.get(element.asType()));

            for (Element elementMethod : element.getEnclosedElements()) {
                MethodSpec intentMethod = MethodSpec
                        .methodBuilder(elementMethod.getSimpleName().toString())
                        .addModifiers(Modifier.PUBLIC)
                        .addStatement("return $S", "my code")
                        .returns(ClassName.get(elementMethod.asType())) //this generate error
                        .build();
                classBuilder.addMethod(intentMethod);
            }

            JavaFile.builder(pack, classBuilder.build()).build().writeTo(filer);

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public Set<String> getSupportedAnnotationTypes() {
        return ImmutableSet.of(Annotation.class.getCanonicalName());
    }

    @Override
    public SourceVersion getSupportedSourceVersion() {
        return SourceVersion.latestSupported();
    }
}

The error is: java.lang.IllegalArgumentException: Unexpected type mirror: ()java.lang.String

It's possible that I did something wrong. How can I get the "Type" from the interface in my case is String and use it in the MethodSpec.returns ?

Thanks.

vikey89
  • 71
  • 6

1 Answers1

1

Cast your Element to ExecutableElement and use its getReturnType()

In particular:

    for (Element elementMethod : element.getEnclosedElements()) {
       if (elementMethod.getKind() != ElementKind.METHOD) {
           //skip non-method elements like final fields
           continue;
       }
       ExecutableElement method = (ExecutableElement)elementMethod; //cast
       MethodSpec intentMethod = MethodSpec
                .methodBuilder(method.getSimpleName().toString())
                .addModifiers(Modifier.PUBLIC)
                .addStatement("return $S", "my code")
                .returns(ClassName.get(method.getReturnType())) //should be ok now
                .build();
       classBuilder.addMethod(intentMethod);
    }
Kostiantyn
  • 1,856
  • 11
  • 13