Skip to content

Instantly share code, notes, and snippets.

@andrewrlee
Created August 3, 2014 17:42
Show Gist options
  • Save andrewrlee/72db066749b1d4dd9f94 to your computer and use it in GitHub Desktop.
Save andrewrlee/72db066749b1d4dd9f94 to your computer and use it in GitHub Desktop.
Java Mixins with Spring AOP
package uk.co.optimisticpanda.spring.proxy;
import java.util.ArrayList;
import java.util.List;
import org.springframework.aop.Advisor;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.support.DefaultIntroductionAdvisor;
import org.springframework.aop.support.DelegatingIntroductionInterceptor;
public class Composite<D>{
private List<Object> instances = new ArrayList<Object>();
private Class<D> returnType;
private Composite(Class<D> returnType){
this.returnType = returnType;
}
private Composite(){
this(null);
}
public static <A> Composite<A> create(Class<A> a){
return new Composite<A>(a);
}
@SuppressWarnings("rawtypes")
public static Composite<?> create(){
return new Composite();
}
public Composite<D> mixin(Object... o){
for (Object object : o) {
instances.add(object);
}
return this;
}
@SuppressWarnings("unchecked")
public D build(){
ProxyFactory factory = new ProxyFactory();
if(instances.isEmpty()){
throw new RuntimeException("Need to specify at least one implementation to mixin");
}
for (Object instance : instances) {
factory.addAdvisor(buildAdvisor(instance));
}
if(returnType != null){
factory.addInterface(returnType);
}
return (D) factory.getProxy();
}
private Advisor buildAdvisor(Object instance){
DelegatingIntroductionInterceptor interceptor = new DelegatingIntroductionInterceptor(instance);
DefaultIntroductionAdvisor advisor = new DefaultIntroductionAdvisor(interceptor);
return advisor;
}
}
package uk.co.optimisticpanda.spring.proxy;
import junit.framework.TestCase;
public class CompositeTest extends TestCase{
private IA a;
private IB b;
@Override
protected void setUp() throws Exception {
a = new IA(){
@Override
public String getA() {
return "a";
}};
b = new IB() {
@Override
public String getB() {
return "b";
}};
}
public void testTypeSafeComposite(){
IAandB proxy = (IAandB) Composite.create(IAandB.class).mixin(a,b).build();
assertEquals("a", proxy.getA());
assertEquals("b", proxy.getB());
}
public void testComposite(){
Object proxy = Composite.create().mixin(a,b).build();
assertEquals("a", ((IA)proxy).getA());
assertEquals("b", ((IB)proxy).getB());
}
public void testTypeMustBeInterface(){
try{
Composite.create(Object.class).mixin(a,b).build();
fail("Should fail as object is not interface");
}catch(IllegalArgumentException e){
assertEquals("[java.lang.Object] is not an interface", e.getMessage());
}
}
public void testNeedToSpecifyImplementations(){
try{
Composite.create().build();
fail("Should fail as no interfaces specified");
}catch(RuntimeException e){
assertEquals("Need to specify at least one implementation to mixin", e.getMessage());
}
}
public interface IA {
String getA();
}
public interface IB {
String getB();
}
public interface IAandB extends IA,IB { }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment