Skip to content

Commit

Permalink
fixes #585 a problem with the way certain factories are used in sprin…
Browse files Browse the repository at this point in the history
…g. More specificaly the "Activiti engine" library, but other libraries might encounter the same problems.
  • Loading branch information
SnakeSVx committed Oct 24, 2014
1 parent 67944f1 commit 26ff655
Show file tree
Hide file tree
Showing 7 changed files with 123 additions and 35 deletions.
@@ -1,44 +1,30 @@
package org.jboss.resteasy.plugins.spring;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.ws.rs.ext.MessageBodyReader;
import javax.ws.rs.ext.MessageBodyWriter;
import javax.ws.rs.ext.Provider;

import org.jboss.resteasy.core.Dispatcher;
import org.jboss.resteasy.spi.HttpRequest;
import org.jboss.resteasy.spi.HttpResponse;
import org.jboss.resteasy.spi.PropertyInjector;
import org.jboss.resteasy.spi.Registry;
import org.jboss.resteasy.spi.ResteasyDeployment;
import org.jboss.resteasy.spi.ResteasyProviderFactory;
import org.jboss.resteasy.spi.*;
import org.jboss.resteasy.util.GetRestful;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.PropertyValue;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.annotation.Required;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.BeanReference;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.*;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.context.event.SmartApplicationListener;
import org.springframework.util.ClassUtils;

import javax.ws.rs.ext.MessageBodyReader;
import javax.ws.rs.ext.MessageBodyWriter;
import javax.ws.rs.ext.Provider;
import java.lang.reflect.Method;
import java.util.*;

/**
* <p>
* The processor will register any bean annotated with @Path or @Provider into
Expand Down Expand Up @@ -425,13 +411,46 @@ private static Class<?> getBeanClass(String name, BeanDefinition beanDef,
}
}

for (Method method : getBeanClass(factoryClassName).getDeclaredMethods())
{
if (method.getName().equals(factoryMethodName))
{
return method.getReturnType();
}
}
final Class<?> beanClass = getBeanClass(factoryClassName);
final Method[] methods = beanClass.getDeclaredMethods();
for (Method method : methods) {
if (method.getName().equals(factoryMethodName)) {
return method.getReturnType();
}
}

/*
https://github.com/resteasy/Resteasy/issues/585
If we haven't found the correct factoryMethod using the previous method,
fallback to the default FactoryBean getObject method.
Case in which this tends to happen:
1. A bean (Bean A) exists which provides factoryMethods for retrieving 1 or more other beans (Bean B, Bean C, ...)
example: <bean id="processEngine" class="org.activiti.spring.ProcessEngineFactoryBean"/>
2. Bean B is retrieved by telling Spring that the Factory-Bean is Bean A and that there is a method X to retrieve Bean B.
example: <bean id="repositoryService" factory-bean="processEngine" factory-method="getRepositoryService"/>
3. When resteasy has to inject Bean B it tries to lookup method X on Bean A instead of Bean B using the above code.
As a fix for this, we retrieve the return type for Bean A from the FactoryBean, which later on can be used to retrieve the other beans.
*/
if (FactoryBean.class.isAssignableFrom(beanClass)) {
String defaultFactoryMethod = "getObject";
Class<?> returnType = null;
for (Method method : methods) {
if (method.getName().equals(defaultFactoryMethod)) {
returnType = method.getReturnType();
if (returnType != Object.class) {
break;
}
}
}
if (returnType != null) {
return returnType;
}
}
}

throw new IllegalStateException("could not find the type for bean named " + name);
Expand Down
@@ -0,0 +1,14 @@
package org.jboss.resteasy.spring.beanprocessor;

/**
* Created with IntelliJ IDEA.
* User: sgv
* Date: 23/10/14
* Time: 16:16
*/
public class MyBean {

public MyInnerBean getMyInnerBean() {
return new MyInnerBeanImpl();
}
}
@@ -0,0 +1,27 @@
package org.jboss.resteasy.spring.beanprocessor;

import org.springframework.beans.factory.FactoryBean;

/**
* Created with IntelliJ IDEA.
* User: sgv
* Date: 23/10/14
* Time: 16:15
*/
public class MyBeanFactoryBean implements FactoryBean<MyBean> {

@Override
public MyBean getObject() throws Exception {
return new MyBean();
}

@Override
public Class<?> getObjectType() {
return MyBean.class;
}

@Override
public boolean isSingleton() {
return true;
}
}
@@ -0,0 +1,10 @@
package org.jboss.resteasy.spring.beanprocessor;

/**
* Created with IntelliJ IDEA.
* User: sgv
* Date: 24/10/14
* Time: 8:44
*/
public interface MyInnerBean {
}
@@ -0,0 +1,10 @@
package org.jboss.resteasy.spring.beanprocessor;

/**
* Created with IntelliJ IDEA.
* User: sgv
* Date: 24/10/14
* Time: 8:45
*/
public class MyInnerBeanImpl implements MyInnerBean {
}
Expand Up @@ -5,10 +5,9 @@
import org.jboss.resteasy.core.ValueInjector;
import org.jboss.resteasy.spi.HttpRequest;
import org.jboss.resteasy.spi.HttpResponse;
import org.jboss.resteasy.spi.PropertyInjector;
import org.jboss.resteasy.spi.ResteasyProviderFactory;
import org.jboss.resteasy.spi.metadata.Parameter;
import org.jboss.resteasy.spi.metadata.ResourceClass;
import org.jboss.resteasy.spring.beanprocessor.MyInnerBean;
import org.jboss.resteasy.springmvc.tjws.TJWSEmbeddedSpringMVCServer;
import org.jboss.resteasy.test.TestPortProvider;
import org.jboss.resteasy.util.FindAnnotation;
Expand All @@ -18,6 +17,7 @@
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;

import javax.ws.rs.GET;
Expand Down Expand Up @@ -110,6 +110,9 @@ public void setConfigured(String configured)
}
}

@Autowired
private MyInnerBean myInnerBean;

@Path("/")
public static class TestBeanResource
{
Expand Down
Expand Up @@ -2,15 +2,20 @@
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

<!-- Import basic SpringMVC Resteasy integration -->
<import resource="classpath:springmvc-resteasy.xml" />
<import resource="classpath:springmvc-resteasy.xml"/>

<bean id="injectorFactory" class="org.jboss.resteasy.springmvc.test.spring.RequestScopedBeanTest$QualifierInjectorFactoryImpl">
<bean id="injectorFactory"
class="org.jboss.resteasy.springmvc.test.spring.RequestScopedBeanTest$QualifierInjectorFactoryImpl">
</bean>

<bean id="testBean" class="org.jboss.resteasy.springmvc.test.spring.RequestScopedBeanTest$TestBean" scope="request">
<property name="configured" value="configuredValue"/>
<property name="configured" value="configuredValue"/>
</bean>

<bean id="testResource" class="org.jboss.resteasy.springmvc.test.spring.RequestScopedBeanTest$TestBeanResource"/>

<!-- https://github.com/resteasy/Resteasy/issues/585 -->
<bean id="myBean" class="org.jboss.resteasy.spring.beanprocessor.MyBeanFactoryBean"/>
<bean id="myInnerBean" factory-bean="myBean" factory-method="getMyInnerBean"/>

</beans>

0 comments on commit 26ff655

Please sign in to comment.