Skip to content

Commit

Permalink
#26 refactored ProxyFactory API
Browse files Browse the repository at this point in the history
  • Loading branch information
ggeorgovassilis committed Sep 21, 2017
1 parent 7b95c66 commit b4b2e38
Show file tree
Hide file tree
Showing 8 changed files with 88 additions and 34 deletions.
21 changes: 20 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ Features:

## News

XXXX-XX-XX: Released 1.6. #26 CglibProxyFactory now really creating opaque proxies; refactored ProxyFactory API.

2017-09-20: Released 1.5. #20 Backported to Java 6, #21 Separate integration tests, #22 HTTP method headers for JaxRs

2017-08-04: Released 1.4. Handling parametrised return types (credits to [Valentin Ozanne](https://github.com/ValentinOzanne))
Expand Down Expand Up @@ -508,13 +510,30 @@ Account joinAccounts(@RequestPart @RequestParam("account1") Account account1, @R
```

Whenever the ```joinAccounts``` method is invoked, the ```serverIp``` property will be looked up in the application context and replaced by its current value. Note that this mechanism works only for values of the ```@RequestMapping``` and ```@Path``` annotations.

#### Where can I find more examples?

Have a look at mapping declarations for the unit test: https://github.com/ggeorgovassilis/spring-rest-invoker/tree/master/spring-rest-invoker/src/test/java/com/github/ggeorgovassilis/springjsonmapper/services

#### I need proxies to extend a specific class

Since 1.0.RC it's possible to generate opaque proxies with cglib instead of the default dynamic proxies. Opaque proxies extend a concrete class and implement the REST mapping interface. In order to do so, specify the name of the class proxies should extend with the ```proxyTargetClass``` property of the factory proxy bean (i.e. the ```SpringRestInvokerProxyFactoryBean```). If you just need opaque proxies, use ``` java.lang.Object```.
Since 1.0.RC it's possible to generate opaque proxies with cglib instead of the default dynamic proxies. Opaque proxies extend a concrete class and implement the REST mapping interface. In order to do so, specify a ```ProxyFactory``` instance, e.g.:

```xml
<bean id="BookService_OpaqueProxy" class="com.github.ggeorgovassilis.springjsonmapper.spring.SpringRestInvokerProxyFactoryBean">
<property name="baseUrl" value="https://www.googleapis.com/books/v1" />
<property name="remoteServiceInterfaceClass"
value="com.github.ggeorgovassilis.springjsonmapper.services.spring.BookServiceSpring" />
<property name="proxyFactory">
<bean
class="com.github.ggeorgovassilis.springjsonmapper.utils.CglibProxyFactory">
<property name="proxyTargetClass"
value="com.github.ggeorgovassilis.springjsonmapper.support.BaseProxyClass" />
</bean>
</property>
</bean>
```


#### I specified some (other) annotations on the mapping interface but they are missing on the service proxy

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,8 @@
* {@link SpringRestInvokerProxyFactoryBean} and
* {@link JaxRsInvokerProxyFactoryBean}
*
* Will generate by default dynamic java proxies. Use
* {@link #setProxyTargetClass(ClassLoader, Class)} or
* {@link #setProxyTargetClass(Class)} in order to generate proxies extending a
* concrete class.
* Will generate by default dynamic java proxies. Use {@link #setProxyFactory(ProxyFactory)}
* for other implementation, e.g. for having proxies extend a concrete class.
*
* @see JaxRsInvokerProxyFactoryBean
* @see SpringRestInvokerProxyFactoryBean
Expand Down Expand Up @@ -87,26 +85,11 @@ protected UrlMapping getRequestMapping(Method method, Object[] args) {
}

/**
* Specify the class to extend
*
* @param classLoader
* Classloader to use
* @param c
* Proxies will extend this base class
*/

public void setProxyTargetClass(ClassLoader classLoader, Class<?> c) {
proxyFactory = new CglibProxyFactory(classLoader, c);
}

/**
* Specify class to derive proxies from
*
* @param c
* Base class. Will use this class' classloader
* Optionally set the proxy factory to use. Defaults to {@link DynamicJavaProxyFactory}
* @param proxyFactory
*/
public void setProxyTargetClass(Class<?> c) {
setProxyTargetClass(c.getClassLoader(), c);
public void setProxyFactory(ProxyFactory proxyFactory) {
this.proxyFactory = proxyFactory;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,13 @@ public class CglibProxyFactory implements ProxyFactory {
protected Class<?> baseClass;
protected ClassLoader classLoader;

public CglibProxyFactory(ClassLoader classLoader, Class<?> baseClass) {
this.baseClass = baseClass;
this.classLoader = classLoader;
}

@Override
public Object createProxy(final ClassLoader classLoader, final Class<?>[] interfaces,
public Object createProxy(ClassLoader classLoader, final Class<?>[] interfaces,
final InvocationHandler callback) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(Object.class);
if (classLoader == null)
classLoader = Thread.currentThread().getContextClassLoader();
enhancer.setClassLoader(classLoader);
enhancer.setCallback(new net.sf.cglib.proxy.InvocationHandler() {

Expand All @@ -35,7 +32,19 @@ public Object invoke(Object proxy, Method method, Object[] args) throws Throwabl
}
});
enhancer.setInterfaces(interfaces);
if (baseClass!=null)
enhancer.setSuperclass(baseClass);
return enhancer.create();
}

@Override
public void setProxyTargetClass(Class<?> c) {
this.baseClass = c;
}

@Override
public void setProxyTargetClassLoader(ClassLoader classLoader) {
this.classLoader = classLoader;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,15 @@ public Object createProxy(ClassLoader classLoader, Class<?>[] interfaces, Invoca
return Proxy.newProxyInstance(classLoader, interfaces, callback);
}

@Override
public void setProxyTargetClass(Class<?> c) {
throw new RuntimeException("Not implemented. Use an opque ProxyFactory implementation");
}

@Override
public void setProxyTargetClassLoader(ClassLoader classLoader) {
throw new RuntimeException("Not implemented. Use an opque ProxyFactory implementation");
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,17 @@ public interface ProxyFactory {
* @return Proxy
*/
Object createProxy(ClassLoader classLoader, Class<?>[] interfaces, InvocationHandler callback);


/**
* Generated proxies will extend the class "c". Not all implementations support proxying
* classes (e.g. DynamicJavaProxyFactory)
* @param classLoader
*/
void setProxyTargetClass(Class<?> c);

/**
* Proxies will use this classloader for the proxied class
* @param classLoader
*/
void setProxyTargetClassLoader(ClassLoader classLoader);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.github.ggeorgovassilis.springjsonmapper.support;

/**
* Base class for proxies. Is used by opaque proxy test.
* @author george georgovassilis
*
*/
public abstract class BaseProxyClass {

}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import org.springframework.web.bind.annotation.RequestMapping;

import com.github.ggeorgovassilis.springjsonmapper.services.BookService;
import com.github.ggeorgovassilis.springjsonmapper.support.BaseProxyClass;

import static org.junit.Assert.*;

Expand Down Expand Up @@ -69,6 +70,7 @@ public void testAnnotationsOnDynamicProxy() throws Exception {
*/
@Test
public void testAnnotationsOnOpaqueProxy() throws Exception {
assertTrue(opaqueProxy instanceof BaseProxyClass);
Method method = ReflectionUtils.findMethod(opaqueProxy.getClass(), "findBooksByTitle",
new Class[] { String.class });
assertNotNull(method);
Expand Down
14 changes: 11 additions & 3 deletions src/test/resources/test-context-annotations.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,22 @@
<bean id="BookService_DynamicProxy"
class="com.github.ggeorgovassilis.springjsonmapper.spring.SpringRestInvokerProxyFactoryBean">
<property name="baseUrl" value="https://www.googleapis.com/books/v1" />
<property name="remoteServiceInterfaceClass" value="com.github.ggeorgovassilis.springjsonmapper.services.spring.BookServiceSpring"/>
<property name="remoteServiceInterfaceClass"
value="com.github.ggeorgovassilis.springjsonmapper.services.spring.BookServiceSpring" />
</bean>

<bean id="BookService_OpaqueProxy"
class="com.github.ggeorgovassilis.springjsonmapper.spring.SpringRestInvokerProxyFactoryBean">
<property name="baseUrl" value="https://www.googleapis.com/books/v1" />
<property name="remoteServiceInterfaceClass" value="com.github.ggeorgovassilis.springjsonmapper.services.spring.BookServiceSpring"/>
<property name="proxyTargetClass" value="java.lang.Object"/>
<property name="remoteServiceInterfaceClass"
value="com.github.ggeorgovassilis.springjsonmapper.services.spring.BookServiceSpring" />
<property name="proxyFactory">
<bean
class="com.github.ggeorgovassilis.springjsonmapper.utils.CglibProxyFactory">
<property name="proxyTargetClass"
value="com.github.ggeorgovassilis.springjsonmapper.support.BaseProxyClass" />
</bean>
</property>
</bean>

</beans>

0 comments on commit b4b2e38

Please sign in to comment.