|
From: Bill B. <bb...@re...> - 2013-04-18 13:27:16
|
k, pull request merged. let me know how it goes On 4/18/2013 8:30 AM, Solomon Duskis wrote: > Samuel, > > I submitted a merge request for this. I think that there would be great > value if you (and others with the same problem) would test out the fix. > We have some excellent unit tests, but this problem relates to > subtleties in the Spring lifecycle and requires situation specific > testing. If your testing is successful, perhaps we can work on creating > an additional unit test for resteasy. > > -Solomon > > > On Wed, Apr 17, 2013 at 10:33 PM, Solomon Duskis <sd...@gm... > <mailto:sd...@gm...>> wrote: > > Thank you for the careful analysis. I'll see if I can work around > this issue using other approaches relating to the Spring lifecycle. > I fixed a similar issue a while back with @Providers, and might be > able to use the same approach for ResteasyRegistration. > > I hope to check in something tomorrow. Since this is a nuanced > issue, I think that this change would benefit from field testing. > Would you feel comfortable with being beta testers for this change? > > -Solomon > > > On Wed, Apr 17, 2013 at 7:37 PM, Gendler, Samuel > <Sam...@we... > <mailto:Sam...@we...>> wrote: > > So it proved to be even more subtle than just the existence of a > factory bean. It has to be a factory bean that doesn’t declare > the type of objects it will create – which is probably limited > only to things like JndiObjectFactoryBean. The FactoryBean > interface declares a method called getObjectType() which is > explicitly supposed to return null if the type of the object is > not known in advance. The following is from the javadoc for > FactoryBean:____ > > __ __ > > Returns:____ > > the type of object that this FactoryBean creates, or null if not > known at the time of the call____ > > __ __ > > When I created a factory bean that specifies a type in > getObjectType(), the properties were not initialized during the > SpringBeanProcessor’s call to getBeansOfType(). When I created > a factory bean that returns null, my properties get initialized > with the values before property placeholder has done its thing > because it actually asks the factory for the bean in order to > determine the type, so it must initialize it first. I’m not > quite sure what the fix to this would be, since the logic of > what is going on in SpringBeanProcessor isn’t entirely clear to > me, but it does appear to be a bug on the resteasy side of > things. Somehow, this code needs to execute after property > placeholder replacement (this seems to be the case in resteast > 2.2.3.GA <http://2.2.3.GA>, which still contains calls to > getBeansOfType(), but doesn’t trigger this bug, so something is > happening to change the order of events).____ > > __ __ > > *From:*Gendler, Samuel > *Sent:* Wednesday, April 17, 2013 4:05 PM > *To:* 'res...@li... > <mailto:res...@li...>' > *Cc:* 'res...@li... > <mailto:res...@li...>' > *Subject:* RE: spring bean processor bug____ > > __ __ > > One further piece of info – the javadoc for getBeansOfType() > says that factories will be initialized in order to check the > type of returned objects. My jndiTemplate is referenced by a > bean created via a factory, and I suspect that this is why it is > causing the jndiTemplate to be initialized while beans that have > identical properties but are not used by factories are not > initialized until much later and only after property placeholder > replacement has occurred. I haven’t actually verified this > hypothesis, but it seems likely. My factory beans are declared > as follows:____ > > __ __ > > <bean id="sonicJmsTradeConnectionFactory" > class="org.springframework.jms.connection.UserCredentialsConnectionFactoryAdapter">____ > > <property name="targetConnectionFactory">____ > > <bean > class="org.springframework.jndi.JndiObjectFactoryBean">____ > > <property name="jndiTemplate" ref="jndiTemplate" />____ > > <property name="jndiName">____ > > <value>${jndi.ConnectionFactory}</value>____ > > </property>____ > > </bean>____ > > </property>____ > > <property name="username">____ > > <value>${jndi.user}</value>____ > > </property>____ > > <property name="password">____ > > <value>${jndi.password}</value>____ > > </property>____ > > </bean>____ > > __ __ > > <bean id="destination" > class="org.springframework.jndi.JndiObjectFactoryBean">____ > > <property name="jndiTemplate" ref="jndiTemplate" />____ > > <property name="jndiName">____ > > <value>${jndi.TopicName}</value>____ > > </property>____ > > </bean>____ > > __ __ > > My guess is that it is actually incorrect to utilize the > getBeansOfType() methods in an application context which is not > yet completely initialized. At the same time, I don’t really > understand why setting the order to LOWEST_PRECEDENCE doesn’t > fix the problem unless something internal to spring is ignoring > the suggested ordering.____ > > __ __ > > *From:*Gendler, Samuel [mailto:Sam...@we...] > *Sent:* Wednesday, April 17, 2013 3:36 PM > *To:* 'res...@li... > <mailto:res...@li...>' > *Cc:* 'res...@li... > <mailto:res...@li...>' > *Subject:* [Resteasy-developers] spring bean processor bug____ > > __ __ > > I recently upgraded a project from 2.2.3.GA <http://2.2.3.GA> to > 2.3.6.FINAL and encountered a bug that appears to originate in > the SpringBeanProcessor and which breaks property placeholder > variable replacement in certain spring beans.____ > > __ __ > > I haven’t completely unwound the bug to the root cause, but I’ve > gotten close enough to be confident that someone with more > resteasy knowledge can likely address it much more quickly than > I can.____ > > __ __ > > First, the symptoms:____ > > __ __ > > I have a bean of class org.springframework.jndi.JndiTemplate > declared as follows:____ > > __ __ > > <bean id="jndiTemplate" > class="org.springframework.jndi.JndiTemplate">____ > > <property name="environment">____ > > <props>____ > > <prop > key="java.naming.factory.initial">com.sonicsw.jndi.mfcontext.MFContextFactory</prop>____ > > <prop key="java.naming.provider.url">${jndi.url}</prop>____ > > <prop > key="java.naming.security.principal">${jndi.user}</prop>____ > > <prop > key="java.naming.security.credentials">${jndi.password}</prop>____ > > <prop > key="com.sonicsw.jndi.mfcontext.domain">${jndi.domain}</prop>____ > > <prop key="clientId">${jndi.clientId}</prop> ____ > > <prop key="subscriptionDurable">true</prop>____ > > <prop > key="durableSubscriptionName">${jndi.durableSubscriptionName}</prop> > ____ > > <prop key="timeToLive">${jndi.timeToLive}</prop>____ > > <prop > key="com.sonicsw.jndi.mfcontext.idleTimeout">${jndi.timeout}</prop>____ > > </props>____ > > </property>____ > > </bean>____ > > __ __ > > I have a property placeholder that is most definitely > initialized with values for all of those properties. I can set > the same values in a test object and see that they are correctly > replaced. However, for reasons that I’ll get into in a moment, > the jndiTemplate properties are NOT replaced and it receives the > raw ${…} strings instead. Needless to say, this breaks my > project. Switching back to 2.2.3.GA <http://2.2.3.GA> > definitely fixes it without making any other changes.____ > > __ __ > > What I’ve discovered so far about the cause:____ > > __ __ > > In SpringBeanProcessor.postProcessBeanFactory(), a method called > findResteasyRegistrations() is called. That method, in turn, > calls the following:____ > > __ __ > > beanFactory.getBeansOfType(ResteasyRegistration.class);____ > > __ __ > > That method call causes some beans (but not all beans) to be > instantiated, and any beans that are instantiated at that point > do not have property placeholder values replaced in them, > because the property placeholder processor has (apparently) not > yet executed. What I haven’t figured out is why my jndiTemplate > bean is impacted by this, while another bean that I created > simply to test the creation of properties inside of a bean > definition is not. It is apparently skipped over by the > getBeansOfType(ResteasyRegistration.class) and property > replacement happens correctly in that case.____ > > __ __ > > Initially, I suspected that this was a problem with post > processor ordering. This was somewhat vexing as the > SpringBeanProcessor does implement the PriorityOrdered > interface, but exposes no mechanism for modifying the order > value. I created my own version of SpringContextLoaderListener > which forgoes the use of SpringContextLoaderSupport and performs > the same work, but also calls setOrder(x) on the > SpringBeanProcessor before adding it to the postprocessors and > application listeners. However, that didn’t seem to have any > impact, no matter in which relative order I placed the property > placeholder and the spring bean processor.____ > > __ __ > > For one final data point, if I don’t use a property placeholder, > but instead reference a properties object via Spring-EL in the > XML, then the values are correctly replaced, because the > spring-el is evaluated when the xml is parsed (I assume), while > property placeholders are definitely evaluated lazily, long > after the bean definitions are created by the xml parsing > process.____ > > __ __ > > <util:properties id="jmsProperties" > location="file:${catalina.base}/conf/jms.properties"/>____ > > ____ > > <bean id="jndiTemplate" > class="org.springframework.jndi.JndiTemplate">____ > > <property name="environment">____ > > <props>____ > > <prop > key="java.naming.factory.initial">com.sonicsw.jndi.mfcontext.MFContextFactory____ > > </prop>____ > > <prop > key="java.naming.provider.url">#{jmsProperties['jndi.url']}</prop>____ > > <prop > key="java.naming.security.principal">#{jmsProperties['jndi.user']}</prop>____ > > <prop > key="java.naming.security.credentials">#{jmsProperties['jndi.password']}</prop>____ > > <prop > key="com.sonicsw.jndi.mfcontext.domain">#{jmsProperties['jndi.domain']}</prop>____ > > <prop > key="clientId">#{jmsProperties['jndi.clientId']}</prop> ____ > > <prop key="subscriptionDurable">true</prop>____ > > <prop > key="durableSubscriptionName">#{jmsProperties['jndi.durableSubscriptionName']}</prop> > ____ > > <prop > key="timeToLive">#{jmsProperties['jndi.timeToLive']}</prop>____ > > <prop > key="com.sonicsw.jndi.mfcontext.idleTimeout">#{jmsProperties['jndi.timeout']}</prop>____ > > </props>____ > > </property>____ > > </bean>____ > > __ __ > > This works, but is a kludge. I’d much prefer to have > property-placeholding actually functional, especially since it > is apparently impossible to predict which beans will fail to > have properties replaced. Looking at the sourec code to > jndiTemplate, I can see no obvious reason why it is treated > differently than my own test bean. Both have no annotations and > both receive a java.util.Properties object as a property. The > behavior is consistent no matter what order they appear in my > context xml file.____ > > __ __ > > I’ve attached my replacement SpringContextLoaderListener just > for reference, in case someone else wants to modify the ordering > of the placeholders while testing or fixing this. The relevant > web.xml entries are below:____ > > __ __ > > <context-param>____ > > <param-name>resteasy.postprocessor.order</param-name>____ > > <param-value>0</param-value>____ > > </context-param>____ > > __ __ > > <listener>____ > > <listener-class>____ > > > org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap</listener-class>____ > > </listener>____ > > __ __ > > <listener>____ > > <!-- > listener-class>org.jboss.resteasy.plugins.spring.SpringContextLoaderListener</listener-class-->____ > > <listener-class>____ > > > com.westernasset.compliance.util.SpringContextLoaderListener____ > > </listener-class>____ > > </listener>____ > > __ __ > > ********************************************************************** > E-mail sent through the Internet is not secure. Western Asset > therefore recommends that you do not send any confidential or > sensitive information to us via electronic mail, including > social security numbers, account numbers, or personal > identification numbers. Delivery, and or timely delivery of > Internet mail is not guaranteed. Western Asset therefore > recommends that you do not send time sensitive or > action-oriented messages to us via electronic mail. > ********************************************************************** > ____ > > > ------------------------------------------------------------------------------ > Precog is a next-generation analytics platform capable of advanced > analytics on semi-structured data. The platform includes APIs > for building > apps and a phenomenal toolset for data science. Developers can use > our toolset for easy data analysis & visualization. Get a free > account! > http://www2.precog.com/precogplatform/slashdotnewsletter > _______________________________________________ > Resteasy-developers mailing list > Res...@li... > <mailto:Res...@li...> > https://lists.sourceforge.net/lists/listinfo/resteasy-developers > > > > > > ------------------------------------------------------------------------------ > Precog is a next-generation analytics platform capable of advanced > analytics on semi-structured data. The platform includes APIs for building > apps and a phenomenal toolset for data science. Developers can use > our toolset for easy data analysis & visualization. Get a free account! > http://www2.precog.com/precogplatform/slashdotnewsletter > > > > _______________________________________________ > Resteasy-developers mailing list > Res...@li... > https://lists.sourceforge.net/lists/listinfo/resteasy-developers > -- Bill Burke JBoss, a division of Red Hat http://bill.burkecentral.com |