使用 SPOON 创建匿名类的实例
Posted
技术标签:
【中文标题】使用 SPOON 创建匿名类的实例【英文标题】:Create instance of anonymous class with SPOON 【发布时间】:2020-12-28 20:27:29 【问题描述】:我需要在 Spoon 中传递一个匿名类的实例作为函数参数。 在我的例子中,我有一个匿名的 Comparator,我需要将它传递给一个获取 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 的新手,非常感谢您的帮助。
谢谢。
【问题讨论】:
@Holger 我猜public void testComparator...
来自要使用处理器处理的代码(覆盖isToBeProcessed
和process
)。 CtType
是 spoon.reflect.declaration.CtClass
而不是 javassist.CtClass
。
@Dmytro Mitin 是对的。上面的代码来自 Spoon 的处理器类。和他写的代码一模一样。
@DmytroMitin 好的。所以它不是Javassist。但是,由于您的答案仍然没有显示,OP 如何从CtType
创建一个Comparator
,以传递给testComparator
,您似乎同意这不是 OP 应该做的。由于 OP 没有询问如何获得 CtNewClass<?>
,也许您应该告诉 OP,如何处理 CtNewClass<?>
...
@user1579191 你能在处理器转换之前编写代码,在转换之后编写所需的代码吗?
@Dmytro Mitin - 我需要检测系统中所有无效的比较器。只是检测它们,而不是纠正它们。我们有数百个比较器。所以我写了一个函数来处理一个比较器并告诉它是否有效。现在我想为我们系统中的每个 Comparator 调用这个函数,并将所有无效的比较器写入文件。所以我需要以某种方式将 Comparator 类或实例传递给 testComparator(),但我很难做到这一点。
【参考方案1】:
我想我设法做到了你所要求的。
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
所以Main
中的testComparator
执行了两次,对应于App
中的foo1
和foo2
。
【讨论】:
是的,它有效!这正是我需要的!非常感谢!以上是关于使用 SPOON 创建匿名类的实例的主要内容,如果未能解决你的问题,请参考以下文章