[weld-dev] How to make method injection when bean subclass is required in Weld?

Matej Novotny manovotn at redhat.com
Wed Aug 30 05:45:07 EDT 2017


Hi Alex

What you suggest will inevitably fail for the reasons we mentioned previously.
Both approaches will try to resolve a bean of type SimpleFoo which is ambiguous.

Furthermore, doing `foo = new Foo()` is like saying "goodbye CDI".
If you do this, you control the lifecycle of such object, not CDI.
Therefore, there will be no injection done into such object, neither will CDI be able to dispose of such object.

Matej

----- Original Message -----
> From: "Alex Sviridov" <ooo_saturn7 at mail.ru>
> To: "weld-dev" <weld-dev at lists.jboss.org>
> Sent: Wednesday, August 30, 2017 11:10:27 AM
> Subject: Re: [weld-dev] How to make method injection when bean subclass is required in Weld?
> 
> 
> 
> Hi Matej,
> 
> I meant the following (in previous example I had a mistake - called Parent
> Child and Child Parent)
> , now without this mistake:
> 1)
> public class Parent {
> 
> @Inject
> private Instance<SimpleFoo> fooInstance;
> 
> private SimpleFoo foo;
> 
> protected SimpleFoo newFoo() {
> return fooInstance.get();
> }
> 
> @PostConstruct
> private void doPostConstruct() {
> foo = newFoo();
> }
> }
> 
> public class Child extends Parent {
> 
> @Inject
> private Instance<AdvancedFoo> fooInstance;
> 
> @Override
> protected AdvancedFoo newFoo() {
> return fooInstance.get();
> }
> }
> 
> 
> 2)
> 
> public class Parent {
> 
> @Inject
> protected BeanManager beanManager;
> 
> private SimpleFoo foo;
> 
> protected SimpleFoo newFoo() {
> SimpleFoo foo = constructing bean with BM;
> return foo;
> }
> 
> @PostConstruct
> private void doPostConstruct() {
> foo = newFoo();
> }
> }
> 
> public class Child extends Parent {
> 
> @Override
> protected AdvancedFoo newFoo() {
> AdvancedFoo foo = constructing bean with BM;
> return foo;
> }
> }
> 
> Thank you for your explanation of Typed. I got it.
> 
> Best regards, Alex
> 
> 
> Среда, 30 августа 2017, 10:51 +03:00 от Matej Novotny <manovotn at redhat.com>:
> 
> 1) If you inject Instance<T>, you still have the ambiguous dependency issue
> for any class which does have a subclass.
> E.g. from your sample:
> 
> @Inject
> Instance<SimpleFoo> instance;
> 
> //within some method
> instance.get(); -> this will blow up because you have two beans which have
> SimpleFoo type (SimpleFoo and AdvancedFoo)
> 
> 2) I don't understand what you mean by this. How does BM help here?
> 
> 
> Sidenote:
> You might want to try and use what Martin said - limiting the types of a bean
> with @Typed(MyClass.Foo).
> That way you have control over the bean types and can further manupulate the
> injection.
> Limit all your children to only the actual subclass type they have:
> 
> @Dependent
> @Typed(AdvancedFoo.class)
> public class AdvancedFoo extends SimpleFoo {
> // this ben now only has a bean of AdvancedFoo, e.g. it does not fit into
> injection point for SimpleFoo
> }
> 
> And then override the initializer methods like this:
> 
> @Dependent
> public class Parent extends Child {
> 
> @Inject
> @Override
> protected void setFoo(AdvancedFoo foo) {
> this.foo = foo; // assuming foo is a protected field
> }
> }
> 
> Matej
> 
> 
> ----- Original Message -----
> > From: "Alex Sviridov" < ooo_saturn7 at mail.ru >
> > To: "weld-dev" < weld-dev at lists.jboss.org >
> > Sent: Tuesday, August 29, 2017 8:54:47 PM
> > Subject: Re: [weld-dev] How to make method injection when bean subclass is
> > required in Weld?
> > 
> > I thought here, and would like to share my ideas hoping to get comments
> > from
> > more experienced people.
> > 
> > First of all I came to conclusion that CDI works badly with cases when we
> > need
> > to change field values in super classes. If there is a lot of inheritance
> > as
> > in my case:
> > ParentA, ChildA0, ChildA1.., ParentB, ChildB0, ChildB1..,... then situation
> > is
> > becoming very bad. Maybe in future there will be other solutions in CDI
> > specs.
> > 
> > I found two additional ways that can be used. 1) Inject not beans but
> > instances,
> > + method SimpleFoo newFoo {return Instance<SimpleFoo>.get} + overriding.
> > 2) Inject BeanManager + method SimpleFoo newFoo() {beanManager...} +
> > overriding.
> > 
> > Maybe such ways can be named lazy/postponed initialization with overriding
> > support....
> > 
> > Best regards, Alex
> > 
> > 
> > 
> > 
> > Вторник, 29 августа 2017, 18:22 +03:00 от Martin Kouba < mkouba at redhat.com
> > >:
> > 
> > Hi Alex,
> > 
> > that's an interesting question. Indeed, qualifiers are the way to go if
> > you need to keep the method signature.
> > 
> > Another way could be to override the setFoo() method so that the Child
> > initializer is ignored and add a new method to inject AdvancedFoo:
> > 
> > @Override
> > protected void setFoo(SimpleFoo foo) { // Do nothing }
> > 
> > @Inject
> > void setAdvancedFoo(AdvancedFoo foo) {
> > super.setFoo(foo);
> > }
> > 
> > However, note that right now there are the following beans:
> > 
> > SimpleFoo with bean types Object, SimpleFoo
> > AdvancedFoo -> Object, SimpleFoo, AdvancedFoo
> > 
> > So if you do @Inject SimpleFoo you get ambiguous dependency exception
> > because both SimpleFoo and AdvancedFoo are eligible for injection.
> > 
> > To resolve this you need to use qualifiers or restrict the bean types of
> > AdvancedFoo:
> > 
> > @Typed(AdvancedFoo.class)
> > class AdvancedFoo extends SimpleFoo {}
> > 
> > HTH
> > 
> > Martin
> > 
> > 
> > Dne 29.8.2017 v 15:09 Matej Novotny napsal(a):
> > > Hi Alex,
> > > 
> > > no need to be sorry, you have come to the right place :)
> > > As for your question, the simplest thing is probably to use qualifiers.
> > > 
> > > Create your own like this:
> > > 
> > > @Qualifier
> > > @Retention(RetentionPolicy.RUNTIME)
> > > @Target({ ElementType.TYPE, ElementType.PARAMETER, ElementType.FIELD,
> > > ElementType.METHOD })
> > > public @interface MyQualifier {}
> > > 
> > > 
> > > And then change your AdvancedFoo class to use the qualifier:
> > > 
> > > @Dependent
> > > @MyQualifier
> > > public class AdvancedFoo extends SimpleFoo {
> > > }
> > > 
> > > And accordingly, the init method which uses injection should then look
> > > like
> > > this:
> > > 
> > > @Dependent
> > > public class Parent extends Child {
> > > 
> > > @Inject
> > > @Override
> > > protected void setFoo(@MyQualifier SimpleFoo foo) {
> > > super.setFoo(foo);
> > > }
> > > }
> > > 
> > > Does this answer your question?
> > > 
> > > Matej
> > > 
> > > ----- Original Message -----
> > >> From: "Alex Sviridov" < ooo_saturn7 at mail.ru >
> > >> To: "weld-dev" < weld-dev at lists.jboss.org >
> > >> Sent: Tuesday, August 29, 2017 1:46:23 PM
> > >> Subject: [weld-dev] How to make method injection when bean subclass is
> > >> required in Weld?
> > >> 
> > >> Hi all,
> > >> 
> > >> I am really sorry for writing to this mailing list, but I checked all
> > >> user
> > >> forums and chats and saw that they are very old.
> > >> 
> > >> I would be very thankful if someone gives suggestion for solving the
> > >> following problem.
> > >> I have a child and parent class. Child has SimpleFoo, Parent needs
> > >> Advaced
> > >> foo. So,
> > >> 
> > >> @Dependent
> > >> public class SimpleFoo {
> > >> }
> > >> 
> > >> @Dependent
> > >> public class AdvancedFoo extends SimpleFoo {
> > >> }
> > >> 
> > >> @Dependent
> > >> public class Child {
> > >> 
> > >> private SimpleFoo foo;
> > >> 
> > >> @Inject
> > >> protected void setFoo(SimpleFoo foo) {
> > >> this.foo = foo;
> > >> }
> > >> }
> > >> 
> > >> @Dependent
> > >> public class Parent extends Child {
> > >> 
> > >> @Inject
> > >> @Override
> > >> protected void setFoo(SimpleFoo foo) { //How to inject here AdvancedFoo?
> > >> super.setFoo(foo);
> > >> }
> > >> }
> > >> 
> > >> How to inject in Parent AdvancedFoo? I know that I can do it via
> > >> constructor
> > >> injection
> > >> but I need method injection. How to do it? Can it be done without using
> > >> names
> > >> (like MyBean1)
> > >> but only using classes (AdvancedFoo)?
> > >> 
> > >> Best regards, Alex
> > >> 
> > >> 
> > >> 
> > >> 
> > >> 
> > >> --
> > >> Alex Sviridov
> > >> 
> > >> _______________________________________________
> > >> weld-dev mailing list
> > >> weld-dev at lists.jboss.org
> > >> https://lists.jboss.org/mailman/listinfo/weld-dev
> > > _______________________________________________
> > > weld-dev mailing list
> > > weld-dev at lists.jboss.org
> > > https://lists.jboss.org/mailman/listinfo/weld-dev
> > > 
> > 
> > --
> > Martin Kouba
> > Senior Software Engineer
> > Red Hat, Czech Republic
> > 
> > 
> > _______________________________________________
> > weld-dev mailing list
> > weld-dev at lists.jboss.org
> > https://lists.jboss.org/mailman/listinfo/weld-dev
> 
> 
> _______________________________________________
> weld-dev mailing list
> weld-dev at lists.jboss.org
> https://lists.jboss.org/mailman/listinfo/weld-dev



More information about the weld-dev mailing list