|
|
|
@ -25,10 +25,7 @@ import java.lang.reflect.Method; |
|
|
|
|
|
|
|
|
|
|
|
import org.aopalliance.intercept.MethodInterceptor; |
|
|
|
import org.aopalliance.intercept.MethodInterceptor; |
|
|
|
import org.aopalliance.intercept.MethodInvocation; |
|
|
|
import org.aopalliance.intercept.MethodInvocation; |
|
|
|
import org.objenesis.Objenesis; |
|
|
|
|
|
|
|
import org.objenesis.ObjenesisStd; |
|
|
|
|
|
|
|
import org.springframework.aop.framework.ProxyFactory; |
|
|
|
import org.springframework.aop.framework.ProxyFactory; |
|
|
|
import org.springframework.beans.BeanUtils; |
|
|
|
|
|
|
|
import org.springframework.cglib.proxy.Callback; |
|
|
|
import org.springframework.cglib.proxy.Callback; |
|
|
|
import org.springframework.cglib.proxy.Enhancer; |
|
|
|
import org.springframework.cglib.proxy.Enhancer; |
|
|
|
import org.springframework.cglib.proxy.Factory; |
|
|
|
import org.springframework.cglib.proxy.Factory; |
|
|
|
@ -39,8 +36,8 @@ import org.springframework.data.mongodb.LazyLoadingException; |
|
|
|
import org.springframework.data.mongodb.MongoDbFactory; |
|
|
|
import org.springframework.data.mongodb.MongoDbFactory; |
|
|
|
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity; |
|
|
|
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity; |
|
|
|
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty; |
|
|
|
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty; |
|
|
|
|
|
|
|
import org.springframework.objenesis.ObjenesisStd; |
|
|
|
import org.springframework.util.Assert; |
|
|
|
import org.springframework.util.Assert; |
|
|
|
import org.springframework.util.ClassUtils; |
|
|
|
|
|
|
|
import org.springframework.util.ReflectionUtils; |
|
|
|
import org.springframework.util.ReflectionUtils; |
|
|
|
import org.springframework.util.StringUtils; |
|
|
|
import org.springframework.util.StringUtils; |
|
|
|
|
|
|
|
|
|
|
|
@ -57,10 +54,9 @@ import com.mongodb.DBRef; |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
public class DefaultDbRefResolver implements DbRefResolver { |
|
|
|
public class DefaultDbRefResolver implements DbRefResolver { |
|
|
|
|
|
|
|
|
|
|
|
private static final boolean OBJENESIS_PRESENT = ClassUtils.isPresent("org.objenesis.Objenesis", null); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private final MongoDbFactory mongoDbFactory; |
|
|
|
private final MongoDbFactory mongoDbFactory; |
|
|
|
private final PersistenceExceptionTranslator exceptionTranslator; |
|
|
|
private final PersistenceExceptionTranslator exceptionTranslator; |
|
|
|
|
|
|
|
private final ObjenesisStd objenesis; |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Creates a new {@link DefaultDbRefResolver} with the given {@link MongoDbFactory}. |
|
|
|
* Creates a new {@link DefaultDbRefResolver} with the given {@link MongoDbFactory}. |
|
|
|
@ -73,6 +69,7 @@ public class DefaultDbRefResolver implements DbRefResolver { |
|
|
|
|
|
|
|
|
|
|
|
this.mongoDbFactory = mongoDbFactory; |
|
|
|
this.mongoDbFactory = mongoDbFactory; |
|
|
|
this.exceptionTranslator = mongoDbFactory.getExceptionTranslator(); |
|
|
|
this.exceptionTranslator = mongoDbFactory.getExceptionTranslator(); |
|
|
|
|
|
|
|
this.objenesis = new ObjenesisStd(true); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* |
|
|
|
/* |
|
|
|
@ -117,32 +114,44 @@ public class DefaultDbRefResolver implements DbRefResolver { |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
private Object createLazyLoadingProxy(MongoPersistentProperty property, DBRef dbref, DbRefResolverCallback callback) { |
|
|
|
private Object createLazyLoadingProxy(MongoPersistentProperty property, DBRef dbref, DbRefResolverCallback callback) { |
|
|
|
|
|
|
|
|
|
|
|
ProxyFactory proxyFactory = new ProxyFactory(); |
|
|
|
|
|
|
|
Class<?> propertyType = property.getType(); |
|
|
|
Class<?> propertyType = property.getType(); |
|
|
|
|
|
|
|
LazyLoadingInterceptor interceptor = new LazyLoadingInterceptor(property, dbref, exceptionTranslator, callback); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!propertyType.isInterface()) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Factory factory = (Factory) objenesis.newInstance(getEnhancedTypeFor(propertyType)); |
|
|
|
|
|
|
|
factory.setCallbacks(new Callback[] { interceptor }); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return factory; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ProxyFactory proxyFactory = new ProxyFactory(); |
|
|
|
|
|
|
|
|
|
|
|
for (Class<?> type : propertyType.getInterfaces()) { |
|
|
|
for (Class<?> type : propertyType.getInterfaces()) { |
|
|
|
proxyFactory.addInterface(type); |
|
|
|
proxyFactory.addInterface(type); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
LazyLoadingInterceptor interceptor = new LazyLoadingInterceptor(property, dbref, exceptionTranslator, callback); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
proxyFactory.addInterface(LazyLoadingProxy.class); |
|
|
|
proxyFactory.addInterface(LazyLoadingProxy.class); |
|
|
|
|
|
|
|
|
|
|
|
if (propertyType.isInterface()) { |
|
|
|
|
|
|
|
proxyFactory.addInterface(propertyType); |
|
|
|
proxyFactory.addInterface(propertyType); |
|
|
|
proxyFactory.addAdvice(interceptor); |
|
|
|
proxyFactory.addAdvice(interceptor); |
|
|
|
|
|
|
|
|
|
|
|
return proxyFactory.getProxy(); |
|
|
|
return proxyFactory.getProxy(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
proxyFactory.setProxyTargetClass(true); |
|
|
|
/** |
|
|
|
proxyFactory.setTargetClass(propertyType); |
|
|
|
* Returns the CGLib enhanced type for the given source type. |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* @param type |
|
|
|
|
|
|
|
* @return |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
private Class<?> getEnhancedTypeFor(Class<?> type) { |
|
|
|
|
|
|
|
|
|
|
|
if (!OBJENESIS_PRESENT) { |
|
|
|
Enhancer enhancer = new Enhancer(); |
|
|
|
proxyFactory.addAdvice(interceptor); |
|
|
|
enhancer.setSuperclass(type); |
|
|
|
return proxyFactory.getProxy(); |
|
|
|
enhancer.setCallbackType(org.springframework.cglib.proxy.MethodInterceptor.class); |
|
|
|
} |
|
|
|
enhancer.setInterfaces(new Class[] { LazyLoadingProxy.class }); |
|
|
|
|
|
|
|
|
|
|
|
return ObjenesisProxyEnhancer.enhanceAndGet(proxyFactory, propertyType, interceptor); |
|
|
|
return enhancer.createClass(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
@ -371,109 +380,4 @@ public class DefaultDbRefResolver implements DbRefResolver { |
|
|
|
return result; |
|
|
|
return result; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* Static class to accommodate optional dependency on Objenesis. |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* @author Oliver Gierke |
|
|
|
|
|
|
|
* @author Thomas Darimont |
|
|
|
|
|
|
|
* @since 1.4 |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
private static class ObjenesisProxyEnhancer { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static final boolean IS_SPRING_4_OR_BETTER = ClassUtils.isPresent( |
|
|
|
|
|
|
|
"org.springframework.core.DefaultParameterNameDiscoverer", null); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static final InstanceCreatorStrategy INSTANCE_CREATOR; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (IS_SPRING_4_OR_BETTER) { |
|
|
|
|
|
|
|
INSTANCE_CREATOR = new Spring4ObjenesisInstanceCreatorStrategy(); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
INSTANCE_CREATOR = new DefaultObjenesisInstanceCreatorStrategy(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static Object enhanceAndGet(ProxyFactory proxyFactory, Class<?> type, |
|
|
|
|
|
|
|
org.springframework.cglib.proxy.MethodInterceptor interceptor) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Enhancer enhancer = new Enhancer(); |
|
|
|
|
|
|
|
enhancer.setSuperclass(type); |
|
|
|
|
|
|
|
enhancer.setCallbackType(org.springframework.cglib.proxy.MethodInterceptor.class); |
|
|
|
|
|
|
|
enhancer.setInterfaces(new Class[] { LazyLoadingProxy.class }); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Factory factory = (Factory) INSTANCE_CREATOR.newInstance(enhancer.createClass()); |
|
|
|
|
|
|
|
factory.setCallbacks(new Callback[] { interceptor }); |
|
|
|
|
|
|
|
return factory; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* Strategy for constructing new instances of a given {@link Class}. |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* @author Thomas Darimont |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
interface InstanceCreatorStrategy { |
|
|
|
|
|
|
|
Object newInstance(Class<?> clazz); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* An {@link InstanceCreatorStrategy} that uses Objenesis from the classpath. |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* @author Thomas Darimont |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
private static class DefaultObjenesisInstanceCreatorStrategy implements InstanceCreatorStrategy { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static final Objenesis OBJENESIS = new ObjenesisStd(true); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* |
|
|
|
|
|
|
|
* (non-Javadoc) |
|
|
|
|
|
|
|
* @see org.springframework.data.mongodb.core.convert.DefaultDbRefResolver.ObjenesisProxyEnhancer.InstanceCreatorStrategy#newInstance(java.lang.Class) |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
@Override |
|
|
|
|
|
|
|
public Object newInstance(Class<?> clazz) { |
|
|
|
|
|
|
|
return OBJENESIS.newInstance(clazz); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* An {@link InstanceCreatorStrategy} that uses a repackaged version of Objenesis from Spring 4. |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* @author Thomas Darimont |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
private static class Spring4ObjenesisInstanceCreatorStrategy implements InstanceCreatorStrategy { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static final String SPRING4_OBJENESIS_CLASS_NAME = "org.springframework.objenesis.ObjenesisStd"; |
|
|
|
|
|
|
|
private static final Object OBJENESIS; |
|
|
|
|
|
|
|
private static final Method NEW_INSTANCE_METHOD; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
try { |
|
|
|
|
|
|
|
Class<?> objenesisClass = ClassUtils.forName(SPRING4_OBJENESIS_CLASS_NAME, |
|
|
|
|
|
|
|
ObjenesisProxyEnhancer.class.getClassLoader()); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
OBJENESIS = BeanUtils.instantiateClass(objenesisClass.getConstructor(boolean.class), true); |
|
|
|
|
|
|
|
NEW_INSTANCE_METHOD = objenesisClass.getMethod("newInstance", Class.class); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} catch (Exception e) { |
|
|
|
|
|
|
|
throw new RuntimeException("Could not setup Objenesis infrastructure with Spring 4 ", e); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* |
|
|
|
|
|
|
|
* (non-Javadoc) |
|
|
|
|
|
|
|
* @see org.springframework.data.mongodb.core.convert.DefaultDbRefResolver.ObjenesisProxyEnhancer.InstanceCreatorStrategy#newInstance(java.lang.Class) |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
@Override |
|
|
|
|
|
|
|
public Object newInstance(Class<?> clazz) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
try { |
|
|
|
|
|
|
|
return NEW_INSTANCE_METHOD.invoke(OBJENESIS, clazz); |
|
|
|
|
|
|
|
} catch (Exception e) { |
|
|
|
|
|
|
|
throw new RuntimeException("Could not created instance for " + clazz, e); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|