U60 change makes annotations visible in synthesized methods, causes CDI to see lambdas as observer methods

arjan tijms arjan.tijms at gmail.com
Wed Aug 26 14:42:27 UTC 2015


Hi,

On Wed, Aug 26, 2015 at 4:28 PM, Remi Forax <remi.forax at u-pem.fr> wrote:
> IMO, it seems to be a bug of the CDI implementation,
> as you said the method corresponding to the lambda body is synthetized so it should be ignored by the CDI implementation, no ?

Yes I agree that might be another possibility. I'll bring this to the
attention of the CDI and/or Weld people as well.

Still, it's a somewhat sudden change and there are many CDI
implementations out there.

> BTW, it's the wrong list, lambdas are delivered so you should have use core-lib-dev instead (in CC).

core-lib-dev, hmm, who would have thought? But I'll keep it in mind
for future messages. Thanks!

Kind regards,
Arjan Tijms

>
> cheers,
> Rémi
>
> ----- Mail original -----
> De: "arjan tijms" <arjan.tijms at gmail.com>
> À: lambda-dev at openjdk.java.net
> Envoyé: Mercredi 26 Août 2015 16:04:22
> Objet: U60 change makes annotations visible in synthesized methods, causes      CDI to see lambdas as observer methods
>
> Hi,
>
> I'm with the JSF EG/Mojarra team and we're seeing what looks like a
> problematic regression in JDK8 u60.
>
> In a CDI extension we have the following observer method:
>
>     public <T> void processBean(@Observes ProcessBean<T> event,
> BeanManager beanManager) {
>         getAnnotation(beanManager, event.getAnnotated(), FacesDataModel.class)
>            .ifPresent(d ->
>                forClassToDataModelClass.put(
>                    d.forClass(),
>                    (Class<? extends DataModel<?>>)
> event.getBean().getBeanClass()
>                )
>            );
>     }
>
> With u45 and below this will generate the following (decompiled the
> class with javap -v -p -s -c)
>
>   private void lambda$processBean$4(javax.enterprise.inject.spi.ProcessBean,
> javax.faces.model.FacesDataModel);
>     descriptor:
> (Ljavax/enterprise/inject/spi/ProcessBean;Ljavax/faces/model/FacesDataModel;)V
>     flags: ACC_PRIVATE, ACC_SYNTHETIC
>     Code:
>       stack=3, locals=3, args_size=3
>          0: aload_0
>          1: getfield      #4                  // Field
> forClassToDataModelClass:Ljava/util/Map;
>          4: aload_2
>          5: invokeinterface #57,  1           // InterfaceMethod
> javax/faces/model/FacesDataModel.forClass:()Ljava/lang/Class;
>         10: aload_1
>         11: invokeinterface #58,  1           // InterfaceMethod
> javax/enterprise/inject/spi/ProcessBean.getBean:()Ljavax/enterprise/inject/spi/Bean;
>         16: invokeinterface #59,  1           // InterfaceMethod
> javax/enterprise/inject/spi/Bean.getBeanClass:()Ljava/lang/Class;
>         21: invokeinterface #55,  3           // InterfaceMethod
> java/util/Map.put:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
>         26: checkcast     #45                 // class java/lang/Class
>         29: pop
>         30: return
>       LineNumberTable:
>         line 110: 0
>         line 111: 5
>         line 112: 11
>         line 110: 21
>       LocalVariableTable:
>         Start  Length  Slot  Name   Signature
>             0      31     0  this   Lcom/sun/faces/cdi/CdiExtension;
>             0      31     2     d   Ljavax/faces/model/FacesDataModel;
>
>
> U60 however generates the following:
>
>   private void lambda$processBean$4(javax.enterprise.inject.spi.ProcessBean,
> javax.faces.model.FacesDataModel);
>     descriptor:
> (Ljavax/enterprise/inject/spi/ProcessBean;Ljavax/faces/model/FacesDataModel;)V
>     flags: ACC_PRIVATE, ACC_SYNTHETIC
>     Code:
>       stack=3, locals=3, args_size=3
>          0: aload_0
>          1: getfield      #4                  // Field
> forClassToDataModelClass:Ljava/util/Map;
>          4: aload_2
>          5: invokeinterface #57,  1           // InterfaceMethod
> javax/faces/model/FacesDataModel.forClass:()Ljava/lang/Class;
>         10: aload_1
>         11: invokeinterface #58,  1           // InterfaceMethod
> javax/enterprise/inject/spi/ProcessBean.getBean:()Ljavax/enterprise/inject/spi/Bean;
>         16: invokeinterface #59,  1           // InterfaceMethod
> javax/enterprise/inject/spi/Bean.getBeanClass:()Ljava/lang/Class;
>         21: invokeinterface #55,  3           // InterfaceMethod
> java/util/Map.put:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
>         26: checkcast     #45                 // class java/lang/Class
>         29: pop
>         30: return
>       LineNumberTable:
>         line 110: 0
>         line 111: 5
>         line 112: 11
>         line 110: 21
>       LocalVariableTable:
>         Start  Length  Slot  Name   Signature
>             0      31     0  this   Lcom/sun/faces/cdi/CdiExtension;
>             0      31     1 event   Ljavax/enterprise/inject/spi/ProcessBean;
>             0      31     2     d   Ljavax/faces/model/FacesDataModel;
>     RuntimeVisibleParameterAnnotations:
>       parameter 0:
>         0: #79()
>       parameter 1:
>
> The difference is that the parameter annotation is made visible for
> this synthesized method. The result is that CDI subsequently scans
> this class and sees the synthesized method for the lambda as an
> observer method, which is of course not the intention. In this
> particular case it will result in a definition error:
>
> "Error occurred during deployment: Exception while loading the app :
>
> CDI definition failure:
>
> WELD-000409: Observer method for container lifecycle event
> [[BackedAnnotatedMethod]
>
> private com.sun.faces.cdi.CdiExtension.lambda$processBean$4(@Observes
> ProcessBean<Object>, FacesDataModel)] can only inject BeanManager.."
>
> I think that if the synthesized method happened to be a correct
> observer method, e.g. for a no-parameter lambda or one that happens to
> have the BeanManager as its first and only parameter, then CDI would
> silently start to call this method in response to events, which too is
> highly undesirable.
>
> Kind regards,
> Arjan Tijms
>



More information about the core-libs-dev mailing list