英文:
Create instance of anonymous class with SPOON
问题
以下是翻译好的内容:
我需要在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) {
    // 在这里我需要传递匿名Comparator类
    testComparator( ??? ); 
}
public void testComparator(Comparator<?> comparator) {
  // ......
}
我对Spoon还不太熟悉,希望您能帮助我解决这个问题。
谢谢。
英文:
I need to pass an instance of an anonymous class as a function parameter, in Spoon.
In my case I have an anonymous Comparator that I need to pass to a function that gets Comparator<?> as a parameter.
Here's my code:
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) {
      ......
    }
I'm new to Spoon and I would appreciate your help with this.
Thanks.
答案1
得分: 0
我猜我成功地完成了你的要求。
*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*
```none
...
<dependency>
    <groupId>fr.inria.gforge.spoon</groupId>
    <artifactId>spoon-core</artifactId>
    <version>8.2.0</version>
</dependency>
同时,必须将目录spooned-classes添加到类路径中。我正在使用sbt。这可以在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。
<details>
<summary>英文:</summary>
I guess I managed to do what you asked.
*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*
```none
...
<dependency>
<groupId>fr.inria.gforge.spoon</groupId>
<artifactId>spoon-core</artifactId>
<version>8.2.0</version>
</dependency>
Also directory spooned-classes has to be added to classpath. I'm using sbt. This can be specified there as unmanagedClasspath in Runtime ++= Seq(file("spooned-classes")).classpath. In Maven this should be specified similarly.
Output:
[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
So testComparator in Main was executed twice corresponding to foo1 and foo2 in App.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论