Can an EJB3 bean "self inject" and call its own methods via EJB container?
Asked Answered
K

5

14

Is it possible to "self inject" an EJB in order to call local methods as bean methods? There are some cases where this could be favorable, for example if container managed transactions are used and something should be accomplished in a new transaction.

An example how this could work:

Foo.java:

@Local
public interface FoO {
    public void doSomething();
    public void processWithNewTransaction(); // this should actually be private
}

FooBean.java:

@Stateless
public class FooBean implements Foo {

    @EJB
    private Foo foo;

    public void doSomething() {
        ...
        foo.processWithNewTransaction();
        ...
    }

    @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
    public void processWithNewTransaction() {
        ...
    }
}

If I extract processWithNewTransaction() to another bean, it would need to be exposed as a public method in the interface, even though it should be called only by FooBean. (The same issue is with my code above, that's why there is a comment in the interface definition.)

One solution would be to switch to bean managed transactions. However this would require changing the whole bean to manage its own transactions, and would add a lot of boiler plate to all methods.

Krebs answered 11/3, 2009 at 8:0 Comment(2)
As an addition to the answers below: If you do not want to have the method with new transaction in your local interface, you can annotate your bean implementation with both @Local(Foo.class) and @LocalBean and have the method as public method in the implementation class only.Thankyou
OP - Please update this to uncheck the selected answer which is incorrect.Laundress
Z
2

Update: As noted by other answers, this is indeed technically possible. Please see the answers of Csaba and Michael on how and why it works despite the apparend endless recursion.


I cannot give a 100% accurate answer but I'm pretty sure that this is not possible.

I think so because for injecting the Foo bean into the Foo bean itself the container would initially have to create a Foo instance which he can inject afterwards. But to create this he has to inject an already existing instance of Foo into the Foo to be created... which leads to an infinite recursion.

If you need separate transactions I'd suggest to keep things easy and create two independend beans/interfaces.

Zarger answered 11/3, 2009 at 10:39 Comment(5)
Agree! Recursiv definition of session beans is not a good idea.Orchestrion
Though it is suggested to keep things separate, it is indeed possible (see michael nesterenko answer)Restoration
This is possible with ejb 2.1 and 3+. Either you can use '@EJB Foo self;' or you can use @michael nesterenko's suggessionKeating
This answer is just plain wrong and should not be marked as correct.Laundress
@Laundress The technical incorrectness of the answer has been integrated via an update already almost two years ago. It also references the technically more correct answers.Zarger
G
13

It is possible to do a self injection. You need to use SessionContext.

SessionContext sc = ...
sc.getBusinessObject(FooBean.class).processWithNewTransaction()
Grassplot answered 5/1, 2013 at 12:59 Comment(1)
Yes and another possibility is via an @EJB reference to a bean of it's own type here Foo. (see How To Self-Invoke EJB 3.x with(out) "this")Restoration
C
11

Self injection of a EJB is indeed possible. The reason why an infinite recursion won't happen in this case is pretty simple: the container doesn't inject an actual bean instance from the pool. Instead, it injects a proxy object. When you call a method on the injected proxy (foo), the container gets a bean instance from its pool or creates one, if there are no available instances.

Clothes answered 4/9, 2012 at 1:24 Comment(0)
Z
2

Update: As noted by other answers, this is indeed technically possible. Please see the answers of Csaba and Michael on how and why it works despite the apparend endless recursion.


I cannot give a 100% accurate answer but I'm pretty sure that this is not possible.

I think so because for injecting the Foo bean into the Foo bean itself the container would initially have to create a Foo instance which he can inject afterwards. But to create this he has to inject an already existing instance of Foo into the Foo to be created... which leads to an infinite recursion.

If you need separate transactions I'd suggest to keep things easy and create two independend beans/interfaces.

Zarger answered 11/3, 2009 at 10:39 Comment(5)
Agree! Recursiv definition of session beans is not a good idea.Orchestrion
Though it is suggested to keep things separate, it is indeed possible (see michael nesterenko answer)Restoration
This is possible with ejb 2.1 and 3+. Either you can use '@EJB Foo self;' or you can use @michael nesterenko's suggessionKeating
This answer is just plain wrong and should not be marked as correct.Laundress
@Laundress The technical incorrectness of the answer has been integrated via an update already almost two years ago. It also references the technically more correct answers.Zarger
C
2

I'd tend to disagree, often it's useful for transaction management to call a local bean method via the container.

Exactly as the example if you had to call a local bean method inside a loop you'd be better having a transaction per iteration than for all iterations. (provided business logic wasn't "all or nothing" like despatching a delivery, or issuing stock)

Cronk answered 29/7, 2011 at 11:28 Comment(1)
It depends of you business requerimentsCentiliter
D
1

Interesting question. I never create a method with a different transaction attribute in the same bean, that is, this begs for refactoring. This usually makes it hard to spot bugs in the application when it evolves.

EDIT: fixed typos

Drusy answered 13/3, 2009 at 0:21 Comment(2)
It doesn't even matter whether or not you need to have a different TX attribute. If you simply want to factor your logic such that it makes sense for one method to call another you will run into this if for example you are passing entities (which need to remain in a managed state) or wish to exist with the same TX as the caller or you wish interceptors to be called. If you don't use the proxy none of those things will happen.Laundress
@NBW: I'm not questioning if it will happen or not. I'm just saying it makes your code harder to read and increases the chance of invoking the method incorrectly because now you can do in more than one way. Having a separate component make it easier to maintain. Your mileage may vary though.Drusy

© 2022 - 2024 — McMap. All rights reserved.