0

I am trying to inject an instance of a CDI managed bean with constructor parameters. I have annotated a constructor that takes parameters with @Inject, for example :-

@Stateless
public class ShoppingCart {

  int capacity;

  ShoppingCart(){};

  @Inject
  ShoppingCart(int capacity) {
    this.capacity = capacity;
  }
'
'
}

How can I inject a shoppingCart instance into another CDI managed bean so that I actually have a ShoppingCart instance I can call other methods on? equivalent to :-

 ShoppingCart sc = new ShoppingCart(10);

All the examples seem to just access properties in the referenced bean and don't actually obtain an instance of the bean itself, e.g. from 3.7. Bean constructors

@SessionScoped
public class ShoppingCart implements Serializable {
    private User customer;

    @Inject
    public ShoppingCart(User customer) {
        this.customer = customer;
    }

    public ShoppingCart(ShoppingCart original) {
        this.customer = original.customer;
    }

    ShoppingCart() {}

    ...
}

@ConversationScoped
public class Order {
    private Product product;
    private User customer;

    @Inject
    public Order(@Selected Product product, User customer) {
        this.product = product;
        this.customer = customer;
    }

    public Order(Order original) {
        this.product = original.product;
        this.customer = original.customer;
    }

    Order() {}

    ...
}

The Order instance does not end up with a ShoppingCart object on which it could call ShoppingCart methods which you would end up with if you did

@Inject
ShoppingCart cart;

but of course this then requires you to use a setter method to pass in the capacity value afterwards with a setter method :-

cart.setCapacity = 10; 

There seems some doubt in my mind if it's actually possible to @Inject a bean with constructor parameters? I haven't found an example yet, any help always appreciated.

Community
  • 1
  • 1
mikee
  • 335
  • 3
  • 11

2 Answers2

-1

You need to use producer method for such case.

First , define a qualifier for this type of shopping cart (shopping cart with 10 capacity):

@Qualifier
@Target({ ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface TenCapacity {
} 

Then define the producer method for how to create this type of shopping cart :

public class ShoppingCart {

    int capacity;

    ShoppingCart() {
    };

    public ShoppingCart(int capacity) {
        this.capacity = capacity;
    }

    @Produces
    @TenCapacity
    public static ShoppingCart newTenCapacityShoppingCart() {
        return new ShoppingCart(10);
    }
}

Then inject this type of shopping cart using the qualifier

 @Inject
 @TenCapacity
 private ShoppingCart shoppingCart; 

If you need to inject many shopping carts with different capacity , you can consider to use InjectionPoint to avoid creating many different qualifers. Please see this for the idea.

Community
  • 1
  • 1
Ken Chan
  • 84,777
  • 26
  • 143
  • 172
-1

Producers are probably a way to go here.

Firstly, if you are only creating a given few types of ShoppingCart, you might want to create a set of producers with qualifiers such as:

@Qualifier
@Target({TYPE,METHOD,PARAMETER,FIELD})
@Retention(RUNTIME)
public @interface Basic {
}

And a producer giving you this basic shopping cart would look like this:

@Produces
@Basic
public ShoppingCart createBasicShoppingCart() {
    return new ShoppingCart(10); //assuming 10 is desired "basic" value
}

If, however, you wish to have a control over the capacity while creating the object, CDI cannot help you directly. You need to create a logic which will determine this capacity and put this logic into the producer. Also, according to CDI spec:

A producer method may have any number of parameters. All producer method parameters are injection points.

Therefore you are free to inject, say, Order into this producer and use its meta-data to determine the cart capacity.

@Produces
@Custom // assuming you created this qualifier
public ShoppingCart createShoppingCart(Order order) {
    int desiredCapacity;
    // determine desired capacity
    // you can use any data from injected parameters
    // as well as data from bean declaring this producer
    desiredCapacity = order.getAllProducts.size();
    return new ShoppingCart(desiredCapacity);
}
Siliarus
  • 6,393
  • 1
  • 14
  • 30
  • Thank you (and @Ken Chan) for your detailed explanation, much appreciated. Can you verify that because we are using the \@Produces annotation even though we are using **new ShoppingCart**, the injected ShoppingCart is managed by CDI and so can still use \@Inject if it needs to? – mikee Jun 09 '16 at 22:14
  • @mikee I am not sure I understand your question? You mean if CDI will still manage the bean even if you have a producer which creates the bean with `new` keyword? If so, the answer is **yes**. As long as you create it with producer, CDI will manage it and you can use `@Inject`. – Siliarus Jun 13 '16 at 06:32