简体   繁体   中英

Java enum anonymous inner class and reflection

I have an enum with anonymous inner class like:

public enum Status {

    PRELIMINARY() {
    @Override
    boolean process() {
        return true;
    }

    SUBMITTED() {
    @Override
    boolean process() {
        return false;
    }

    abstract boolean process();

}

I have a model like

public class Foo {

    private Status status;

    public void setStatus(Status status) {
        this.status = status;
    }
}

I need to use reflection to set a Foo.status like:

private static <T> void setFieldValue(Foo instance, Class<?> klazz, Object value) {
    try {
        Class<?> aClass = value.getClass(); // Is Status$1 instead of Status
        Method method = klazz.getDeclaredMethod(getSetterName('setStatus'), aClass);
        method.invoke(instance, value);
    } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
        if (!klazz.equals(Object.class)) {
            setFieldValue(instance, klazz.getSuperclass(), fieldName, value);
        }
    }
}

This works when Status does not contain an inner class and is a simple enum, however for the above Status class it will throw a NoSuchMethodException . This is because the class of my value will be package.Status$1 instead of package.Status .

Is there a good work around for this?

You just need to change your means of locating the desired method. Something like the following should work:

private static @Nullable Method findMethod(Class<?> klass,
                                           final String methodName,
                                           final Object... args) {

    @Nullable Method candidate = null;

    classSearch:
    while (klass != null) {

        // Check all the class' methods for a matching one.
        methodSearch:
        for (final Method method : klass.getDeclaredMethods()) {
            if (!method.getName().equals(methodName)) continue;

            final Class<?>[] parameterTypes = method.getParameterTypes();
            if (parameterTypes.length != args.length) continue;

            // Check all parameters can come from the given args.
            for (int i = 0; i < args.length; i++) {
                if (!parameterTypes[i].isInstance(args[i])) continue methodSearch;
            }

            candidate = method;
            break classSearch;
        }

        // No matching method, check super class.
        klass = klass.getSuperclass();
    }

    // May be 'null' if no match was found.
    // Throw an Exception if this isn't a valid outcome in your case.
    return candidate;
}

Chaining this with your existing code (calling .invoke on the returned Method (if it's not null )) should give you the desired outcome.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM