Hi Martin

Thank you very much for your comment and suggestion about improving.

Best regards, Alex


Четверг, 31 августа 2017, 12:50 +03:00 от Martin Kouba <mkouba@redhat.com>:

Hi Alex,

1) should work but looks a little bit cumbersome. WRT 2) you should
avoid using BeanManager to create a bean instance whenever possible. And
in this particular case, if SimpleFoo is @Dependent it wouldn't be
destroyed correctly (@PreDestroy) when Parent or Child is destroyed.

The following should also work (no need to have two Instance IPs):

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 {

       @Override
       protected AdvancedFoo newFoo() {
             return fooInstance.select(AdvancedFoo.class).get();
       }
  }


Martin

Dne 31.8.2017 v 11:07 Alex Sviridov napsal(a):
> Hi Martin,
>
>
> Could you comment the following solutions?
>
> 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;
> }
> }
>
>
> Best regards, Alex
>
> Среда, 30 августа 2017, 10:51 +03:00 от Matej Novotny
> <manovotn@redhat.com <mailto:manovotn@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@mail.ru
> <mailto:ooo_saturn7@mail.ru>>
> > To: "weld-dev" <weld-dev@lists.jboss.org
> <mailto:weld-dev@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@redhat.com <mailto:mkouba@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@mail.ru
> <mailto:ooo_saturn7@mail.ru> >
> > >> To: "weld-dev" < weld-dev@lists.jboss.org
> <mailto:weld-dev@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@lists.jboss.org <mailto:weld-dev@lists.jboss.org>
> > >> https://lists.jboss.org/mailman/listinfo/weld-dev
> > > _______________________________________________
> > > weld-dev mailing list
> > > weld-dev@lists.jboss.org <mailto:weld-dev@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@lists.jboss.org <mailto:weld-dev@lists.jboss.org>
> > https://lists.jboss.org/mailman/listinfo/weld-dev
>
>
>
> ------------------------------------------------------------------------
>
> --
> Alex Sviridov

--
Martin Kouba
Senior Software Engineer
Red Hat, Czech Republic


--
Alex Sviridov