I have difficulty in accessing member of a class with the parameter using a collection. For example List. This is a tiny example of a "grabber" class, which accesses a function with int parameter, but cannot find the function with the collection as its argument. This code prints a list of all members and their arguments as a diagnosis.
import static java.lang.System.out;
import static java.lang.System.err;
import java.util.List;
import java.util.ArrayList;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
public class grabber
{
public static void main(String args[])
{
Class<?> c=null;
try {
c=Class.forName("item");
} catch (ClassNotFoundException e) {
out.printf("?W: class item not found\n");
return;
}
try {
Object an_item=c.getDeclaredConstructor().newInstance();
out.printf("Listing methods of 'item' and their parameters\n");
Method[] allm=c.getDeclaredMethods();
for (Method m: allm)
{
String mnam=m.getName();
Type[] mptype=m.getGenericParameterTypes();
out.printf("\n\tItem Method m=%s lg of param types:%d\n",mnam, mptype.length);
for (Type t:mptype)
{
out.printf("\t arg type=%s\n",t.toString());
}
}
out.println();
Method callf2=c.getDeclaredMethod("f2", int.class);
out.printf("\tMethod callf2() is : %s\n", callf2);
Object ret=callf2.invoke(an_item,234);
List<Object> arlob=new ArrayList<Object>(); // identical to item.f1 argument
Method callf1=c.getDeclaredMethod("f1",arlob.getClass()); // this causes exception
} catch (Exception e) {
err.println("?E: Exception "+e.getClass().getName());
err.println("?E: Exception "+e.getLocalizedMessage());
e.printStackTrace(err);
return;
}
} /* main() */
} /* class */
The called class "item" is simply:
import java.util.List;
class item
{
List<Object> f1(List<Object> lob)
{
System.out.printf("\t\t------item.f1: lob.lg=%d\n",lob.size());
return lob;
}
int f2(int arg)
{
System.out.printf("\t\t------item.f2: arg=%d\n",arg);
return arg;
}
}
When I run the class grabber, the following happens, and I could not discover a way to access the function f1(List):
Listing methods of 'item' and their parameters
Item Method m=f2 lg of param types:1
arg type=int
Item Method m=f1 lg of param types:1
arg type=java.util.List<java.lang.Object>
Method callf2() is : public int item.f2(int)
------item.f2: arg=234
?E: Exception java.lang.NoSuchMethodException
?E: Exception item.f1(java.util.ArrayList)
java.lang.NoSuchMethodException: item.f1(java.util.ArrayList)
at java.lang.Class.getDeclaredMethod(Class.java:2130)
at grabber.main(grabber.java:51)
I wonder if someone found out how to access functions using abstract classes in argument list.
Simply solution would be to put known type as you already know what method is accepting as you have done in the first method call.
Change
Method callf1=c.getDeclaredMethod("f1",arlob.getClass());
to
Method callf1=c.getDeclaredMethod("f1",List.class);
Related
I have one problem in understanding of Java 8 associated with reference to methods as a parameter to static methods. There is my code where I can't find how to send a reference to a method which doesn't have any parameters and must be a method for an object of the definite class.
So, I want that the method which I send to static function may be used for the object in the static method.
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.stream.Stream;
interface FuncForPath<T> {
T func(T path);
}
class MethodsForFolder {
public static void printFilesInFolder(Path path, FuncForPath<Path> funcPath) {
Stream<Path> paths = null;
try {
paths = Files.list(path);
} catch (IOException e) {
System.out.println(
"The problems have been appeared during reading folder: " + path.toAbsolutePath().toString());
e.printStackTrace();
}
System.out.println("Files list in folder:" + path.toAbsolutePath().toString());
paths.forEach(p -> funcPath.func(p).toString()); // I don't know to how to write this code to perform
}
}
public class TestRefToIntance {
public static String testWindowsFloder = "C://Logs";
public static void main(String[] args) {
Path path = Paths.get(testWindowsFloder);
// I want that this 2 methods are performed depending on transfered methods
// reference
MethodsForFolder.printFilesInFolder(path, Path::toAbsolutePath);
MethodsForFolder.printFilesInFolder(path, Path::getFileName);
}
}
Try Function<Path, Path> instead of FuncForPath. This will require a method taking a Path parameter and returning a Path. Note that instance methods always have an "invisible" this parameter, hence Path::getFileName matches that signature.
You'd then call it like this: paths.forEach( p -> funcPath.apply( p ).toString() ); (although you're not doing anything with the returned string, so you probably want to call paths.map( f ).map( Path::toString ).collect( someCollector ); instead.
How I understand I have resolved this problem. There is code below.
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.stream.Stream;
interface FuncForPath<T> {
T func(T path);
}
class MethodsForFolder {
public static void printFilesInFolder(Path path, FuncForPath<Path> funcPath) {
Stream<Path> paths = null;
try {
paths = Files.list(path);
} catch (IOException e) {
System.out.println(
"The problems have been appeared during reading folder: " + path.toAbsolutePath().toString());
e.printStackTrace();
}
System.out.println("Files list in folder:" + path.toAbsolutePath().toString());
paths.forEach(p -> System.out.println(funcPath.func(p).toString())); // I don't know to how to write this code to perform
}
}
public class TestRefToIntance {
public static String testWindowsFloder = "C://Logs";
public static void main(String[] args) {
Path path = Paths.get(testWindowsFloder);
// I want that this 2 methods are performed depending on transfered methods
// reference
MethodsForFolder.printFilesInFolder(path, Path::toAbsolutePath);
MethodsForFolder.printFilesInFolder(path, Path::getFileName);
}
}
Also, I have deleted the generic specification in interface description.
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.stream.Stream;
interface FuncForPath { // there is interface without type <T>
Path func(Path path);
}
class MethodsForFolder {
public static void printFilesInFolder(Path path, FuncForPath funcPath) {
Stream<Path> paths = null;
try {
paths = Files.list(path);
} catch (IOException e) {
System.out.println(
"The problems have been appeared during reading folder: " + path.toAbsolutePath().toString());
e.printStackTrace();
}
System.out.println("Files list in folder:" + path.toAbsolutePath().toString());
paths.forEach(p -> System.out.println(funcPath.func(p).toString())); // I don't know to how to write this code
// to perform
}
}
public class TestRefToIntance {
public static String testWindowsFloder = "C://Logs";
public static void main(String[] args) {
Path path = Paths.get(testWindowsFloder);
// I want that this 2 methods are performed depending on transfered methods
// reference
MethodsForFolder.printFilesInFolder(path, Path::toAbsolutePath);
MethodsForFolder.printFilesInFolder(path, Path::getFileName);
}
}
Methods[] method =classname.getClass().getDeclaredMethods();
In the above code, i want to get the value of particular method. Suppose above method will return some getter and setter methods. Can we get the value of any getter methods?
Like PeterMmm said, you can use invoke on Method, passing the object that you want the call to be made on, and any other arguments the method needs, as get methods usually don't have arguments, you can do like this:
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class MethodsTest {
public int getA() {
return 5;
}
public int getB() {
return 8;
}
public static void main(String[] args) {
MethodsTest obj = new MethodsTest();
Method[] methods = obj.getClass().getDeclaredMethods();
for (Method method: methods) {
if (method.getName().startsWith("get"))
try {
System.out.println(method.getName() + ": " + method.invoke(obj));
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
e.printStackTrace();
}
}
}
}
it will print:
getB: 8
getA: 5
hope it helps
From what i know, java cannot retrieve anything inside method. so i using option -g or -g:vars in javac.
for e.g :
class Test {
int a=0;
void method(boolean boo){
String b;
try
{
new Thread().sleep(1000);
}
catch(InterruptedException e){}
JOptionPane.showMessageDialog(null,"test");
BufferedImage image=ImageIO.read(new File("C:\\file.png"));
}
}
So, i use BCEL to retrieve local variable.
import org.apache.bcel.classfile.*;
import org.apache.bcel.Repository;
class javap
{
public static void main(String[]args)
{
try
{
JavaClass jc = Repository.lookupClass("test");
ConstantPool constantPool = jc.getConstantPool();
Method [] method=jc.getMethods();
for (Method m : method)
{
LocalVariableTable lvt=m.getLocalVariableTable();
LocalVariable[] lv=lvt.getLocalVariableTable();
for(LocalVariable l : lv)
{
System.out.println(l.getName()+" : "+l.getSignature());
}
}
}
catch(Exception ex)
{
ex.printStackTrace();
}
}
}
But it doesn't work if variable is not initialized like String b. Additionally I want to track constructor calls like new Thread() or new File() as well as invocations of static methods and inside intialize inside JFileChooser like new File and JOptionPane too. So I want to see in output Thread, String b, JOptionPane, ImageIO, and File.
What should I do, to make them are printed in my program?
You simply cannot get the b variable, because java compilers (at least javac and ecj) do not put it into the generated class file at all: if variable is not assigned, no variable slot is allocated and it's not stored in the LocalVariableTable. You can create unused variable with longer name like String blahblah;, compile the class, open the compiled .class-file in text editor and search for blahblah string. You will not found it. So BCEL cannot help you to find the variable which is absent.
If you want to track new objects creation and static methods invocation, you can do it scanning the method bytecode. The easiest way to do it with BCEL is to utilize the MethodGen (even though you don't want to generate the new method). Here's the full code:
import org.apache.bcel.Constants;
import org.apache.bcel.Repository;
import org.apache.bcel.classfile.ConstantMethodref;
import org.apache.bcel.classfile.ConstantPool;
import org.apache.bcel.classfile.JavaClass;
import org.apache.bcel.classfile.LocalVariable;
import org.apache.bcel.classfile.LocalVariableTable;
import org.apache.bcel.classfile.Method;
import org.apache.bcel.generic.ConstantPoolGen;
import org.apache.bcel.generic.INVOKESTATIC;
import org.apache.bcel.generic.InstructionHandle;
import org.apache.bcel.generic.MethodGen;
import org.apache.bcel.generic.NEW;
class javap
{
public static void main(String[]args)
{
try
{
JavaClass jc = Repository.lookupClass("Test");
ConstantPool constantPool = jc.getConstantPool();
Method [] method=jc.getMethods();
for (Method m : method)
{
LocalVariableTable lvt=m.getLocalVariableTable();
LocalVariable[] lv=lvt.getLocalVariableTable();
for(LocalVariable l : lv)
{
System.out.println(l.getName()+" : "+l.getSignature());
}
}
ConstantPoolGen cpg = new ConstantPoolGen(constantPool);
for(Method m : method)
{
MethodGen mg = new MethodGen(m, m.getName(), cpg);
for(InstructionHandle ih = mg.getInstructionList().getStart();
ih != null; ih = ih.getNext())
{
if(ih.getInstruction() instanceof NEW)
{
NEW newInst = ((NEW)ih.getInstruction());
String className = constantPool.getConstantString(
newInst.getIndex(), Constants.CONSTANT_Class);
System.out.println("Class instantiation: "+className);
}
if(ih.getInstruction() instanceof INVOKESTATIC)
{
INVOKESTATIC newInst = ((INVOKESTATIC)ih.getInstruction());
String className = constantPool.getConstantString(
((ConstantMethodref) constantPool
.getConstant(newInst.getIndex()))
.getClassIndex(),
Constants.CONSTANT_Class);
System.out.println("Static call: "+className);
}
}
}
}
catch(Exception ex)
{
ex.printStackTrace();
}
}
}
The output is the following:
this : LTest;
this : LTest;
boo : Z
Class instantiation: java/lang/Thread
Static call: java/lang/Thread
Static call: javax/swing/JOptionPane
Class instantiation: java/io/File
Static call: javax/imageio/ImageIO
Note that you have java/lang/Thread twice, because new Thread() is catched as object creation and Thread.sleep() is catched as static method invocation.
With Java7 and Java8, I would like to generate a warning if some methods was called.
The warning will be print if a specific jar is present when then user compile.
I write an Annotation Processor and catch the visitMethodInvocation(). Now, I want extract the class and method names will be invoked.
Is it possible to do that ?
Or how to approach this?
You can do something like:
package mystuff;
import com.sun.source.tree.*;
import com.sun.source.util.*;
import java.util.*;
import javax.annotation.processing.*;
import javax.lang.model.element.*;
import javax.tools.*;
#SupportedAnnotationTypes("*")
public class Proc extends AbstractProcessor{
#Override
public boolean process(Set<?extends TypeElement>annotations,RoundEnvironment roundEnvironment){
final Trees trees=Trees.instance(processingEnv);
for(Element element:roundEnvironment.getRootElements()){
TreePath path=trees.getPath(element);
final CompilationUnitTree compilationUnit=path.getCompilationUnit();
compilationUnit.accept(new TreeScanner<Object,Object>(){
#Override
public Object visitMethodInvocation(MethodInvocationTree tree,Object data){
tree.getMethodSelect().accept(new SimpleTreeVisitor<Object,Object>(){
#Override
public Object visitMemberSelect(MemberSelectTree tree,Object data){
processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE,String.format("class: %1$s\nmethod: %2$s",tree.getExpression(),tree.getIdentifier()));
return null;
}
},null);
return null;
}
},null);
}
return true;
}
}
I used that processor to process the below class
package stuff;
import java.util.*;
#MyAnnotation
class MyProgram{
public void run(){
System.out.println("Hello World!");
}
}
and achieved this result:
class: System.out
method: println
I am pretty sure that the method name generated is what you are looking for. I am pretty sure that the "class" is not exactly what you are looking for, but is a pretty good start.
In my example you probably wanted it to print "java.io.PrintStream" for the class. To get that you could use processingEnv.getElementUtils().getTypeElement("java.lang.System") to get a TypeElement representing the system class. Then you can use processingEnv.getElementUtils().getAllMembers() to get every single member of the system class. Iterate through that to find out. Use the asType method to get its type.
The preceding paragraph was a gross simplification. The processor did not know a priori that out is a static member of a class that is part of the implicitly imported java.lang package. So your code will have to try and fail to find the following classes System and java.util.System (because it is in the imports), System.out, java.util.System.out, and java.lang.System.out.
I only dealt with MemberSelect. You will have to deal with other possibilities including MethodInvocation. For example new Object().toString().hashCode() should be class=Object, method=hashCode.
As an alternative to the great answer from #emory, you can consider using the pluggable type-checking annotation processing provided by the Checker Framework. The advantage is it can help you to easily determinate the type of the method invoker. Here is an example processor based on the checker framework (add checker.jar to the classpath when compile).
#SupportedAnnotationTypes("*")
#SupportedSourceVersion(SourceVersion.RELEASE_8)
public class MyTypeProcessor extends AbstractTypeProcessor {
class MyTreePathScanner extends TreePathScanner<Void, Void> {
private final Trees trees;
private final TreePath root;
public MyTreePathScanner(TreePath root) {
this.trees = Trees.instance(processingEnv);
this.root = root;
}
#Override
public Void visitMemberSelect(MemberSelectTree node, Void aVoid) {
ExpressionTree expression = node.getExpression();
TreePath expr = TreePath.getPath(root, expression);
TypeMirror type = trees.getTypeMirror(expr);
Element typeElement = processingEnv.getTypeUtils().asElement(type);
Optional<? extends Element> invoker = typeElement.getEnclosedElements().stream().filter(
e -> e.getSimpleName().equals(node.getIdentifier())).findFirst();
if (invoker.isPresent() && invoker.get().getKind() == ElementKind.METHOD) {
System.out.println("Type: " + typeElement + ", method: " + invoker.get());
}
return super.visitMemberSelect(node, aVoid);
}
}
#Override
public void typeProcess(TypeElement typeElement, TreePath root) {
new MyTreePathScanner(root).scan(root, null);
}
}
Which is processing the following input source.
public class Test {
public void foo() {
}
public static void main(String[] args) {
System.out.println("Hello world!");
Test t = new Test();
t.foo();
}
}
Here is the output:
Type: java.io.PrintStream, method: println()
Type: Test, method: foo()
I have a private method which take a list of integer value returns me a list of integer value. How can i use power mock to test it. I am new to powermock.Can i do the test with easy mock..? how..
From the documentation, in the section called "Common - Bypass encapsulation":
Use Whitebox.invokeMethod(..) to invoke a private method of an
instance or class.
You can also find examples in the same section.
Here is a full example how to do to it:
import java.util.ArrayList;
import java.util.List;
import org.junit.Assert;
import org.junit.Test;
import org.powermock.reflect.Whitebox;
class TestClass {
private List<Integer> methodCall(int num) {
System.out.println("Call methodCall num: " + num);
List<Integer> result = new ArrayList<>(num);
for (int i = 0; i < num; i++) {
result.add(new Integer(i));
}
return result;
}
}
#Test
public void testPrivateMethodCall() throws Exception {
int n = 10;
List result = Whitebox.invokeMethod(new TestClass(), "methodCall", n);
Assert.assertEquals(n, result.size());
}
Whitebox.invokeMethod(myClassToBeTestedInstance, "theMethodToTest", expectedFooValue);
When you want to test a private method with Powermockito and this private method has syntax:
private int/void testmeMethod(CustomClass[] params){
....
}
in your testing class method:
CustomClass[] params= new CustomClass[] {...}
WhiteboxImpl.invokeMethod(spy,"testmeMethod",params)
will not work because of params. you get an error message that testmeMethod with that arguments doesn't exist
Look here:
WhiteboxImpl class
public static synchronized <T> T invokeMethod(Object tested, String methodToExecute, Object... arguments)
throws Exception {
return (T) doInvokeMethod(tested, null, methodToExecute, arguments);
}
For arguments of type Array, PowerMock is messed up. So modify this in your test method to:
WhiteboxImpl.invokeMethod(spy,"testmeMethod",(Object) params)
You don't have this problem for parameterless private methods. As I can remember it works for parameters of type Primitve type and wrapper class.
"Understanding TDD is understanding Software Engineering"