All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.freedesktop.jaccall.compiletime.SymbolsWriter Maven / Gradle / Ivy

The newest version!
package org.freedesktop.jaccall.compiletime;


import org.freedesktop.jaccall.JNI;
import org.freedesktop.jaccall.Symbol;
import org.freedesktop.jaccall.Symbols;
import com.squareup.javapoet.AnnotationSpec;
import com.squareup.javapoet.ArrayTypeName;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.CodeBlock;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.TypeSpec;

import javax.annotation.Generated;
import javax.annotation.processing.Filer;
import javax.annotation.processing.Messager;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.PackageElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.util.ElementFilter;
import javax.tools.Diagnostic;
import java.io.IOException;
import java.util.Collections;
import java.util.List;

final class SymbolsWriter {

    private final Messager messager;
    private final Filer    filer;

    public SymbolsWriter(final Messager messager,
                         final Filer filer) {
        this.messager = messager;
        this.filer = filer;
    }

    public void process(final TypeElement typeElement) {

        final MethodParser methodParser = new MethodParser(this.messager);

        final CodeBlock.Builder methodNamesArray   = CodeBlock.builder();
        final CodeBlock.Builder argSizesArray      = CodeBlock.builder();
        final CodeBlock.Builder ffiSignaturesArray = CodeBlock.builder();
        final CodeBlock.Builder jniSignaturesArray = CodeBlock.builder();

        final List methodsIn = ElementFilter.methodsIn(typeElement.getEnclosedElements());

        int i = 0;
        for (final ExecutableElement executableElement : methodsIn) {
            if (executableElement.getModifiers()
                                 .contains(Modifier.NATIVE)) {
                if (i != 0) {
                    methodNamesArray.add(",\n");
                    argSizesArray.add(",\n");
                    ffiSignaturesArray.add(",\n");
                    jniSignaturesArray.add(",\n");
                }

                final String methodName = methodParser.parseMethodName(executableElement);
                methodNamesArray.add("$S",
                                     methodName);
                argSizesArray.add("/*$L*/ $L",
                                  methodName,
                                  (byte) methodParser.parseArgSize(executableElement));

                boolean isSymobl = false;
                for (final AnnotationMirror annotationMirror : executableElement.getAnnotationMirrors()) {
                    isSymobl = annotationMirror.getAnnotationType()
                                               .asElement()
                                               .getSimpleName()
                                               .toString()
                                               .equals(Symbol.class.getSimpleName());
                    if (isSymobl) {
                        break;
                    }
                }

                if (isSymobl) {
                    //symbol
                    ffiSignaturesArray.add("/*$L*/ 0",
                                           methodName);
                }
                else {
                    //function
                    ffiSignaturesArray.add("/*$L*/ $T.ffi_callInterface($L)",
                                           methodName,
                                           JNI.class,
                                           methodParser.parseFfiSignature(executableElement));
                }


                jniSignaturesArray.add("/*$L*/ $S",
                                       methodName,
                                       methodParser.parseJniSignature(executableElement));
                i++;
            }
        }

        final MethodSpec constructor = MethodSpec.constructorBuilder()
                                                 .addModifiers(Modifier.PUBLIC)
                                                 .addStatement("super($T.class,\n" +
                                                               "new $T{ /*method name*/\n $L\n },\n" +
                                                               "new $T{ /*number of arguments*/\n $L\n },\n" +
                                                               "new $T{ /*FFI call interface*/\n $L\n },\n" +
                                                               "new $T{ /*JNI method signature*/\n $L\n })",
                                                               ClassName.get(typeElement),
                                                               ArrayTypeName.of(String.class),
                                                               methodNamesArray.build(),
                                                               ArrayTypeName.of(byte.class),
                                                               argSizesArray.build(),
                                                               ArrayTypeName.of(long.class),
                                                               ffiSignaturesArray.build(),
                                                               ArrayTypeName.of(String.class),
                                                               jniSignaturesArray.build())
                                                 .build();

        final AnnotationSpec annotationSpec = AnnotationSpec.builder(Generated.class)
                                                            .addMember("value",
                                                                       "$S",
                                                                       JaccallGenerator.class.getName())
                                                            .build();
        final TypeSpec typeSpec = TypeSpec.classBuilder(typeElement.getSimpleName() + "_Symbols")
                                          .addAnnotation(annotationSpec)
                                          .addModifiers(Modifier.PUBLIC)
                                          .addModifiers(Modifier.FINAL)
                                          .superclass(Symbols.class)
                                          .addMethod(constructor)
                                          .build();

        for (final PackageElement packageElement : ElementFilter.packagesIn(Collections.singletonList(typeElement.getEnclosingElement()))) {
            final JavaFile javaFile = JavaFile.builder(packageElement.getQualifiedName()
                                                                     .toString(),
                                                       typeSpec)
                                              .skipJavaLangImports(true)
                                              .build();
            try {
                javaFile.writeTo(this.filer);
            }
            catch (final IOException e) {
                this.messager.printMessage(Diagnostic.Kind.ERROR,
                                           "Could not write symbols source file: \n" + javaFile.toString(),
                                           typeElement);
                e.printStackTrace();
            }
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy