Skip to content

Instantly share code, notes, and snippets.

@volgar1x
Created November 19, 2012 20:47
Show Gist options
  • Save volgar1x/4113766 to your computer and use it in GitHub Desktop.
Save volgar1x/4113766 to your computer and use it in GitHub Desktop.
package org.mambo.core;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.assistedinject.Assisted;
import org.junit.Test;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.List;
import java.util.Map;
import static junit.framework.Assert.assertEquals;
/**
* Created with IntelliJ IDEA.
* User: Blackrush
* Date: 18/11/12
* Time: 20:30
*/
public class GuiceTest {
Provider<?> singleton(final Provider<?> provider) {
return new Provider<Object>() {
Object instance;
public Object get() {
if (instance == null) instance = provider.get();
return instance;
}
};
}
Provider<?> createProvider(final Map<Class<?>, Provider<?>> services, final Class<?> clazz) throws NoSuchMethodException {
Constructor<?> ctor = null;
for (Constructor<?> c : clazz.getDeclaredConstructors()) {
if (c.isAnnotationPresent(Inject.class)) {
ctor = c;
}
}
if (ctor == null) {
return new Provider<Object>() {
public Object get() {
try {
return clazz.newInstance();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
};
}
final Constructor<?> foundCtor = ctor;
final List<Provider<?>> providers = Lists.newArrayList();
for (Class<?> param : foundCtor.getParameterTypes()) {
providers.add(services.get(param));
}
return new Provider<Object>() {
public Object get() {
Object[] params = new Object[providers.size()];
int i = 0;
for (Provider<?> provider : providers) {
params[i] = provider.get();
++i;
}
try {
return foundCtor.newInstance(params);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
};
}
boolean hasAnnotation(Class<? extends Annotation> clazz, Annotation[] annotations) {
if (annotations.length <= 0) return false;
for (Annotation annotation : annotations) {
if (clazz.isInstance(annotation)) return true;
}
return false;
}
Provider<?> createAssistedFactoryProvider(final Map<Class<?>, Provider<?>> services, final Class<?> clazz, final Class<?> factory) {
Constructor<?> ctor = null;
for (Constructor<?> c : clazz.getDeclaredConstructors()) {
if (c.isAnnotationPresent(Inject.class)) {
ctor = c;
}
}
if (ctor == null) throw new RuntimeException("there is no injectable ctor on " + clazz.getName());
final Class<?>[] factoryClasses = new Class<?>[] {factory};
final Constructor<?> foundCtor = ctor;
return new Provider<Object>() {
public Object get() {
return Proxy.newProxyInstance(clazz.getClassLoader(), factoryClasses, new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] defaultArgs) throws Throwable {
Object[] args = new Object[foundCtor.getParameterTypes().length];
int i = 0, j = 0;
for (Class<?> param : foundCtor.getParameterTypes()) {
Provider<?> provider = services.get(param);
if (provider != null) {
args[i] = provider.get();
} else if (hasAnnotation(Assisted.class, foundCtor.getParameterAnnotations()[i])) {
while (j < defaultArgs.length) {
if (defaultArgs[j].getClass() == param) {
args[i] = defaultArgs[j++];
break;
}
}
} else {
throw new RuntimeException(param.getName() + " is not a service and is not assisted (on injected ctor of " + clazz.getName() + ")");
}
++i;
}
return foundCtor.newInstance(args);
}
});
}
};
}
@Test
public void injectInjector() throws Exception {
final Map<Class<?>, Provider<?>> services = Maps.newIdentityHashMap();
services.put(MyMessageFactory.class, singleton(createProvider(services, MyMessageFactory.class)));
services.put(MyObjectFactory.class, singleton(createAssistedFactoryProvider(services, MyObject.class, MyObjectFactory.class)));
MyMessageFactory factory = (MyMessageFactory) services.get(MyMessageFactory.class).get();
assertEquals("Hello world !", factory.create("world"));
MyObjectFactory factory2 = (MyObjectFactory) services.get(MyObjectFactory.class).get();
MyObject object = factory2.create("Derpinson", "Derp");
object.hello(); // => "Hello Derpinson Derp !"
}
static class MyMessageFactory {
String create(String name) {
return String.format("Hello %s !", name);
}
}
static class MyObject {
MyMessageFactory factory;
String name, surname;
@Inject
MyObject(MyMessageFactory factory, @Assisted String name, @Assisted String surname) {
this.factory = factory;
this.name = name;
this.surname = surname;
}
void hello() {
System.out.println(factory.create(name + " " + surname));
}
}
static interface MyObjectFactory {
MyObject create(String name, String surname);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment