The following code runs successfully but the value isn't changed when the reference is an applicationscoped bean. When the bean is a Singleton EJB the value does change.
Changing the value via AnnotatedParameter and Method.invoke does change the value.
Does anyone know what might cause the difference in behaviour? I cannot find the reason in (java)docs, specs or elsewhere.
InjectionPoint ip = ....;
Class bc = ip.getMember().getDeclaringClass();
Object reference = CDI.current().select(bc).get();
Annotated a = ip.getAnnotated();
Object value = ....;
if (annotated instanceof AnnotatedField af) {
Field f = af.getJavaMember();
try {
boolean ac = f.canAccess(reference);
f.setAccessible(true);
f.set(reference, value);
f.setAccessible(ac);
} catch (IllegalAccessException e) {
log.error(String.format("error updating %s with %s",
f, value));
}
}
With CDI, the actual instance that's injected is a proxy. It's an instance of a generated sub class of the bean class. That's why CDI has some limitations like requiring a no-arg constructor and no final methods. The generated sub class has a no-arg constructor that calls the no-arg constructor of the bean class (super()
), and each method is overridden. Inside the proxy there is (in some way) a reference to the single instance; the overridden methods each call the same method of this instance.
The reference
you have has all of the fields of the bean class, but if you inspect them in a debugger you'll probably see they are all null
. That's my experience so far. The only field that matters is the internal reference to the single instance. The field you set is simply ignored by the proxy.
With @Singleton
on the other hand, both in JBoss and in Quarkus, there is no proxy. The injected instance is the singleton instance itself.
Some links that document this: