0

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?

RicardoS
  • 2,088
  • 1
  • 21
  • 22

2 Answers2

1

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.

markus_
  • 480
  • 3
  • 12
  • Great explanation @markus_ ! The point really was scope on the Producer. I've changed to ApplicationScoped. Although I couldn't understand why Singleton and AplicationScoped work on a different way... – RicardoS Mar 16 '17 at 19:59
  • I'm still in doubt if Weld should verify my fields in this case, because I use the Externalizable interface for a fine/manual Serialization, instead of the reflection one (Serializable). So, for me, it shouldn't check my fields when using Externalizable – RicardoS Mar 16 '17 at 20:04
0

In your facade of class ConfigurationReaderFacde add @Stateless

@Stateless public class ConfigurationReaderFacde extends AbstractFacade<ConfigurationReaderFacde> { }
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Mar 06 '22 at 09:32