mardi 19 avril 2016

Java Reflection to load classes

I am given an external folder called "ATM".

In the folder, it only contains files that ends with .class.

How would I load it?

I've been using Class.forName. It does not work.

I need to load it to use Java's reflection on it.





Provider of a Class

This question is for the provider of a class.

I need to write a Design Analyzer class using Java's reflection

Here is a class example:

class A{

     private D d1;
     private D d2;

     public A(D d1, D d2){
           this.d1 = d1;
           this.d2 = d2;
      } 
}

Does class A uses class D one time or two?

This would help me with my counting algorithm.





Get a list of methods from a class which can be called from java source code

I need a way to get a list of all methods of a java class which could be called from a java file. I know that I can use Class.getMethods, but that does not work in some situations like I need it:

public interface IField<T> {
    public void setValue(T value);
}

public class Field implements IField<String> {
    private String value;

    @Override
    public void setValue(String value) {
        this.value = value;
    }
}

Calling Field.class.getMethods() contains to setValue methods, but only the one with the String parameter is allowed to be called from a java source file.

Just remove the one with the "less specific" parameter is also not a solution becasue there might be situations like this:

public abstract class AbstractBean {
    private Object value;

    public void setValue(Object value) {
        this.value = value;
    }
}

public class Field extends AbstractBean {
    private Integer value;

    public void setValue(Integer value) {
        this.value = value;
    };
}

where both setValue methods are ok to be called.





Java Reflection cannot call getMethod with primitive type [duplicate]

This question already has an answer here:

I have few class like this.

interface AsyncCallback {
    void onComplete(Object response);
}

class Impl {
    public String bar(String i, String j) {
        return i + j;
    }
}

class Async {

    private final Impl impl;

    public Async() {
        impl = new Impl();
    }

    public void bar(String i, String j, AsyncCallback callback) {
        callAsync("bar", callback, new Object[]{i, j});
    }

    private Class[] getParamsClasses(Object[] params) {
        ArrayList<Class> classes = new ArrayList<>();
        for (Object param : params) {
            classes.add(param.getClass());
        }
        return classes.toArray(new Class[classes.size()]);
    }


    private void callAsync(String methodName, AsyncCallback callback, Object[] params) {
        try {
            Thread.sleep(1000);
            Class[] paramClasses = getParamsClasses(params);
            Method methodToCall = impl.getClass().getMethod(methodName, paramClasses);
            Object response;
            response = methodToCall.invoke(impl, params);
            callback.onComplete(response);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}

And then I put them together into this

    Async a = new Async();
    a.bar("1", "2", new AsyncCallback() {

        @Override
        public void onComplete(Object response) {
            System.out.println(response);
        }
    });

This works, outputting string "12" to stdout.

But when I tried adding new method using primitive type.

class Impl {
    //new method
    public int foo(int i, int j, int k) {
        return i + j + k;
    }
}

class Async {
    //new method
    public void foo(int i, int j, int k, AsyncCallback callback) {
        callAsync("foo", callback, new Object[]{i, j, k});
    }
}

And I tried using the new method.

    a.foo(1, 2, 3, new AsyncCallback() {

        @Override
        public void onComplete(Object response) {
            System.out.println(response);
        }
    });

It should return the string "3" to stdout. But instead it threw Exception

java.lang.NoSuchMethodException: Impl.foo(java.lang.Integer, java.lang.Integer, java.lang.Integer)

Why this happens and how to fix this?





lundi 18 avril 2016

Java reflection, get the name of a generic class parameter

I would like to get the name of a generic parameter of a class. For instance :

public class A<B> {
...
}

and in this class i would like to the name of the class B. Like :

A<Solution> var = new A<Solution>();

I would like to have a way to have the String "Solution" somewhere in a method of A

If you have any idea i am here :)

Thank you !





More than one method with the same parameter types in a class

I know, there is already at least one question on this topic. But I want to ask it again because this is what I discovered in the javadoc of Class#getDeclaredMethod(...):

If more than one method with the same parameter types is declared in a class, and one of these methods has a return type that is more specific than any of the others, that method is returned; otherwise one of the methods is chosen arbitrarily.

So the developers of the reflection in java consider that case as a probable one, is it maybe possible after all to do such declaration? Or is it maybe just deprecated?





How to assign the value returned by Expression.Call() to a ParameterExpression?

I have the following code :

var factory = Expression.Parameter(typeof(FooFactory));
var fooInstance = Expression.Variable(typeof(Foo));

var factoryCall = Expression.Call(factory, "Instantiate", new[] { typeof(Foo) });
Expression.Assign(fooInstance, factoryCall); 

List<Expression> expressions = new List<Expression>();
// TODO : add more expressions to do things on fooInstance ...//

expressions.Add(fooInstance); //return fooInstance
Expression finalExpr = Expression.Block(new[] { fooInstance }, expressions);

What it is supposed to do :

  1. Use factory given as parameter and call Instantiate<T>() method on it.
  2. Store the returned value (a foo instance) to a local variable.
  3. Do things on that local variable (missing in that example)
  4. Return the instance

The problem is : when I compile and call the expression, Instantiate() is never called. The value returned is always null :

var method = Expression.Lambda<Func<FooFactory, Foo>>(finalExpr, factory).Compile();
Foo foo = method(new FooFactory());  //foo is null :(