24 Ağustos 2023 Perşembe

com.sun.source.util.Plugin Arayüzü

Giriş
Şu satırı dahil ederiz
import com.sun.source.util.Plugin;
java compiler tarafından çağrılır ve kod üretebilmeyi sağlar. java compiler javac komutu veya JavaCompiler arayüzü olabilir

Maven
Şu satırı dahil ederiz
<dependency>
  <groupId>com.sun</groupId>
  <scope>system</scope>
  <artifactId>tools</artifactId>
  <version>1.8.0</version>
  <systemPath>${java.home}/../lib/tools.jar</systemPath>
</dependency>
init metodu
Örnek
Şöyle yaparız
public class myJavacPlugin implements Plugin { 

  @Override 
  public String getName() { 
   return "InterviewBit"; 
  }

  @Override 
  public void init(JavacTask task, String... args) { 
    Context context = ((BasicJavacTask) task).getContext(); 
    Log.instance(context) 
      .printRawLines(Log.WriterKind.NOTICE, "Hi from " + getName()); 
  } 
}
Şu dosyayı yaratırız
META-INF/services/com.sun.source.utility.Plugin
Dosyanın içi şöyledir
com.JavaTutorials.javac.myJavacPlugin
Çalıştırmak için şöyle yaparız
 javac -cp ./core-java/target/classes -Xplugin:plugin
  ./core-java/src/main/java/com/JavaTutorials/javac/sampleClass.java
Hi from plugin
TaskListener Arayüzü
Şu satırı dahil ederiz
import com.sun.source.util.JavacTask;
com.sun.source.util.JavacTask nesnesine listener takılabilir

Örnek
Şöyle yaparız
public void init(JavacTask task, String... args) {
  task.addTaskListener(new TaskListener() {
    @Override
    public void started(TaskEvent e) {
    }

    @Override
    public void finished(TaskEvent e) {
      if (e.getKind() != TaskEvent.Kind.PARSE) {
        return;
      }
      // Perform instructions
    }
  });
}
finished metodu
TaskEvent nesnesinin getKind() metodu şunları döndürebilir
PARSE - builds an Abstract Syntax Tree (AST)
ENTER - source code imports are resolved
ANALYZE - We analyze parser output for errors
GENERATE - Creating binaries for the target source file
There are two more event kinds - ANNOTATION_PROCESSING and ANNOTATION_PROCESSING_ROUND but we don’t bother about them here.

Örnek - Extract AST Data
Şöyle yaparız.  com.sun.source.util.TreeScanner kullanılıyor TreeScanner sınıfı com.sun.source.tree.TreeVisitor arayüzünü gerçekleştirir
public void finished(TaskEvent e) {
  if (e.getKind() != TaskEvent.Kind.PARSE) {
    return;
  }
  e.getCompilationUnit().accept(new TreeScanner<Void, Void>() {
    @Override
    public Void visitClass(ClassTree currentNode, Void aVoid) {
      return super.visitClass(currentNode, aVoid);
    }

    @Override
    public Void visitMethod(MethodTree currentNode, Void aVoid) {
      return super.visitMethod(currentNode, aVoid);
    }
  }, null);
}
Örnek - Modify AST Data
Şöyle yaparız. Burada amaç @Position olarak benim tanımladığım bir anotasyon için kod üretip geçilen parametre eksi bir değerse exception fırlatmak
public void finished(TaskEvent e) {
  if (e.getKind() != TaskEvent.Kind.PARSE) {
    return;
  }
  e.getCompilationUnit().accept(
    new TreeScanner<Void, Void>() {
      @Override
      public Void visitMethod(MethodTree method, Void v) {
        List<VariableTree> parametersToInstrument
          = method.getParameters().stream()
            .filter(SampleJavacPlugin.this::shouldInstrument)
            .collect(Collectors.toList());
            
        if (!parametersToInstrument.isEmpty()) {
          Collections.reverse(parametersToInstrument);
          parametersToInstrument.forEach(p -> addCheck(method, p, context));
        }
        return super.visitMethod(method, v);
      } // visitMethod
    }, null); //accept
}

private static Set<String> TARGET_TYPES = Stream.of(
  byte.class, short.class, char.class, 
  int.class, long.class, float.class, double.class)
 .map(Class::getName)
 .collect(Collectors.toSet());
 
private boolean shouldInstrument(VariableTree parameter) {
    return TARGET_TYPES.contains(parameter.getType().toString())
      && parameter.getModifiers().getAnnotations().stream()
      .anyMatch(a -> Positive.class.getSimpleName()
        .equals(a.getAnnotationType().toString()));
}
addCheck metodu AST'yi değiştiren yer. Şöyle yaparız.  Bu kodu tam olarak kopyalamadım.
private void addCheck(MethodTree myMethod, VariableTree myParameter, Context myContext) {
    JCTree.JCIf check = createCheck(myParameter, myContext);
    JCTree.JCBlock body = (JCTree.JCBlock) myMethod.getBody();
    body.stats = body.stats.prepend(check);
}

private static JCTree.JCIf createCheck(VariableTree parameter, Context context) {
    TreeMaker factory = TreeMaker.instance(context);
    Names symbolsTable = Names.instance(context);
        
    return factory.at(((JCTree) parameter).pos)
      .If(factory.Parens(
	    createIfCondition(factory, symbolsTable, parameter)),
        createIfBlock(factory, symbolsTable, parameter), 
		null)
		
}







Hiç yorum yok:

Yorum Gönder