package org.mongodb.morphia.ext.guice;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.mongodb.DBObject;
import org.mongodb.morphia.ObjectFactory;
import org.mongodb.morphia.mapping.MappedField;
import org.mongodb.morphia.mapping.Mapper;
import org.mongodb.morphia.utils.Assert;
import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* @author us@thomas-daily.de
*/
public class GuiceObjectFactory implements ObjectFactory {
// rather messy, i'd like ObjectFactory to be tackled to have a clean
// separation of concern (choose impl class vs. instantiate & inject)
private final ObjectFactory delegate;
private final Injector injector;
/**
* Create a GuiceObjectFactory wrapper around an ObjectFactory
*
* @param delegate the ObjectFactory to wrap
* @param injector the Guice Injector to use
*/
public GuiceObjectFactory(final ObjectFactory delegate, final Injector injector) {
this.delegate = delegate;
this.injector = injector;
}
@Override
public <T> T createInstance(final Class<T> clazz) {
Assert.parameterNotNull("clazz", clazz);
if (injectOnConstructor(clazz)) {
return injector.getInstance(clazz);
}
return injectMembers(delegate.createInstance(clazz));
}
@SuppressWarnings("unchecked")
private boolean injectOnConstructor(final Class clazz) {
final Constructor[] cs = clazz.getDeclaredConstructors();
for (final Constructor constructor : cs) {
if (constructor.getAnnotation(Inject.class) != null) {
return true;
}
}
return false;
}
private <T> T injectMembers(final T o) {
if (o != null) {
injector.injectMembers(o);
}
return o;
}
@Override
public <T> T createInstance(final Class<T> clazz, final DBObject dbObj) {
if (injectOnConstructor(clazz)) {
return injector.getInstance(clazz);
}
return injectMembers(delegate.createInstance(clazz, dbObj));
}
@Override
@SuppressWarnings("unchecked")
public Object createInstance(final Mapper mapper, final MappedField mf, final DBObject dbObj) {
final Class clazz = mf.getType();
if (clazz.isInterface() || Modifier.isAbstract(clazz.getModifiers())) {
// there is no good way to find the clazz to use, yet, so delegate
return injectMembers(delegate.createInstance(mapper, mf, dbObj));
}
if (injectOnConstructor(clazz)) {
return injector.getInstance(clazz);
}
return injectMembers(delegate.createInstance(mapper, mf, dbObj));
}
@Override
@SuppressWarnings("unchecked")
public Map createMap(final MappedField mf) {
final Class clazz = mf.getType();
if (clazz.isInterface() || Modifier.isAbstract(clazz.getModifiers())) {
// there is no good way to find the clazz to use, yet, so delegate
return injectMembers(delegate.createMap(mf));
}
if (injectOnConstructor(clazz)) {
return (Map) injector.getInstance(clazz);
}
return injectMembers(delegate.createMap(mf));
}
@Override
@SuppressWarnings("unchecked")
public List createList(final MappedField mf) {
final Class clazz = mf.getType();
if (clazz.isInterface() || Modifier.isAbstract(clazz.getModifiers())) {
// there is no good way to find the clazz to use, yet, so delegate
return injectMembers(delegate.createList(mf));
}
if (injectOnConstructor(clazz)) {
return (List) injector.getInstance(clazz);
}
return injectMembers(delegate.createList(mf));
}
@Override
@SuppressWarnings("unchecked")
public Set createSet(final MappedField mf) {
final Class clazz = mf.getType();
if (clazz.isInterface() || Modifier.isAbstract(clazz.getModifiers())) {
// there is no good way to find the clazz to use, yet, so delegate
return injectMembers(delegate.createSet(mf));
}
if (injectOnConstructor(clazz)) {
return (Set) injector.getInstance(clazz);
}
return injectMembers(delegate.createSet(mf));
}
}