From arjan.tijms at gmail.com Wed Aug 26 14:04:22 2015 From: arjan.tijms at gmail.com (arjan tijms) Date: Wed, 26 Aug 2015 16:04:22 +0200 Subject: U60 change makes annotations visible in synthesized methods, causes CDI to see lambdas as observer methods Message-ID: 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 void processBean(@Observes ProcessBean event, BeanManager beanManager) { getAnnotation(beanManager, event.getAnnotated(), FacesDataModel.class) .ifPresent(d -> forClassToDataModelClass.put( d.forClass(), (Class>) 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, 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 From forax at univ-mlv.fr Wed Aug 26 14:34:02 2015 From: forax at univ-mlv.fr (Remi Forax) Date: Wed, 26 Aug 2015 16:34:02 +0200 (CEST) Subject: U60 change makes annotations visible in synthesized methods, causes CDI to see lambdas as observer methods In-Reply-To: <393833021.596102.1440599327702.JavaMail.zimbra@u-pem.fr> References: <393833021.596102.1440599327702.JavaMail.zimbra@u-pem.fr> Message-ID: <1392080638.596845.1440599642169.JavaMail.zimbra@u-pem.fr> 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 ? BTW, it's the wrong list, lambdas are delivered so you should have use core-lib-dev instead (in CC). cheers, R?mi ----- Mail original ----- De: "arjan tijms" ?: 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 void processBean(@Observes ProcessBean event, BeanManager beanManager) { getAnnotation(beanManager, event.getAnnotated(), FacesDataModel.class) .ifPresent(d -> forClassToDataModelClass.put( d.forClass(), (Class>) 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, 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 From arjan.tijms at gmail.com Wed Aug 26 14:42:27 2015 From: arjan.tijms at gmail.com (arjan tijms) Date: Wed, 26 Aug 2015 16:42:27 +0200 Subject: U60 change makes annotations visible in synthesized methods, causes CDI to see lambdas as observer methods In-Reply-To: <393833021.596102.1440599327702.JavaMail.zimbra@u-pem.fr> References: <393833021.596102.1440599327702.JavaMail.zimbra@u-pem.fr> Message-ID: Hi, On Wed, Aug 26, 2015 at 4:28 PM, Remi Forax 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" > ?: 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 void processBean(@Observes ProcessBean event, > BeanManager beanManager) { > getAnnotation(beanManager, event.getAnnotated(), FacesDataModel.class) > .ifPresent(d -> > forClassToDataModelClass.put( > d.forClass(), > (Class>) > 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, 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 > From brian.goetz at oracle.com Wed Aug 26 18:12:17 2015 From: brian.goetz at oracle.com (Brian Goetz) Date: Wed, 26 Aug 2015 14:12:17 -0400 Subject: U60 change makes annotations visible in synthesized methods, causes CDI to see lambdas as observer methods In-Reply-To: References: <393833021.596102.1440599327702.JavaMail.zimbra@u-pem.fr> Message-ID: > On Wed, Aug 26, 2015 at 4:28 PM, Remi Forax 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 ? I concur with Remi?s prescription; CDI should be ignoring synthetic members. > >> 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! Actually since you?re asking about changes in compiler behavior, compiler-dev might be the right choice here. But Remi is correct, lambda-dev is finished, and now lambda-related questions go to the appropriate jdk component list.