Reflection type mismatch

2019-08-22 04:43发布

问题:

I have compiled a class at runtime which I would like to use on the fly, provided that its constructor takes one parameter

package com.notmycompany;

import com.mycompany.Manager;
import com.mycompany.Processor;

import com.mycompany.Event;

public class CustomProcessor extends Processor {


    public CustomProcessor( Manager m) {
        super( m);
    }

    @Override
    public void process( Event evt) {
        // Do you own stuff
        System.out.println( "My Own Stuff");
    }
}

Compilation goes fine and I can load the class right away. But the constructor is giving me a hard time.

Class<?> clazz = urlClassLoader.loadClass("com.notmycompany.CustomProcessor");
Constructor<?> constructor = clazz.getConstructor( com.mycompany.Manager.class);
this.customProcessor = (Processor) constructor.newInstance( this.manager);

In this case, getConstructor throws a NoSuchMethodException

I tried using getConstructors instead, which only gets me one step further with IllegalArgumentException during newInstance call (of course this.manager is com.mycompany.Manager)

Constructor<?> list[] = clazz.getConstructors();
Constructor<?> constructor = list[0];
this.customProcessor = (Processor) constructor.newInstance( this.manager);

Watever I do, there is a mismatch between Manager object at runtime and compilation
How can I fix this constructor signature?

Edit 1: getParameterTypes output

        for( Class<?> c : constructor.getParameterTypes()) {
            System.out.println( c);
        }

outputs

class com.mycompany.Manager


Edit 2: I removed constructor parameter as a temporary workaround

Now the code throws ClassCastException complaining that com.notmycompany.CustomProcessor cannot be cast to com.mycompany.Processor when constructor is invoked:

Constructor<?> constructor = clazz.getConstructor();
this.customProcessor = (Processor) constructor.newInstance();

This all seems to be part of the same problem where runtime classes seem inconsistent with compilation's, although names match.

回答1:

Your CustomProcessor class has no constructor because the name of the method you believe to be your constructor is different.

public CustomLatencyProcessor(Manager m) {
    super(m);
}

Should be changed to

public CustomProcessor(Manager m) {
    super(m);
}

Because the name of your class is CustomProcessor. Constructor's names must match the name of their containing class exactly.



回答2:

I have been able to get it to work eventually after using a URL that uses the currentThread as parent (as opposed to a URLClassLoader created from scratch with URLs)

URLClassLoader ucl = (URLClassLoader)Thread.currentThread().getContextClassLoader();
URLClassLoader ucl2 = new URLClassLoader( new URL[] { new URL( "file://d:/temp/")},ucl);
Class<?> clazz = ucl2.loadClass("com.notmycompany.CustomProcessor");

I hope this can save you 2 days!