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 lambda-dev
mailing list