[cdi-dev] CDI and generics

Marko Lukša marko.luksa at gmail.com
Tue Jul 16 03:13:48 EDT 2013


What Arne was concerned about is that we cannot inject the same instance 
into two different typed injection points. We can't have an object that 
is a list of strings and a list of integers at the same time. We would 
need such an object if we wanted to inject it into both @Inject 
List<String> and @Inject List<Integer>.

What I pointed out is that CDI has this covered, as it requires all 
beans with a parameterized bean class to be dependent scoped and by 
definition not sharable across multiple injection points. CDI will 
create a _new instance_ for each injection point, therefore it actually 
can inject bean MyClass<T> into both @Inject MyClass<String> and @Inject 
MyClass<Integer>, since it injects two different instances. There is no 
need to have a custom extension and register MyClass<T> multiple times 
(as MyClass<String>, MyClass<Integer>, etc.).

So this means the change at [1] was a mistake.

[1] 
https://github.com/cdi-spec/cdi/commit/b32243350ace6a0bba337f91a35f5fd05c151f14

Marko

On 16.7.2013 7:17, Romain Manni-Bucau wrote:
>
> Hmm not sure i get the Dependent limit. Using a custom extension 
> you'll register the same bean as many times as needed but using 
> different values for parameters and the scope you want.
>
> Why CDI wouldnt be able of it out of the box?
>
> It is really something basic in 2013 and find really sad that's look 
> so complicated. Please explain me what i'm missing if so.
>
> Le 16 juil. 2013 00:15, "Marko Lukša" <marko.luksa at gmail.com 
> <mailto:marko.luksa at gmail.com>> a écrit :
>
>     Actually, it will never be the same instance, since all beans with
>     a parameterized bean class must be @Dependent scoped.
>
>     Marko
>
>     On 15.7.2013 23:46, Arne Limburg wrote:
>>     No, I understood you right ;-)
>>     In Java the same instance cannot be MyClass<String> and
>>     MyClass<Integer> at the same time.
>>     We would do exactly that, if we had two injection points like
>>     @Inject
>>     MyClass<String> myStringClass;
>>     @Inject
>>     MyClass<Integer> myIntegerClass;
>>     In plain java this could never be the same instances without
>>     heavy (compile-time) casting, thus this should not be the same
>>     instances in CDI.
>>
>>     Cheers,
>>     Arne
>>
>>     Von: Romain Manni-Bucau <rmannibucau at gmail.com
>>     <mailto:rmannibucau at gmail.com>>
>>     Datum: Montag, 15. Juli 2013 23:41
>>     An: Arne Limburg <arne.limburg at openknowledge.de
>>     <mailto:arne.limburg at openknowledge.de>>
>>     Cc: Mark Struberg <struberg at yahoo.de <mailto:struberg at yahoo.de>>,
>>     Martin Kouba <mkouba at redhat.com <mailto:mkouba at redhat.com>>,
>>     "cdi-dev at lists.jboss.org <mailto:cdi-dev at lists.jboss.org>"
>>     <cdi-dev at lists.jboss.org <mailto:cdi-dev at lists.jboss.org>>
>>     Betreff: Re: [cdi-dev] CDI and generics
>>
>>     hmm think you misunderstood what i said (sorry if it was unclear)
>>
>>     basically my point was a generic bean or produced bean should be
>>     injectable everywhere so MyClass<T> should match @Inject
>>     MyClass<String>. In plain java we do: new MyClass<String>().
>>
>>     /Romain Manni-Bucau/
>>     /Twitter: @rmannibucau <https://twitter.com/rmannibucau>/
>>     /Blog: //http://rmannibucau.wordpress.com//
>>     /LinkedIn: //_http://fr.linkedin.com/in/rmannibucau_/
>>     /Github: https://github.com/rmannibucau/
>>
>>
>>
>>     2013/7/15 Arne Limburg <arne.limburg at openknowledge.de
>>     <mailto:arne.limburg at openknowledge.de>>
>>
>>         Hi Romain,
>>
>>         In plain old java the behavior would depend on where the type
>>         variable is declared.
>>         See the following samples:
>>
>>         public class MyClass<T> {
>>
>>           List<T> myList = new ArrayList<T>();
>>
>>           List<String> myStringList = myList;
>>         }
>>
>>         public class MyClass {
>>
>>           <T> List<T> myList() {
>>               return new ArrayList<T>();
>>           }
>>
>>           List<String> myStringList = myList();
>>         }
>>
>>         The first example does not work and the second works.
>>
>>         And even, if you would access myList from outside, the first
>>         example just works, if you instantiate myClass with the type
>>         argument:
>>
>>         List<String> myStringList = new MyClass<String>().myList;
>>
>>         To transfer this to CDI: We would need an instance of Bean
>>         MyClass with MyClass<String> in the type closure. And we
>>         would have to do this for every type argument that can be
>>         found within the injection points, i.e., if we had the
>>         injection points
>>         @Inject
>>         MyClass<String> myStringClass;
>>         @Inject
>>         MyClass<Integer> myIntegerClass;
>>         either the type closure of my class would have to contain
>>         MyClass<String> AND MyClass<Integer> or we would need to have
>>         different beans for both types. I think, we cannot do either.
>>
>>         I suggest to handle TypeVariables declared at class level
>>         different than TypeVariables declared at (producer-)method
>>         level. Thus we could handle Mark Strubergs case and leave the
>>         rest like it is in plain old java.
>>
>>         I suggest to change the fourth bullet point of chapter 5.2.4:
>>         "the required type parameter is an actual type, the bean type
>>         parameter is a type variable that is declared at class level
>>         and the actual type is assignable from the upper bound of the
>>         type variable,"
>>         and add another bullet point:
>>         "the required type parameter is an actual type, the bean type
>>         parameter is a type variable that is declared at method level
>>         and the actual type is assignable to the upper bound of the
>>         type variable, or"
>>         And add a footnote: "If no explicit upper bound is defined,
>>         the implicit upper bound java.lang.Object is assumed"
>>
>>         BTW. Should we create a spec issue for that?
>>
>>         WDYT?
>>         Regards,
>>         Arne
>>
>>         P.S.: I don't think this is a backward compatibility issue,
>>         just because Weld and OpenWebBeans implemented it differently
>>         in the past. It just was not clear in 1.0 and is not in 1.1.
>>         The misleading part is the "if any" in the fourth bullet
>>         point. A TypeVariable ALWAYS has an upper bound. "If no bound
>>         is given for a type variable, Object is assumed" (Java Lang
>>         Spec 4.4)
>>
>>         Von: Romain Manni-Bucau <rmannibucau at gmail.com
>>         <mailto:rmannibucau at gmail.com>>
>>         Datum: Montag, 15. Juli 2013 07:55
>>         An: Mark Struberg <struberg at yahoo.de <mailto:struberg at yahoo.de>>
>>         Cc: Martin Kouba <mkouba at redhat.com
>>         <mailto:mkouba at redhat.com>>, Arne Limburg
>>         <arne.limburg at openknowledge.de
>>         <mailto:arne.limburg at openknowledge.de>>,
>>         "cdi-dev at lists.jboss.org <mailto:cdi-dev at lists.jboss.org>"
>>         <cdi-dev at lists.jboss.org <mailto:cdi-dev at lists.jboss.org>>
>>         Betreff: Re: [cdi-dev] CDI and generics
>>
>>         +1, if we are no more aligned on something so simple in plain
>>         java we are useless i fear :(
>>
>>         (i used and saw it used in a lot of real apps)
>>
>>
>>         /Romain Manni-Bucau/
>>         /Twitter: @rmannibucau <https://twitter.com/rmannibucau>/
>>         /Blog: //http://rmannibucau.wordpress.com//
>>         /LinkedIn: //_http://fr.linkedin.com/in/rmannibucau_/
>>         /Github: https://github.com/rmannibucau/
>>
>>
>>
>>         2013/7/14 Mark Struberg <struberg at yahoo.de
>>         <mailto:struberg at yahoo.de>>
>>
>>             folks, this breaks backward compatibility
>>
>>
>>             In CDI 1.0 it was perfectly fine to do the following
>>
>>                 @Produces
>>                 @Dependent
>>                 public <KEY, VALUE extends Serializable> Cache<KEY,
>>             VALUE> getDefaultCache(InjectionPoint injectionPoint) {
>>                     Type ipType = injectionPoint.getType();
>>                     String cacheName = null;
>>
>>                     if (ipType instanceof ParameterizedType) {
>>                         ParameterizedType generic =
>>             (ParameterizedType) ipType;
>>                         Type[] paramTypes =
>>             generic.getActualTypeArguments();
>>                         if (paramTypes == null || paramTypes.length
>>             != 2) {
>>                             throw new RuntimeException("illegal param
>>             types for generic type " + ipType);
>>                         }
>>
>>                         if (paramTypes[1] instanceof Class) {
>>                             cacheName = ((Class)
>>             paramTypes[1]).getSimpleName();
>>                         }
>>                         else {
>>                             cacheName = paramTypes[1].toString();
>>                         }
>>                     }
>>
>>                     return getCache(cacheName);
>>                 }
>>
>>
>>
>>             usage:
>>
>>
>>             @Inject
>>             private Cache<String, IdmUser> userCache;
>>
>>
>>             With your new interpretation you basically trash this, right?
>>             For having a generic producer you would need to create a
>>             distinct producer method for each and every usage. This
>>             just doesn't work out in practice...
>>
>>
>>
>>             LieGrue,
>>             strub
>>
>>
>>
>>
>>
>>             ----- Original Message -----
>>             From: Martin Kouba <mkouba at redhat.com
>>             <mailto:mkouba at redhat.com>>
>>             To: Arne Limburg <arne.limburg at openknowledge.de
>>             <mailto:arne.limburg at openknowledge.de>>
>>             Cc: "cdi-dev at lists.jboss.org
>>             <mailto:cdi-dev at lists.jboss.org>"
>>             <cdi-dev at lists.jboss.org <mailto:cdi-dev at lists.jboss.org>>
>>             Sent: Wednesday, 10 July 2013, 14:01
>>             Subject: Re: [cdi-dev] CDI and generics
>>
>>             No, it's not necessary. We'll fix this within CDITCK-349
>>             [1]. Leave a
>>             comment if you wish :-)
>>
>>             Thanks
>>             Martin
>>
>>             [1]
>>             https://issues.jboss.org/browse/CDITCK-349
>>
>>
>>             Dne 10.7.2013 13:52, Arne Limburg napsal(a):
>>             > OK, so shall I create a TCK issue for that?
>>             >
>>             >
>>             > Cheers,
>>             > Arne
>>             >
>>             > Am 10.07.13 13:50 schrieb "Martin Kouba" unter
>>             <mkouba at redhat.com <mailto:mkouba at redhat.com>>:
>>             >
>>             >> Hi Arne,
>>             >>
>>             >> I think so (except the required type is
>>             Baz<List<Qux>>) - there is no
>>             >> bean with assignable bean type for this IP (according
>>             to CDI 1.1 rules
>>             >> of course).
>>             >>
>>             >> Martin
>>             >>
>>             >> Dne 10.7.2013 13:16, Arne Limburg napsal(a):
>>             >>> Hi Martin,
>>             >>>
>>             >>> So, which bean should be injected into
>>             >>> @Inject
>>             >>>     private Baz<List<T2>> t2BazList;
>>             >>> ?
>>             >>>
>>             >>> Baz<T> is also not assignable to Baz<List<String>>,
>>             because List<String>
>>             >>> is also not assignable from Object.
>>             >>>
>>             >>>
>>             >>> Am I right, that the test should throw an
>>             >>> UnsatisfiedResolutionException?
>>             >>>
>>             >>> Cheers,
>>             >>> Arne
>>             >>>
>>             >>> Am 08.07.13 12:17 schrieb "Martin Kouba" unter
>>             <mkouba at redhat.com <mailto:mkouba at redhat.com>>:
>>             >>>
>>             >>>> Re Arne's question:
>>             >>>> Yes, Baz is a managed bean and
>>             AmbiguousResolutionException should not
>>             >>>> be thrown because Qux is not a managed bean (doesn't
>>             have a public
>>             >>>> no-arg constructor).
>>             >>>>
>>             >>>> Re Marko's findings:
>>             >>>> Yes, the TCK assertions are not up to date and
>>             Baz<T> is not assignable
>>             >>>> to Baz<String>, because String is not assignable
>>             from Object (no bound
>>             >>>> is defined -> Object is assumed; see JSL 4.4). So I
>>             confirm a TCK
>>             >>>> issue.
>>             >>>>
>>             >>>> IMO this would deserve a proper cleanup...
>>             >>>>
>>             >>>> Martin
>>             >>>>
>>             >>>> Dne 8.7.2013 01:22, Marko Lukša napsal(a):
>>             >>>>> I'd say it's a bug. While Baz indeed is a managed
>>             bean, it shouldn't
>>             >>>>> be
>>             >>>>> injected into injection point with type Baz<String> nor
>>             >>>>> Baz<List<Qux>>.
>>             >>>>> So I believe you're right in saying that this test
>>             should fail with
>>             >>>>> UnsatisfiedResolutionException.
>>             >>>>>
>>             >>>>> There was a change made to the spec way back in
>>             2010 (see [1]), but
>>             >>>>> the
>>             >>>>> TCK apparently wasn't updated then. I've filed an
>>             issue in the TCK
>>             >>>>> jira
>>             >>>>> [2].
>>             >>>>>
>>             >>>>> The problem isn't only in the TCK, but also in the
>>             spec itself. Some
>>             >>>>> of
>>             >>>>> the examples in section 5.2.4 don't conform to the
>>             rules defined in
>>             >>>>> the
>>             >>>>> same section (according to the rules, bean Dao<T
>>             extends Persistent>
>>             >>>>> shouldn't be eligible for injection into Dao<Order>
>>             or Dao<User>). I
>>             >>>>> remember asking about this a year ago ([3]), but I
>>             didn't articulate
>>             >>>>> the
>>             >>>>> problem properly.
>>             >>>>>
>>             >>>>> [1]
>>             >>>>>
>>             >>>>>
>>             >>>>>
>>             https://github.com/cdi-spec/cdi/commit/b32243350ace6a0bba337f91a35f5fd0
>>             >>>>> 5c
>>             >>>>> 151f14
>>             >>>>> [2] https://issues.jboss.org/browse/CDITCK-349
>>             >>>>> [3]
>>             http://lists.jboss.org/pipermail/cdi-dev/2012-April/001742.html
>>             >>>>>
>>             >>>>> Marko
>>             >>>>>
>>             >>>>> On 7.7.2013 16:04, Arne Limburg wrote:
>>             >>>>>> Hi all,
>>             >>>>>>
>>             >>>>>> At the OpenWebBeans list we are currently
>>             discussing handling of
>>             >>>>>> generics in CDI.
>>             >>>>>> I found a test in the CDI 1.1 TCK, which imho has
>>             a bug. The test
>>             >>>>>> is
>>             >>>>>>
>>             >>>>>>
>>             org.jboss.cdi.tck.tests.inheritance.generics.MemberLevelInheritanceTes
>>             >>>>>> t
>>             >>>>>> and the (simplified) deployment scenario is the
>>             following:
>>             >>>>>>
>>             >>>>>> public class Baz<T> {
>>             >>>>>> }
>>             >>>>>>
>>             >>>>>> public class Qux extends Baz<String> {
>>             >>>>>> }
>>             >>>>>>
>>             >>>>>> @Vetoed
>>             >>>>>> public class Bar<T1, T2> {
>>             >>>>>>  @Inject
>>             >>>>>>  private Baz<T1> baz;
>>             >>>>>>  @Inject
>>             >>>>>>  private Baz<List<T2>> t2BazList;
>>             >>>>>> }
>>             >>>>>>
>>             >>>>>> @RequestScoped
>>             >>>>>> public class Foo extends Bar<String, Qux> {
>>             >>>>>> }
>>             >>>>>>
>>             >>>>>> public class Producer {
>>             >>>>>>  @Produces
>>             >>>>>>  @Amazing
>>             >>>>>>  public String produceString() {
>>             >>>>>>    return "ok";
>>             >>>>>>  }
>>             >>>>>>
>>             >>>>>>  @Produces
>>             >>>>>>  public String[] produceStringArray() {
>>             >>>>>>    return new String[0];
>>             >>>>>>  }
>>             >>>>>>
>>             >>>>>>  @Produces
>>             >>>>>>  public Baz<Baz<Qux>> produceBazBazQux() {
>>             >>>>>>    return new Baz();
>>             >>>>>>  }
>>             >>>>>> }
>>             >>>>>>
>>             >>>>>> The class Bar has some more injection points, but
>>             that does not
>>             >>>>>> matter.
>>             >>>>>> Due to the TCK this deployment should work, but I
>>             don't know how.
>>             >>>>>> Question: Is Baz a Bean (I suppose so) and may it
>>             be injected into
>>             >>>>>> Bean Foo, more precisely into the second injection
>>             point of class
>>             >>>>>> Bar?
>>             >>>>>> - If yes, it also should be injected into the
>>             first injection
>>             >>>>>> point, right? This would lead to an
>>             AmbiguousResolutionException
>>             >>>>>> since
>>             >>>>>> Qux may also be injected into the first injection
>>             point.
>>             >>>>>> - If no, the deployment should fail with a
>>             >>>>>> UnsatisfiedResolutionException since there is no
>>             Bean that can be
>>             >>>>>> injected into that injection point.
>>             >>>>>>
>>             >>>>>> Is this a bug in the TCK and if not, how is this
>>             supposed to work?
>>             >>>>>>
>>             >>>>>> Cheers,
>>             >>>>>> Arne
>>             >>>>>>
>>             >>>>>>
>>             >>>>>> _______________________________________________
>>             >>>>>> cdi-dev mailing list
>>             >>>>>> cdi-dev at lists.jboss.org
>>             <mailto:cdi-dev at lists.jboss.org>
>>             >>>>>> https://lists.jboss.org/mailman/listinfo/cdi-dev
>>             >>>>>
>>             >>>>>
>>             >>>>>
>>             >>>>> _______________________________________________
>>             >>>>> cdi-dev mailing list
>>             >>>>> cdi-dev at lists.jboss.org
>>             <mailto:cdi-dev at lists.jboss.org>
>>             >>>>> https://lists.jboss.org/mailman/listinfo/cdi-dev
>>             >>>>>
>>             >>>> _______________________________________________
>>             >>>> cdi-dev mailing list
>>             >>>> cdi-dev at lists.jboss.org <mailto:cdi-dev at lists.jboss.org>
>>             >>>> https://lists.jboss.org/mailman/listinfo/cdi-dev
>>             >>>
>>             >
>>
>>             _______________________________________________
>>             cdi-dev mailing list
>>             cdi-dev at lists.jboss.org <mailto:cdi-dev at lists.jboss.org>
>>             https://lists.jboss.org/mailman/listinfo/cdi-dev
>>
>>             _______________________________________________
>>             cdi-dev mailing list
>>             cdi-dev at lists.jboss.org <mailto:cdi-dev at lists.jboss.org>
>>             https://lists.jboss.org/mailman/listinfo/cdi-dev
>>
>>
>>
>>
>>
>>     _______________________________________________
>>     cdi-dev mailing list
>>     cdi-dev at lists.jboss.org  <mailto:cdi-dev at lists.jboss.org>
>>     https://lists.jboss.org/mailman/listinfo/cdi-dev
>
>
>     _______________________________________________
>     cdi-dev mailing list
>     cdi-dev at lists.jboss.org <mailto:cdi-dev at lists.jboss.org>
>     https://lists.jboss.org/mailman/listinfo/cdi-dev
>

-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.jboss.org/pipermail/cdi-dev/attachments/20130716/6bcf67c2/attachment-0001.html 


More information about the cdi-dev mailing list