使用SPOON创建匿名类的实例

问题描述

我需要在Spoon中传递一个匿名类的实例作为函数参数。 就我而言,我有一个匿名比较器,我需要将其传递给以Comparator 作为参数的函数

这是我的代码

public boolean isToBeProcessed(CtType<?> candidate) {
        if(candidate instanceof CtClass<?> && ((CtClass<?>)candidate).isAnonymous()==true){
            CtClass<?> clas = (CtClass<?>)candidate;
            List<CtMethod<?>> list = clas.filterChildren(
                  new AbstractFilter<CtMethod<?>>(CtMethod.class) {
                    @Override
                    public boolean matches(CtMethod<?> method) {
                      return method.getSimpleName().equals("compare");
                    }
                  }
                ).list();
        return !(list==null || list.isEmpty());
        }
        return false;
    }
    
    @Override
    public void process(CtType<?> element) {
        // here I need to pass the anonymous Comparator class
        testComparator( ??? ); 
    }

    public void testComparator(Comparator<?> comparator) {
      ......
    }

我是Spoon的新手,感谢您的帮助。

谢谢。

解决方法

我想我设法做到了你的要求。

dir / App.java

import java.util.Comparator;

public class App {
    public static void main(String[] args) {
        foo1(new Comparator<Integer>() {
            @Override
            public int compare(Integer o1,Integer o2) {
                return 0;
            }
        });

        foo2(new Comparator<String>() {
            @Override
            public int compare(String o1,String o2) {
                return 0;
            }
        });
    }
}

src / main / java / MyProcessor.java

import spoon.Launcher;
import spoon.processing.AbstractProcessor;
import spoon.reflect.declaration.CtClass;
import spoon.reflect.declaration.CtMethod;
import spoon.reflect.declaration.CtType;
import spoon.reflect.visitor.filter.AbstractFilter;
import spoon.support.compiler.FileSystemFile;

import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.List;

public class MyProcessor extends AbstractProcessor<CtType<?>> {
    @Override
    public boolean isToBeProcessed(CtType<?> candidate) {
        if (candidate instanceof CtClass<?> && ((CtClass<?>) candidate).isAnonymous() == true) {
            CtClass<?> clas = (CtClass<?>) candidate;
            List<CtMethod<?>> list = clas.filterChildren(
                    new AbstractFilter<CtMethod<?>>(CtMethod.class) {
                        @Override
                        public boolean matches(CtMethod<?> method) {
                            return method.getSimpleName().equals("compare");
                        }
                    }
            ).list();
            return !(list == null || list.isEmpty());
        }
        return false;
    }

    @Override
    public void process(CtType<?> element) {
        String implementsString = element.getParent().toString()
                .replace("()","")
                .replace("new","implements");

        String codeA =
                "public class A {\n" +
                "  public void m() {\n" +
                "    Main.testComparator(new B());\n" +
                "  }\n" +
                "}";

        String codeB = "public class B " + implementsString;

        String fileNameA = "dir2/A.java";
        String fileNameB = "dir2/B.java";
        try (FileWriter fileWriterA = new FileWriter(fileNameA);
             FileWriter fileWriterB = new FileWriter(fileNameB)) {
            fileWriterA.write(codeA);
            fileWriterB.write(codeB);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        Launcher launcher = new Launcher();
        launcher.addInputResource("dir2");
        Collection<CtType<?>> allTypes = launcher.buildModel().getAllTypes();
        CtClass<?> ctClassA = (CtClass<?>) allTypes.stream().findFirst().get();

        Object instance = ctClassA.newInstance();
        Class<?> classA = instance.getClass();
        try {
            Method method = classA.getMethod("m");
            method.invoke(instance);
        } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
            throw new RuntimeException(e);
        }
    }
}

src / main / java / Main.java

import spoon.Launcher;

import java.util.Comparator;

public class Main {
    public static void testComparator(Comparator<?> comparator) {
        System.out.println("test Comparator");
    }

    public static void main(String[] args) {
        Launcher launcher = new Launcher();
        launcher.addInputResource("dir");
        launcher.addProcessor(new MyProcessor());
        launcher.run();
    }
}

dir2 / A.java

dir2 / B.java

pom.xml

...
<dependency>
    <groupId>fr.inria.gforge.spoon</groupId>
    <artifactId>spoon-core</artifactId>
    <version>8.2.0</version>
</dependency>

还必须将目录spooned-classes添加到类路径。我正在使用sbt。可以在此处指定为unmanagedClasspath in Runtime ++= Seq(file("spooned-classes")).classpath。在Maven中,应类似地指定。

输出:

[main] INFO spoon.Launcher - Running in NOCLASSPATH mode (doc: http://spoon.gforge.inria.fr/launcher.html).
[main] INFO spoon.Launcher - Running in NOCLASSPATH mode (doc: http://spoon.gforge.inria.fr/launcher.html).
test Comparator
[main] INFO spoon.Launcher - Running in NOCLASSPATH mode (doc: http://spoon.gforge.inria.fr/launcher.html).
test Comparator

因此,testComparator中的Main对应于foo1中的foo2App执行了两次。