I'm trying to upgrade from CDI 1.0 to CDI 1.2 but i'm facing the following problem:
org.jboss.weld.exceptions.UnserializableDependencyException: WELD-001413: The bean Managed Bean [class ViewProcessContext] with qualifiers [@Default @Named @Any] declares a passivating scope but has a non-passivation-capable dependency Producer Method [ConfigurationReader] with qualifiers [@Default @Any] declared as [[BackedAnnotatedMethod] @Produces @Default @Singleton public ConfigurationReaderProducer.process()]
at org.jboss.weld.bootstrap.Validator.validateInjectionPointPassivationCapable(Validator.java:442)
at org.jboss.weld.bootstrap.Validator.validateInjectionPointForDeploymentProblems(Validator.java:380)
at org.jboss.weld.bootstrap.Validator.validateInjectionPoint(Validator.java:277)
at org.jboss.weld.bootstrap.Validator.validateGeneralBean(Validator.java:130)
at org.jboss.weld.bootstrap.Validator.validateRIBean(Validator.java:151)
at org.jboss.weld.bootstrap.Validator.validateBean(Validator.java:494)
at org.jboss.weld.bootstrap.ConcurrentValidator$1.doWork(ConcurrentValidator.java:64)
at org.jboss.weld.bootstrap.ConcurrentValidator$1.doWork(ConcurrentValidator.java:62)
at org.jboss.weld.executor.IterativeWorkerTaskFactory$1.call(IterativeWorkerTaskFactory.java:62)
at org.jboss.weld.executor.IterativeWorkerTaskFactory$1.call(IterativeWorkerTaskFactory.java:55)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
The codes, which works fine on CDI 1.0, are the following:
Where the error happens:
@Named
@ConversationScoped
public class ViewProcessContext implements Externalizable {
//...
@Inject
private ConfigurationReader compReader;
//...
}
Injected dependency:
public interface ConfigurationReader extends Serializable {
}
Producer:
@ApplicationScoped
public class ConfigurationReaderProducer implements Externalizable {
//...
@Produces
@Default
@Singleton
public ConfigurationReader process() {
}
}
According to CDI spec:
A producer method is passivation capable if and only if it never returns a value which is not passivation capable at runtime.
So my producer always returns a passivation capable instance.
I can't understand why Weld complains about it.
What is invalid about the producer or the dependency in this case?
Hm, I could reproduce your problem. I re-read CDI 1.0 and 1.2 specs. CDI 1.2 is actually somewhat clearer than CDI 1.0 and the changings in Weld are, as far as I can see, quite correct.
See http://docs.jboss.org/cdi/spec/1.2/cdi-spec.html#passivating_scope
First: Validation of producer-methods:
6.6.5.Validation of passivation capable beans and dependencies
If a producer method declares a passivating scope and:
- has a return type that is declared final and does not implement or extend Serializable, or,
- has an injection point that is not passivation capable.
6.6.1.Passivation capable beans
A producer method is passivation capable if and only if it never returns a value which is not passivation capable at runtime.
Conclusion: A producer method MUST always be annotated with a passivation capable annotation if you want to use the result in a passivation capable scope.
Well, which scopes are passivation capable? Answer: Only Session and conversation scopes plus your own ones that declare @NormalScope(passivating=true). Means, @Singleton is NOT (See 6.6.4.Passivation scopes).
You maybe can work around that problem, but:
Do you really want the Singleton to be used in your conversationScope bean? When you conversationScoped-Bean will be passivated, your Singleton will be as well. You need to implement readResolve and writeReplace (see Serializable Api) to truly create a singleton. There will be no proxy object around it.
Rethink your solution, in most cases an (proxied) applicationScoped-Object is what you want.
Nevertheless, you actually can inject a @Singleton-Bean into a @ConversationScope via the standard @Inject mechanism (no producer, just plain inject). Please note, that a @Singleton-bean won't be automatically detected with a beans.xml and bean-discovery-mode="annotated" (and you need readResolve etc. as stated).
Finally: Does it make sense that you can plain-inject a singleton but cannot via producer method? I'd say: no. But that's how it's written in the spec, I'm sorry.
Good luck.