8

I have a @RequestScoped CDI bean that I want to turn into an EJB to get declarative transactions. (I'm on EJB 3.1, Java EE 6)

Currently, I am passing state between subroutines, under the assumption that the instance is only used in a single request. If I add @Stateless now that assumption would change.

For example, I want to do something like

@Stateless
@Named
@RequestScoped
public class Foo {
  private String var1; // can't use instance vars in @Stateless?
  private String var2;

  public void transactionForRequest() {
    var1 = value; 
    var2 = value;
    ....
    subroutine();
  }
}

I assume the above doesn't work- is that correct?

I am contemplating two alternatives:

  • Use @Stateful instead of @Stateless, along with @Named and @RequestScoped.
  • Keep @Stateless and use EJBContext.getContextData map to replace instance variables.

Which is better? And is there some other alternative I'm not thinking of? (Besides wait for Java EE 7 or switch to Spring. :-))

wrschneider
  • 17,913
  • 16
  • 96
  • 176
  • Using `@Stateful` may be an over-skill. Have you considered using normal Stateless bean and `@ConversationScoped` managed bean to pass states? – Mr.J4mes Jan 03 '12 at 09:05
  • how would this work - would you make the EJB `@Stateless` then `@Inject` a CDI bean? Could this CDI bean be `@RequestScoped`? – wrschneider Jan 03 '12 at 16:15
  • I'd keep the bean as `@Stateless` and use `@ConversationScoped` bean to pass variables from pages to pages. Check out this [article](http://blog.goyello.com/2011/06/08/jee6-cdi-and-conversation-scope/) about creating wizard. – Mr.J4mes Jan 03 '12 at 16:22
  • I'm not trying to have a wizard-like conversation - I'm trying to pass variables between subroutines in the scope of a single HTTP request / DB transaction. – wrschneider Jan 03 '12 at 18:31
  • If so, `@SessionScoped` bean with Stateless bean may still be easier to manage than Stateful bean. – Mr.J4mes Jan 03 '12 at 18:36

3 Answers3

12

While @Stateless, @Singleton and @MessageDriven can have scoped references injected via @Inject, they cannot be @RequestScoped or any other scope. Only the @Stateful model is flexible enough to support scopes. In other words, you can annotate the @Stateful bean class itself as @RequestScoped, @SessionScoped, etc..

In simple terms @Stateless, @Singleton have fixed "scopes" already. @Singleton is essentially @ApplicationScoped and @Stateless would perhaps be some made-up scope like @InvocationScoped, if that existed. The lifecycle of an @MessageDriven bean is entirely up to the Connector that drives it and is therefore also not allowed to have user-defined scope.

See also https://stackoverflow.com/a/8720148/190816

Community
  • 1
  • 1
David Blevins
  • 19,178
  • 3
  • 53
  • 68
  • David, just to be sure - If I have `@RequestScoped` reference to `@Stateless` EJB - what does it buy me? I'll get the same reference during the whole request, but it's still (probably) a reference to proxy, so each time I use this reference, I can end in different EJB instance. Is this correct? – Piotr Nowicki Jan 04 '12 at 00:21
  • Exactly. To put it into perspective, in OpenEJB we only create one proxy for each Stateless bean and share with the entire app. Same for Singleton. In the case of putting RequestScoped (or other scope) on a Stateless or Singleton, it should be treated as an error at deployment. I'd have to double check the spec and TCK on that, but that's certainly the way I'd do it. Anything else is just misleading. – David Blevins Jan 04 '12 at 04:35
  • Thanks for clarification David. It's just another time when connection between EJB and CDI can be disorienting... – Piotr Nowicki Jan 04 '12 at 08:47
  • Hadn't thought of this before, but it might be interesting to sort of retroactively declare Singleton as a form of Stereotype and annotate it with ApplicationScoped. Might be a tad bit clearer that it does in fact have a scope and that scope cannot be changed. – David Blevins Jan 04 '12 at 21:48
  • That sounds reasonable. It would not break the EJB spec and make Singleton EJB just a special case of CDI bean. I hope that EE 7 will reorganise this thing. It would be great if it would be possible to map SLSB and SFSB to some CDI stereotype in such a way. Then the CDI context would really make a central part of every type of beans in EE. – Piotr Nowicki Jan 04 '12 at 22:15
3

I would go with SFSB instead of SLSB. You want to hold a state, so for me this is the most important information - this is a job for Stateful EJB.

Also I don't think that EJBContext#getContextData() would help you. As far as I remember, it's only valid for a duration of a call. Therefore, each invocation of a method on your EJB will create new context data map (at least it's what I would expect.)

Piotr Nowicki
  • 17,914
  • 8
  • 63
  • 82
  • Glad to hear @Stateful + @RequestScoped would work - for whatever reason, "stateful session bean" still sounds like a dirty word but "request-scoped session bean" sounds much better. Also - `EJBContext#getContextData()` works fine for me in this situation because the subroutine is a local method call (`this.subroutine()`) rather than an EJB invocation. – wrschneider Jan 05 '12 at 15:51
  • You're right - if its local call than context data is fine. I thought you did inject your EJB (`@EJB` or `@Inject`) and invoked several methods on the proxy instance. – Piotr Nowicki Jan 05 '12 at 16:34
1

If you are using Stateless beans then you are responsible for any state-management and you would normally do this in the web-app layer using HttpSessions. And yes, you can't use instance variables as stateless beans are pooled.

Aravind Yarram
  • 78,777
  • 46
  • 231
  • 327