jeudi 1 octobre 2020

Subclass field injection from superclass constructor

In the following example, we have an abstract class AutoInject where the constructor analyzes the child class being instantiated and injects values into fields annotated with @Inject:

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Field;

public abstract class AutoInject {
    public AutoInject() {
        for (Field field : getClass().getDeclaredFields()) {
            field.setAccessible(true);
            if (field.isAnnotationPresent(Inject.class) && field.getType() == String.class) {
                try {
                    field.set(this, "Hello from field " + field.getName());
                } catch (IllegalAccessException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }

    public static final class Impl extends AutoInject {
        @Inject
        private String autoInjectedField;
    }

    @Retention(RetentionPolicy.RUNTIME)
    @interface Inject {}

    public static void main(String[] args) {
        Impl instance = new Impl();
        System.out.println(instance.autoInjectedField);
    }
}

It appears to function as expected (i.e. outputting "Hello from field autoInjectedField") in JDK11, but the mere act of having a superclass constructor tampering with the fields of a still-in-the-process-of-being-initialized subclass instance positively reeks of "surely this must be undefined behavior". I have however not found any explicit information about whether or not this behavior can be relied upon.

Is something like this even remotely safe, or should one expect it to randomly break in future versions and/or across different JVM implementations?





Aucun commentaire:

Enregistrer un commentaire