Skip to content

Commit

Permalink
Merge pull request #603 from SnakeSVx/master
Browse files Browse the repository at this point in the history
Fix for issue #585 - RESTEasy SpringBeanProcessor cannot support factory bean's factory method
  • Loading branch information
patriot1burke committed Dec 15, 2014
2 parents 58ea62b + 26ff655 commit 6cfb794
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 6cfb794

Please sign in to comment.