使用SPOON创建匿名类的实例

huangapple go评论72阅读模式
英文:

Create instance of anonymous class with SPOON

问题

以下是翻译好的内容:

我需要在Spoon中将一个匿名类的实例作为函数参数传递。在我的情况下,我有一个匿名Comparator,我需要将它传递给一个以Comparator<?>作为参数的函数。

这是我的代码:

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

@Override
public void process(CtType&lt;?&gt; element) {
    // 在这里我需要传递匿名Comparator类
    testComparator( ??? ); 
}

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

    public void testComparator(Comparator&lt;?&gt; 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中的foo1foo2


<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&lt;Integer&gt;() {
@Override
public int compare(Integer o1, Integer o2) {
return 0;
}
});
foo2(new Comparator&lt;String&gt;() {
@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&lt;CtType&lt;?&gt;&gt; {
@Override
public boolean isToBeProcessed(CtType&lt;?&gt; candidate) {
if (candidate instanceof CtClass&lt;?&gt; &amp;&amp; ((CtClass&lt;?&gt;) candidate).isAnonymous() == true) {
CtClass&lt;?&gt; clas = (CtClass&lt;?&gt;) candidate;
List&lt;CtMethod&lt;?&gt;&gt; list = clas.filterChildren(
new AbstractFilter&lt;CtMethod&lt;?&gt;&gt;(CtMethod.class) {
@Override
public boolean matches(CtMethod&lt;?&gt; method) {
return method.getSimpleName().equals(&quot;compare&quot;);
}
}
).list();
return !(list == null || list.isEmpty());
}
return false;
}
@Override
public void process(CtType&lt;?&gt; element) {
String implementsString = element.getParent().toString()
.replace(&quot;()&quot;, &quot;&quot;)
.replace(&quot;new&quot;, &quot;implements&quot;);
String codeA =
&quot;public class A {\n&quot; +
&quot;  public void m() {\n&quot; +
&quot;    Main.testComparator(new B());\n&quot; +
&quot;  }\n&quot; +
&quot;}&quot;;
String codeB = &quot;public class B &quot; + implementsString;
String fileNameA = &quot;dir2/A.java&quot;;
String fileNameB = &quot;dir2/B.java&quot;;
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(&quot;dir2&quot;);
Collection&lt;CtType&lt;?&gt;&gt; allTypes = launcher.buildModel().getAllTypes();
CtClass&lt;?&gt; ctClassA = (CtClass&lt;?&gt;) allTypes.stream().findFirst().get();
Object instance = ctClassA.newInstance();
Class&lt;?&gt; classA = instance.getClass();
try {
Method method = classA.getMethod(&quot;m&quot;);
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&lt;?&gt; comparator) {
System.out.println(&quot;test Comparator&quot;);
}
public static void main(String[] args) {
Launcher launcher = new Launcher();
launcher.addInputResource(&quot;dir&quot;);
launcher.addProcessor(new MyProcessor());
launcher.run();
}
}
*dir2/A.java*
*dir2/B.java*
*pom.xml*
```none
...
&lt;dependency&gt;
&lt;groupId&gt;fr.inria.gforge.spoon&lt;/groupId&gt;
&lt;artifactId&gt;spoon-core&lt;/artifactId&gt;
&lt;version&gt;8.2.0&lt;/version&gt;
&lt;/dependency&gt;

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(&quot;spooned-classes&quot;)).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.

huangapple
  • 本文由 发表于 2020年9月10日 18:44:46
  • 转载请务必保留本文链接:https://go.coder-hub.com/63828008.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定