Remove duplicate LazyLoadingInterceptor code by reusing LazyLoadingProxyFactory.
Original pull request: #3647. Closes #3602.
This commit is contained in:
@@ -15,13 +15,6 @@
|
||||
*/
|
||||
package org.springframework.data.mongodb.core.convert;
|
||||
|
||||
import static org.springframework.util.ReflectionUtils.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
@@ -29,30 +22,18 @@ import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.aopalliance.intercept.MethodInterceptor;
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
import org.bson.Document;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.aop.framework.ProxyFactory;
|
||||
import org.springframework.cglib.proxy.Callback;
|
||||
import org.springframework.cglib.proxy.Enhancer;
|
||||
import org.springframework.cglib.proxy.Factory;
|
||||
import org.springframework.cglib.proxy.MethodProxy;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.dao.support.PersistenceExceptionTranslator;
|
||||
import org.springframework.data.mongodb.ClientSessionException;
|
||||
import org.springframework.data.mongodb.LazyLoadingException;
|
||||
import org.springframework.data.mongodb.MongoDatabaseFactory;
|
||||
import org.springframework.data.mongodb.MongoDatabaseUtils;
|
||||
import org.springframework.data.mongodb.core.convert.ReferenceLoader.DocumentReferenceQuery;
|
||||
import org.springframework.data.mongodb.core.mapping.BasicMongoPersistentProperty;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.objenesis.ObjenesisStd;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.mongodb.DBRef;
|
||||
@@ -74,8 +55,6 @@ public class DefaultDbRefResolver extends DefaultReferenceResolver implements Db
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(DefaultDbRefResolver.class);
|
||||
|
||||
private final MongoDatabaseFactory mongoDbFactory;
|
||||
private final PersistenceExceptionTranslator exceptionTranslator;
|
||||
private final ObjenesisStd objenesis;
|
||||
|
||||
/**
|
||||
* Creates a new {@link DefaultDbRefResolver} with the given {@link MongoDatabaseFactory}.
|
||||
@@ -84,13 +63,11 @@ public class DefaultDbRefResolver extends DefaultReferenceResolver implements Db
|
||||
*/
|
||||
public DefaultDbRefResolver(MongoDatabaseFactory mongoDbFactory) {
|
||||
|
||||
super(new MongoDatabaseFactoryReferenceLoader(mongoDbFactory));
|
||||
super(new MongoDatabaseFactoryReferenceLoader(mongoDbFactory), mongoDbFactory.getExceptionTranslator());
|
||||
|
||||
Assert.notNull(mongoDbFactory, "MongoDbFactory translator must not be null!");
|
||||
|
||||
this.mongoDbFactory = mongoDbFactory;
|
||||
this.exceptionTranslator = mongoDbFactory.getExceptionTranslator();
|
||||
this.objenesis = new ObjenesisStd(true);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -180,44 +157,9 @@ public class DefaultDbRefResolver extends DefaultReferenceResolver implements Db
|
||||
private Object createLazyLoadingProxy(MongoPersistentProperty property, @Nullable DBRef dbref,
|
||||
DbRefResolverCallback callback, DbRefProxyHandler handler) {
|
||||
|
||||
Class<?> propertyType = property.getType();
|
||||
LazyLoadingInterceptor interceptor = new LazyLoadingInterceptor(property, dbref, exceptionTranslator, callback);
|
||||
Object lazyLoadingProxy = getProxyFactory().createLazyLoadingProxy(property, callback, dbref);
|
||||
|
||||
if (!propertyType.isInterface()) {
|
||||
|
||||
Factory factory = (Factory) objenesis.newInstance(getEnhancedTypeFor(propertyType));
|
||||
factory.setCallbacks(new Callback[] { interceptor });
|
||||
|
||||
return handler.populateId(property, dbref, factory);
|
||||
}
|
||||
|
||||
ProxyFactory proxyFactory = new ProxyFactory();
|
||||
|
||||
for (Class<?> type : propertyType.getInterfaces()) {
|
||||
proxyFactory.addInterface(type);
|
||||
}
|
||||
|
||||
proxyFactory.addInterface(LazyLoadingProxy.class);
|
||||
proxyFactory.addInterface(propertyType);
|
||||
proxyFactory.addAdvice(interceptor);
|
||||
|
||||
return handler.populateId(property, dbref, proxyFactory.getProxy(LazyLoadingProxy.class.getClassLoader()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the CGLib enhanced type for the given source type.
|
||||
*
|
||||
* @param type
|
||||
* @return
|
||||
*/
|
||||
private Class<?> getEnhancedTypeFor(Class<?> type) {
|
||||
|
||||
Enhancer enhancer = new Enhancer();
|
||||
enhancer.setSuperclass(type);
|
||||
enhancer.setCallbackType(org.springframework.cglib.proxy.MethodInterceptor.class);
|
||||
enhancer.setInterfaces(new Class[] { LazyLoadingProxy.class });
|
||||
|
||||
return enhancer.createClass();
|
||||
return handler.populateId(property, dbref, lazyLoadingProxy);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -244,249 +186,6 @@ public class DefaultDbRefResolver extends DefaultReferenceResolver implements Db
|
||||
.limit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* A {@link MethodInterceptor} that is used within a lazy loading proxy. The property resolving is delegated to a
|
||||
* {@link DbRefResolverCallback}. The resolving process is triggered by a method invocation on the proxy and is
|
||||
* guaranteed to be performed only once.
|
||||
*
|
||||
* @author Thomas Darimont
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
static class LazyLoadingInterceptor
|
||||
implements MethodInterceptor, org.springframework.cglib.proxy.MethodInterceptor, Serializable {
|
||||
|
||||
private static final Method INITIALIZE_METHOD, TO_DBREF_METHOD, FINALIZE_METHOD;
|
||||
|
||||
private final DbRefResolverCallback callback;
|
||||
private final MongoPersistentProperty property;
|
||||
private final PersistenceExceptionTranslator exceptionTranslator;
|
||||
|
||||
private volatile boolean resolved;
|
||||
private final @Nullable DBRef dbref;
|
||||
private @Nullable Object result;
|
||||
|
||||
static {
|
||||
try {
|
||||
INITIALIZE_METHOD = LazyLoadingProxy.class.getMethod("getTarget");
|
||||
TO_DBREF_METHOD = LazyLoadingProxy.class.getMethod("toDBRef");
|
||||
FINALIZE_METHOD = Object.class.getDeclaredMethod("finalize");
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link LazyLoadingInterceptor} for the given {@link MongoPersistentProperty},
|
||||
* {@link PersistenceExceptionTranslator} and {@link DbRefResolverCallback}.
|
||||
*
|
||||
* @param property must not be {@literal null}.
|
||||
* @param dbref can be {@literal null}.
|
||||
* @param callback must not be {@literal null}.
|
||||
*/
|
||||
public LazyLoadingInterceptor(MongoPersistentProperty property, @Nullable DBRef dbref,
|
||||
PersistenceExceptionTranslator exceptionTranslator, DbRefResolverCallback callback) {
|
||||
|
||||
Assert.notNull(property, "Property must not be null!");
|
||||
Assert.notNull(exceptionTranslator, "Exception translator must not be null!");
|
||||
Assert.notNull(callback, "Callback must not be null!");
|
||||
|
||||
this.dbref = dbref;
|
||||
this.callback = callback;
|
||||
this.exceptionTranslator = exceptionTranslator;
|
||||
this.property = property;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.aopalliance.intercept.MethodInterceptor#invoke(org.aopalliance.intercept.MethodInvocation)
|
||||
*/
|
||||
@Override
|
||||
public Object invoke(@Nullable MethodInvocation invocation) throws Throwable {
|
||||
return intercept(invocation.getThis(), invocation.getMethod(), invocation.getArguments(), null);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.cglib.proxy.MethodInterceptor#intercept(java.lang.Object, java.lang.reflect.Method, java.lang.Object[], org.springframework.cglib.proxy.MethodProxy)
|
||||
*/
|
||||
@Nullable
|
||||
@Override
|
||||
public Object intercept(Object obj, Method method, Object[] args, @Nullable MethodProxy proxy) throws Throwable {
|
||||
|
||||
if (INITIALIZE_METHOD.equals(method)) {
|
||||
return ensureResolved();
|
||||
}
|
||||
|
||||
if (TO_DBREF_METHOD.equals(method)) {
|
||||
return this.dbref;
|
||||
}
|
||||
|
||||
if (isObjectMethod(method) && Object.class.equals(method.getDeclaringClass())) {
|
||||
|
||||
if (ReflectionUtils.isToStringMethod(method)) {
|
||||
return proxyToString(proxy);
|
||||
}
|
||||
|
||||
if (ReflectionUtils.isEqualsMethod(method)) {
|
||||
return proxyEquals(proxy, args[0]);
|
||||
}
|
||||
|
||||
if (ReflectionUtils.isHashCodeMethod(method)) {
|
||||
return proxyHashCode(proxy);
|
||||
}
|
||||
|
||||
// DATAMONGO-1076 - finalize methods should not trigger proxy initialization
|
||||
if (FINALIZE_METHOD.equals(method)) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Object target = ensureResolved();
|
||||
|
||||
if (target == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ReflectionUtils.makeAccessible(method);
|
||||
|
||||
return method.invoke(target, args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a to string representation for the given {@code proxy}.
|
||||
*
|
||||
* @param proxy
|
||||
* @return
|
||||
*/
|
||||
private String proxyToString(@Nullable Object proxy) {
|
||||
|
||||
StringBuilder description = new StringBuilder();
|
||||
if (dbref != null) {
|
||||
description.append(dbref.getCollectionName());
|
||||
description.append(":");
|
||||
description.append(dbref.getId());
|
||||
} else {
|
||||
description.append(System.identityHashCode(proxy));
|
||||
}
|
||||
description.append("$").append(LazyLoadingProxy.class.getSimpleName());
|
||||
|
||||
return description.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the hashcode for the given {@code proxy}.
|
||||
*
|
||||
* @param proxy
|
||||
* @return
|
||||
*/
|
||||
private int proxyHashCode(@Nullable Object proxy) {
|
||||
return proxyToString(proxy).hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs an equality check for the given {@code proxy}.
|
||||
*
|
||||
* @param proxy
|
||||
* @param that
|
||||
* @return
|
||||
*/
|
||||
private boolean proxyEquals(@Nullable Object proxy, Object that) {
|
||||
|
||||
if (!(that instanceof LazyLoadingProxy)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (that == proxy) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return proxyToString(proxy).equals(that.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Will trigger the resolution if the proxy is not resolved already or return a previously resolved result.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Nullable
|
||||
private Object ensureResolved() {
|
||||
|
||||
if (!resolved) {
|
||||
this.result = resolve();
|
||||
this.resolved = true;
|
||||
}
|
||||
|
||||
return this.result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback method for serialization.
|
||||
*
|
||||
* @param out
|
||||
* @throws IOException
|
||||
*/
|
||||
private void writeObject(ObjectOutputStream out) throws IOException {
|
||||
|
||||
ensureResolved();
|
||||
out.writeObject(this.result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback method for deserialization.
|
||||
*
|
||||
* @param in
|
||||
* @throws IOException
|
||||
*/
|
||||
private void readObject(ObjectInputStream in) throws IOException {
|
||||
|
||||
try {
|
||||
this.resolved = true;
|
||||
this.result = in.readObject();
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new LazyLoadingException("Could not deserialize result", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the proxy into its backing object.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Nullable
|
||||
private synchronized Object resolve() {
|
||||
|
||||
if (resolved) {
|
||||
|
||||
if (LOGGER.isTraceEnabled()) {
|
||||
LOGGER.trace("Accessing already resolved lazy loading property {}.{}",
|
||||
property.getOwner() != null ? property.getOwner().getName() : "unknown", property.getName());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
try {
|
||||
if (LOGGER.isTraceEnabled()) {
|
||||
LOGGER.trace("Resolving lazy loading property {}.{}",
|
||||
property.getOwner() != null ? property.getOwner().getName() : "unknown", property.getName());
|
||||
}
|
||||
|
||||
return callback.resolve(property);
|
||||
|
||||
} catch (RuntimeException ex) {
|
||||
|
||||
DataAccessException translatedException = this.exceptionTranslator.translateExceptionIfPossible(ex);
|
||||
|
||||
if (translatedException instanceof ClientSessionException) {
|
||||
throw new LazyLoadingException("Unable to lazily resolve DBRef! Invalid session state.", ex);
|
||||
}
|
||||
|
||||
throw new LazyLoadingException("Unable to lazily resolve DBRef!",
|
||||
translatedException != null ? translatedException : ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Customization hook for obtaining the {@link MongoCollection} for a given {@link DBRef}.
|
||||
*
|
||||
|
||||
@@ -19,6 +19,7 @@ import static org.springframework.data.mongodb.core.convert.ReferenceLookupDeleg
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import org.springframework.dao.support.PersistenceExceptionTranslator;
|
||||
import org.springframework.data.mongodb.core.mapping.DBRef;
|
||||
import org.springframework.data.mongodb.core.mapping.DocumentReference;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
|
||||
@@ -30,10 +31,13 @@ import org.springframework.util.Assert;
|
||||
* proxies} for associations that should be lazily loaded.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @author Mark Paluch
|
||||
* @since 3.3
|
||||
*/
|
||||
public class DefaultReferenceResolver implements ReferenceResolver {
|
||||
|
||||
private final ReferenceLoader referenceLoader;
|
||||
private final LazyLoadingProxyFactory proxyFactory;
|
||||
|
||||
private final LookupFunction collectionLookupFunction = (filter, ctx) -> getReferenceLoader().fetchMany(filter, ctx);
|
||||
private final LookupFunction singleValueLookupFunction = (filter, ctx) -> {
|
||||
@@ -43,13 +47,17 @@ public class DefaultReferenceResolver implements ReferenceResolver {
|
||||
|
||||
/**
|
||||
* Create a new instance of {@link DefaultReferenceResolver}.
|
||||
*
|
||||
*
|
||||
* @param referenceLoader must not be {@literal null}.
|
||||
* @param exceptionTranslator must not be {@literal null}.
|
||||
*/
|
||||
public DefaultReferenceResolver(ReferenceLoader referenceLoader) {
|
||||
|
||||
public DefaultReferenceResolver(ReferenceLoader referenceLoader, PersistenceExceptionTranslator exceptionTranslator) {
|
||||
|
||||
Assert.notNull(referenceLoader, "ReferenceLoader must not be null!");
|
||||
Assert.notNull(exceptionTranslator, "ExceptionTranslator must not be null!");
|
||||
|
||||
this.referenceLoader = referenceLoader;
|
||||
this.proxyFactory = new LazyLoadingProxyFactory(exceptionTranslator);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -92,9 +100,14 @@ public class DefaultReferenceResolver implements ReferenceResolver {
|
||||
return referenceLoader;
|
||||
}
|
||||
|
||||
LazyLoadingProxyFactory getProxyFactory() {
|
||||
return proxyFactory;
|
||||
}
|
||||
|
||||
private Object createLazyLoadingProxy(MongoPersistentProperty property, Object source,
|
||||
ReferenceLookupDelegate referenceLookupDelegate, LookupFunction lookupFunction, MongoEntityReader entityReader) {
|
||||
return new LazyLoadingProxyFactory(referenceLookupDelegate).createLazyLoadingProxy(property, source, lookupFunction,
|
||||
entityReader);
|
||||
return proxyFactory.createLazyLoadingProxy(property, it -> {
|
||||
return referenceLookupDelegate.readReference(it, source, lookupFunction, entityReader);
|
||||
}, source);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,18 +15,18 @@
|
||||
*/
|
||||
package org.springframework.data.mongodb.core.convert;
|
||||
|
||||
import org.springframework.data.mongodb.core.convert.DefaultDbRefResolver.LazyLoadingInterceptor;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
import com.mongodb.DBRef;
|
||||
|
||||
/**
|
||||
* Allows direct interaction with the underlying {@link LazyLoadingInterceptor}.
|
||||
* Allows direct interaction with the underlying {@code LazyLoadingInterceptor}.
|
||||
*
|
||||
* @author Thomas Darimont
|
||||
* @author Christoph Strobl
|
||||
* @author Mark Paluch
|
||||
* @since 1.5
|
||||
* @see LazyLoadingProxyFactory
|
||||
*/
|
||||
public interface LazyLoadingProxy {
|
||||
|
||||
|
||||
@@ -15,46 +15,59 @@
|
||||
*/
|
||||
package org.springframework.data.mongodb.core.convert;
|
||||
|
||||
import static org.springframework.data.mongodb.core.convert.ReferenceLookupDelegate.*;
|
||||
import static org.springframework.util.ReflectionUtils.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.aopalliance.intercept.MethodInterceptor;
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import org.springframework.aop.framework.ProxyFactory;
|
||||
import org.springframework.cglib.proxy.Callback;
|
||||
import org.springframework.cglib.proxy.Enhancer;
|
||||
import org.springframework.cglib.proxy.Factory;
|
||||
import org.springframework.cglib.proxy.MethodProxy;
|
||||
import org.springframework.data.mongodb.core.convert.ReferenceResolver.MongoEntityReader;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.dao.support.PersistenceExceptionTranslator;
|
||||
import org.springframework.data.mongodb.ClientSessionException;
|
||||
import org.springframework.data.mongodb.LazyLoadingException;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.objenesis.ObjenesisStd;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
import com.mongodb.DBRef;
|
||||
|
||||
/**
|
||||
* {@link ProxyFactory} to create a proxy for {@link MongoPersistentProperty#getType()} to resolve a reference lazily.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
class LazyLoadingProxyFactory {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(LazyLoadingProxyFactory.class);
|
||||
|
||||
private final ObjenesisStd objenesis;
|
||||
private final ReferenceLookupDelegate lookupDelegate;
|
||||
|
||||
public LazyLoadingProxyFactory(ReferenceLookupDelegate lookupDelegate) {
|
||||
private final PersistenceExceptionTranslator exceptionTranslator;
|
||||
|
||||
this.lookupDelegate = lookupDelegate;
|
||||
public LazyLoadingProxyFactory(PersistenceExceptionTranslator exceptionTranslator) {
|
||||
this.exceptionTranslator = exceptionTranslator;
|
||||
this.objenesis = new ObjenesisStd(true);
|
||||
}
|
||||
|
||||
public Object createLazyLoadingProxy(MongoPersistentProperty property, Object source, LookupFunction lookupFunction,
|
||||
MongoEntityReader entityReader) {
|
||||
public Object createLazyLoadingProxy(MongoPersistentProperty property, DbRefResolverCallback callback,
|
||||
Object source) {
|
||||
|
||||
Class<?> propertyType = property.getType();
|
||||
LazyLoadingInterceptor interceptor = new LazyLoadingInterceptor(property, source, lookupDelegate, lookupFunction,
|
||||
entityReader);
|
||||
LazyLoadingInterceptor interceptor = new LazyLoadingInterceptor(property, callback, source, exceptionTranslator);
|
||||
|
||||
if (!propertyType.isInterface()) {
|
||||
|
||||
@@ -96,17 +109,9 @@ class LazyLoadingProxyFactory {
|
||||
public static class LazyLoadingInterceptor
|
||||
implements MethodInterceptor, org.springframework.cglib.proxy.MethodInterceptor, Serializable {
|
||||
|
||||
private final ReferenceLookupDelegate referenceLookupDelegate;
|
||||
private final MongoPersistentProperty property;
|
||||
private volatile boolean resolved;
|
||||
private @Nullable Object result;
|
||||
private final Object source;
|
||||
private final LookupFunction lookupFunction;
|
||||
private final MongoEntityReader entityReader;
|
||||
private static final Method INITIALIZE_METHOD, TO_DBREF_METHOD, FINALIZE_METHOD, GET_SOURCE_METHOD;
|
||||
|
||||
private final Method INITIALIZE_METHOD, TO_DBREF_METHOD, FINALIZE_METHOD, GET_SOURCE_METHOD;
|
||||
|
||||
{
|
||||
static {
|
||||
try {
|
||||
INITIALIZE_METHOD = LazyLoadingProxy.class.getMethod("getTarget");
|
||||
TO_DBREF_METHOD = LazyLoadingProxy.class.getMethod("toDBRef");
|
||||
@@ -117,14 +122,20 @@ class LazyLoadingProxyFactory {
|
||||
}
|
||||
}
|
||||
|
||||
public LazyLoadingInterceptor(MongoPersistentProperty property, Object source, ReferenceLookupDelegate reader,
|
||||
LookupFunction lookupFunction, MongoEntityReader entityReader) {
|
||||
private final MongoPersistentProperty property;
|
||||
private final DbRefResolverCallback callback;
|
||||
private final Object source;
|
||||
private final PersistenceExceptionTranslator exceptionTranslator;
|
||||
private volatile boolean resolved;
|
||||
private @Nullable Object result;
|
||||
|
||||
public LazyLoadingInterceptor(MongoPersistentProperty property, DbRefResolverCallback callback, Object source,
|
||||
PersistenceExceptionTranslator exceptionTranslator) {
|
||||
|
||||
this.property = property;
|
||||
this.callback = callback;
|
||||
this.source = source;
|
||||
this.referenceLookupDelegate = reader;
|
||||
this.lookupFunction = lookupFunction;
|
||||
this.entityReader = entityReader;
|
||||
this.exceptionTranslator = exceptionTranslator;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -142,7 +153,7 @@ class LazyLoadingProxyFactory {
|
||||
}
|
||||
|
||||
if (TO_DBREF_METHOD.equals(method)) {
|
||||
return null;
|
||||
return source instanceof DBRef ? source : null;
|
||||
}
|
||||
|
||||
if (GET_SOURCE_METHOD.equals(method)) {
|
||||
@@ -152,7 +163,7 @@ class LazyLoadingProxyFactory {
|
||||
if (isObjectMethod(method) && Object.class.equals(method.getDeclaringClass())) {
|
||||
|
||||
if (ReflectionUtils.isToStringMethod(method)) {
|
||||
return proxyToString(proxy);
|
||||
return proxyToString(source);
|
||||
}
|
||||
|
||||
if (ReflectionUtils.isEqualsMethod(method)) {
|
||||
@@ -160,7 +171,7 @@ class LazyLoadingProxyFactory {
|
||||
}
|
||||
|
||||
if (ReflectionUtils.isHashCodeMethod(method)) {
|
||||
return proxyHashCode(proxy);
|
||||
return proxyHashCode();
|
||||
}
|
||||
|
||||
// DATAMONGO-1076 - finalize methods should not trigger proxy initialization
|
||||
@@ -195,7 +206,13 @@ class LazyLoadingProxyFactory {
|
||||
|
||||
StringBuilder description = new StringBuilder();
|
||||
if (source != null) {
|
||||
description.append(source);
|
||||
if (source instanceof DBRef) {
|
||||
description.append(((DBRef) source).getCollectionName());
|
||||
description.append(":");
|
||||
description.append(((DBRef) source).getId());
|
||||
} else {
|
||||
description.append(source);
|
||||
}
|
||||
} else {
|
||||
description.append(System.identityHashCode(source));
|
||||
}
|
||||
@@ -217,8 +234,36 @@ class LazyLoadingProxyFactory {
|
||||
return proxyToString(proxy).equals(that.toString());
|
||||
}
|
||||
|
||||
private int proxyHashCode(@Nullable Object proxy) {
|
||||
return proxyToString(proxy).hashCode();
|
||||
private int proxyHashCode() {
|
||||
return proxyToString(source).hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback method for serialization.
|
||||
*
|
||||
* @param out
|
||||
* @throws IOException
|
||||
*/
|
||||
private void writeObject(ObjectOutputStream out) throws IOException {
|
||||
|
||||
ensureResolved();
|
||||
out.writeObject(this.result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback method for deserialization.
|
||||
*
|
||||
* @param in
|
||||
* @throws IOException
|
||||
*/
|
||||
private void readObject(ObjectInputStream in) throws IOException {
|
||||
|
||||
try {
|
||||
this.resolved = true;
|
||||
this.result = in.readObject();
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new LazyLoadingException("Could not deserialize result", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -226,32 +271,31 @@ class LazyLoadingProxyFactory {
|
||||
|
||||
if (resolved) {
|
||||
|
||||
// if (LOGGER.isTraceEnabled()) {
|
||||
// LOGGER.trace("Accessing already resolved lazy loading property {}.{}",
|
||||
// property.getOwner() != null ? property.getOwner().getName() : "unknown", property.getName());
|
||||
// }
|
||||
if (LOGGER.isTraceEnabled()) {
|
||||
LOGGER.trace("Accessing already resolved lazy loading property {}.{}",
|
||||
property.getOwner() != null ? property.getOwner().getName() : "unknown", property.getName());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
try {
|
||||
// if (LOGGER.isTraceEnabled()) {
|
||||
// LOGGER.trace("Resolving lazy loading property {}.{}",
|
||||
// property.getOwner() != null ? property.getOwner().getName() : "unknown", property.getName());
|
||||
// }
|
||||
if (LOGGER.isTraceEnabled()) {
|
||||
LOGGER.trace("Resolving lazy loading property {}.{}",
|
||||
property.getOwner() != null ? property.getOwner().getName() : "unknown", property.getName());
|
||||
}
|
||||
|
||||
return referenceLookupDelegate.readReference(property, source, lookupFunction, entityReader);
|
||||
return callback.resolve(property);
|
||||
|
||||
} catch (RuntimeException ex) {
|
||||
throw ex;
|
||||
|
||||
// DataAccessException translatedException = this.exceptionTranslator.translateExceptionIfPossible(ex);
|
||||
//
|
||||
// if (translatedException instanceof ClientSessionException) {
|
||||
// throw new LazyLoadingException("Unable to lazily resolve DBRef! Invalid session state.", ex);
|
||||
// }
|
||||
DataAccessException translatedException = exceptionTranslator.translateExceptionIfPossible(ex);
|
||||
|
||||
// throw new LazyLoadingException("Unable to lazily resolve DBRef!",
|
||||
// translatedException != null ? translatedException : ex);
|
||||
if (translatedException instanceof ClientSessionException) {
|
||||
throw new LazyLoadingException("Unable to lazily resolve DBRef! Invalid session state.", ex);
|
||||
}
|
||||
|
||||
throw new LazyLoadingException("Unable to lazily resolve DBRef!",
|
||||
translatedException != null ? translatedException : ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package org.springframework.data.mongodb.core.convert;
|
||||
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.mongodb.MongoDatabaseFactory;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
@@ -27,12 +28,15 @@ import com.mongodb.DBRef;
|
||||
* The {@link ReferenceResolver} allows to load and convert linked entities.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 3.3
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface ReferenceResolver {
|
||||
|
||||
/**
|
||||
* Resolve the association defined via the given property from a given source value. May deliver a
|
||||
* {@link LazyLoadingProxy proxy instance} in case of a lazy loading association.
|
||||
* Resolve the association defined via the given property from a given source value. May return a
|
||||
* {@link LazyLoadingProxy proxy instance} in case of a lazy loading association. The resolved value is assignable to
|
||||
* {@link PersistentProperty#getType()}.
|
||||
*
|
||||
* @param property the association defining property.
|
||||
* @param source the association source value.
|
||||
@@ -79,7 +83,7 @@ public interface ReferenceResolver {
|
||||
|
||||
/**
|
||||
* Get the target collection name.
|
||||
*
|
||||
*
|
||||
* @return never {@literal null}.
|
||||
*/
|
||||
public String getCollection() {
|
||||
@@ -98,7 +102,7 @@ public interface ReferenceResolver {
|
||||
}
|
||||
|
||||
/**
|
||||
* Domain type conversion callback interface that allows to read
|
||||
* Domain type conversion callback interface that allows to read the {@code source} object into a mapped object.
|
||||
*/
|
||||
@FunctionalInterface
|
||||
interface MongoEntityReader {
|
||||
@@ -107,7 +111,7 @@ public interface ReferenceResolver {
|
||||
* Read values from the given source into an object defined via the given {@link TypeInformation}.
|
||||
*
|
||||
* @param source never {@literal null}.
|
||||
* @param typeInformation information abount the desired target type.
|
||||
* @param typeInformation information about the desired target type.
|
||||
* @return never {@literal null}.
|
||||
*/
|
||||
Object read(Object source, TypeInformation<?> typeInformation);
|
||||
|
||||
@@ -70,16 +70,16 @@ import com.mongodb.client.MongoDatabase;
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
public class DbRefMappingMongoConverterUnitTests {
|
||||
class DbRefMappingMongoConverterUnitTests {
|
||||
|
||||
MappingMongoConverter converter;
|
||||
MongoMappingContext mappingContext;
|
||||
private MappingMongoConverter converter;
|
||||
private MongoMappingContext mappingContext;
|
||||
|
||||
@Mock MongoDatabaseFactory dbFactory;
|
||||
DefaultDbRefResolver dbRefResolver;
|
||||
private DefaultDbRefResolver dbRefResolver;
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
void setUp() {
|
||||
|
||||
when(dbFactory.getExceptionTranslator()).thenReturn(new MongoExceptionTranslator());
|
||||
|
||||
@@ -89,7 +89,7 @@ public class DbRefMappingMongoConverterUnitTests {
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-347
|
||||
public void createsSimpleDBRefCorrectly() {
|
||||
void createsSimpleDBRefCorrectly() {
|
||||
|
||||
Person person = new Person();
|
||||
person.id = "foo";
|
||||
@@ -100,7 +100,7 @@ public class DbRefMappingMongoConverterUnitTests {
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-657
|
||||
public void convertDocumentWithMapDBRef() {
|
||||
void convertDocumentWithMapDBRef() {
|
||||
|
||||
Document mapValDocument = new Document();
|
||||
mapValDocument.put("_id", BigInteger.ONE);
|
||||
@@ -145,7 +145,7 @@ public class DbRefMappingMongoConverterUnitTests {
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-347
|
||||
public void createsDBRefWithClientSpecCorrectly() {
|
||||
void createsDBRefWithClientSpecCorrectly() {
|
||||
|
||||
PropertyPath path = PropertyPath.from("person", PersonClient.class);
|
||||
MongoPersistentProperty property = mappingContext.getPersistentPropertyPath(path).getLeafProperty();
|
||||
@@ -159,7 +159,7 @@ public class DbRefMappingMongoConverterUnitTests {
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-348
|
||||
public void lazyLoadingProxyForLazyDbRefOnInterface() {
|
||||
void lazyLoadingProxyForLazyDbRefOnInterface() {
|
||||
|
||||
String id = "42";
|
||||
String value = "bubu";
|
||||
@@ -180,7 +180,7 @@ public class DbRefMappingMongoConverterUnitTests {
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-348
|
||||
public void lazyLoadingProxyForLazyDbRefOnConcreteCollection() {
|
||||
void lazyLoadingProxyForLazyDbRefOnConcreteCollection() {
|
||||
|
||||
String id = "42";
|
||||
String value = "bubu";
|
||||
@@ -201,7 +201,7 @@ public class DbRefMappingMongoConverterUnitTests {
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-348
|
||||
public void lazyLoadingProxyForLazyDbRefOnConcreteType() {
|
||||
void lazyLoadingProxyForLazyDbRefOnConcreteType() {
|
||||
|
||||
String id = "42";
|
||||
String value = "bubu";
|
||||
@@ -222,7 +222,7 @@ public class DbRefMappingMongoConverterUnitTests {
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-348
|
||||
public void lazyLoadingProxyForLazyDbRefOnConcreteTypeWithPersistenceConstructor() {
|
||||
void lazyLoadingProxyForLazyDbRefOnConcreteTypeWithPersistenceConstructor() {
|
||||
|
||||
String id = "42";
|
||||
String value = "bubu";
|
||||
@@ -243,7 +243,7 @@ public class DbRefMappingMongoConverterUnitTests {
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-348
|
||||
public void lazyLoadingProxyForLazyDbRefOnConcreteTypeWithPersistenceConstructorButWithoutDefaultConstructor() {
|
||||
void lazyLoadingProxyForLazyDbRefOnConcreteTypeWithPersistenceConstructorButWithoutDefaultConstructor() {
|
||||
|
||||
String id = "42";
|
||||
String value = "bubu";
|
||||
@@ -266,7 +266,7 @@ public class DbRefMappingMongoConverterUnitTests {
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-348
|
||||
public void lazyLoadingProxyForSerializableLazyDbRefOnConcreteType() {
|
||||
void lazyLoadingProxyForSerializableLazyDbRefOnConcreteType() {
|
||||
|
||||
String id = "42";
|
||||
String value = "bubu";
|
||||
@@ -288,7 +288,7 @@ public class DbRefMappingMongoConverterUnitTests {
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-884
|
||||
public void lazyLoadingProxyForToStringObjectMethodOverridingDbref() {
|
||||
void lazyLoadingProxyForToStringObjectMethodOverridingDbref() {
|
||||
|
||||
String id = "42";
|
||||
String value = "bubu";
|
||||
@@ -309,7 +309,7 @@ public class DbRefMappingMongoConverterUnitTests {
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-884
|
||||
public void callingToStringObjectMethodOnLazyLoadingDbrefShouldNotInitializeProxy() {
|
||||
void callingToStringObjectMethodOnLazyLoadingDbrefShouldNotInitializeProxy() {
|
||||
|
||||
String id = "42";
|
||||
String value = "bubu";
|
||||
@@ -337,7 +337,7 @@ public class DbRefMappingMongoConverterUnitTests {
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-884
|
||||
public void equalsObjectMethodOnLazyLoadingDbrefShouldNotInitializeProxy() {
|
||||
void equalsObjectMethodOnLazyLoadingDbrefShouldNotInitializeProxy() {
|
||||
|
||||
String id = "42";
|
||||
String value = "bubu";
|
||||
@@ -362,7 +362,7 @@ public class DbRefMappingMongoConverterUnitTests {
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-884
|
||||
public void hashcodeObjectMethodOnLazyLoadingDbrefShouldNotInitializeProxy() {
|
||||
void hashcodeObjectMethodOnLazyLoadingDbrefShouldNotInitializeProxy() {
|
||||
|
||||
String id = "42";
|
||||
String value = "bubu";
|
||||
@@ -385,7 +385,7 @@ public class DbRefMappingMongoConverterUnitTests {
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-884
|
||||
public void lazyLoadingProxyForEqualsAndHashcodeObjectMethodOverridingDbref() {
|
||||
void lazyLoadingProxyForEqualsAndHashcodeObjectMethodOverridingDbref() {
|
||||
|
||||
String id = "42";
|
||||
String value = "bubu";
|
||||
@@ -414,7 +414,7 @@ public class DbRefMappingMongoConverterUnitTests {
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-987
|
||||
public void shouldNotGenerateLazyLoadingProxyForNullValues() {
|
||||
void shouldNotGenerateLazyLoadingProxyForNullValues() {
|
||||
|
||||
Document document = new Document();
|
||||
ClassWithLazyDbRefs lazyDbRefs = new ClassWithLazyDbRefs();
|
||||
@@ -432,7 +432,7 @@ public class DbRefMappingMongoConverterUnitTests {
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-1005
|
||||
public void shouldBeAbleToStoreDirectReferencesToSelf() {
|
||||
void shouldBeAbleToStoreDirectReferencesToSelf() {
|
||||
|
||||
Document document = new Document();
|
||||
|
||||
@@ -448,7 +448,7 @@ public class DbRefMappingMongoConverterUnitTests {
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-1005
|
||||
public void shouldBeAbleToStoreNestedReferencesToSelf() {
|
||||
void shouldBeAbleToStoreNestedReferencesToSelf() {
|
||||
|
||||
Document document = new Document();
|
||||
|
||||
@@ -467,7 +467,7 @@ public class DbRefMappingMongoConverterUnitTests {
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-1012
|
||||
public void shouldEagerlyResolveIdPropertyWithFieldAccess() {
|
||||
void shouldEagerlyResolveIdPropertyWithFieldAccess() {
|
||||
|
||||
MongoPersistentEntity<?> entity = mappingContext.getRequiredPersistentEntity(ClassWithLazyDbRefs.class);
|
||||
MongoPersistentProperty property = entity.getRequiredPersistentProperty("dbRefToConcreteType");
|
||||
@@ -489,7 +489,7 @@ public class DbRefMappingMongoConverterUnitTests {
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-1012
|
||||
public void shouldNotEagerlyResolveIdPropertyWithPropertyAccess() {
|
||||
void shouldNotEagerlyResolveIdPropertyWithPropertyAccess() {
|
||||
|
||||
MongoPersistentEntity<?> entity = mappingContext.getRequiredPersistentEntity(ClassWithLazyDbRefs.class);
|
||||
MongoPersistentProperty property = entity.getRequiredPersistentProperty("dbRefToConcreteTypeWithPropertyAccess");
|
||||
@@ -507,7 +507,7 @@ public class DbRefMappingMongoConverterUnitTests {
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-1076
|
||||
public void shouldNotTriggerResolvingOfLazyLoadedProxyWhenFinalizeMethodIsInvoked() throws Exception {
|
||||
void shouldNotTriggerResolvingOfLazyLoadedProxyWhenFinalizeMethodIsInvoked() throws Exception {
|
||||
|
||||
MongoPersistentEntity<?> entity = mappingContext
|
||||
.getRequiredPersistentEntity(WithObjectMethodOverrideLazyDbRefs.class);
|
||||
@@ -525,7 +525,7 @@ public class DbRefMappingMongoConverterUnitTests {
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-1194
|
||||
public void shouldBulkFetchListOfReferences() {
|
||||
void shouldBulkFetchListOfReferences() {
|
||||
|
||||
String id1 = "1";
|
||||
String id2 = "2";
|
||||
@@ -553,7 +553,7 @@ public class DbRefMappingMongoConverterUnitTests {
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-1666
|
||||
public void shouldBulkFetchSetOfReferencesForConstructorCreation() {
|
||||
void shouldBulkFetchSetOfReferencesForConstructorCreation() {
|
||||
|
||||
String id1 = "1";
|
||||
String id2 = "2";
|
||||
@@ -575,7 +575,7 @@ public class DbRefMappingMongoConverterUnitTests {
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-1194
|
||||
public void shouldFallbackToOneByOneFetchingWhenElementsInListOfReferencesPointToDifferentCollections() {
|
||||
void shouldFallbackToOneByOneFetchingWhenElementsInListOfReferencesPointToDifferentCollections() {
|
||||
|
||||
String id1 = "1";
|
||||
String id2 = "2";
|
||||
@@ -603,7 +603,7 @@ public class DbRefMappingMongoConverterUnitTests {
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-1194
|
||||
public void shouldBulkFetchMapOfReferences() {
|
||||
void shouldBulkFetchMapOfReferences() {
|
||||
|
||||
MapDBRefVal val1 = new MapDBRefVal();
|
||||
val1.id = BigInteger.ONE;
|
||||
@@ -635,7 +635,7 @@ public class DbRefMappingMongoConverterUnitTests {
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-1194
|
||||
public void shouldBulkFetchLazyMapOfReferences() {
|
||||
void shouldBulkFetchLazyMapOfReferences() {
|
||||
|
||||
MapDBRefVal val1 = new MapDBRefVal();
|
||||
val1.id = BigInteger.ONE;
|
||||
@@ -722,15 +722,15 @@ public class DbRefMappingMongoConverterUnitTests {
|
||||
@Id String id;
|
||||
String value;
|
||||
|
||||
public LazyDbRefTarget() {
|
||||
LazyDbRefTarget() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
public LazyDbRefTarget(String id) {
|
||||
LazyDbRefTarget(String id) {
|
||||
this(id, null);
|
||||
}
|
||||
|
||||
public LazyDbRefTarget(String id, String value) {
|
||||
LazyDbRefTarget(String id, String value) {
|
||||
this.id = id;
|
||||
this.value = value;
|
||||
}
|
||||
@@ -750,7 +750,7 @@ public class DbRefMappingMongoConverterUnitTests {
|
||||
|
||||
@Id @AccessType(Type.PROPERTY) String id;
|
||||
|
||||
public LazyDbRefTargetPropertyAccess(String id) {
|
||||
LazyDbRefTargetPropertyAccess(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@@ -767,7 +767,7 @@ public class DbRefMappingMongoConverterUnitTests {
|
||||
public LazyDbRefTargetWithPeristenceConstructor() {}
|
||||
|
||||
@PersistenceConstructor
|
||||
public LazyDbRefTargetWithPeristenceConstructor(String id, String value) {
|
||||
LazyDbRefTargetWithPeristenceConstructor(String id, String value) {
|
||||
super(id, value);
|
||||
this.persistenceConstructorCalled = true;
|
||||
}
|
||||
@@ -783,7 +783,7 @@ public class DbRefMappingMongoConverterUnitTests {
|
||||
boolean persistenceConstructorCalled;
|
||||
|
||||
@PersistenceConstructor
|
||||
public LazyDbRefTargetWithPeristenceConstructorWithoutDefaultConstructor(String id, String value) {
|
||||
LazyDbRefTargetWithPeristenceConstructorWithoutDefaultConstructor(String id, String value) {
|
||||
super(id, value);
|
||||
this.persistenceConstructorCalled = true;
|
||||
}
|
||||
@@ -797,7 +797,7 @@ public class DbRefMappingMongoConverterUnitTests {
|
||||
|
||||
public SerializableLazyDbRefTarget() {}
|
||||
|
||||
public SerializableLazyDbRefTarget(String id, String value) {
|
||||
SerializableLazyDbRefTarget(String id, String value) {
|
||||
super(id, value);
|
||||
}
|
||||
|
||||
@@ -810,7 +810,7 @@ public class DbRefMappingMongoConverterUnitTests {
|
||||
|
||||
public ToStringObjectMethodOverrideLazyDbRefTarget() {}
|
||||
|
||||
public ToStringObjectMethodOverrideLazyDbRefTarget(String id, String value) {
|
||||
ToStringObjectMethodOverrideLazyDbRefTarget(String id, String value) {
|
||||
super(id, value);
|
||||
}
|
||||
|
||||
@@ -830,7 +830,7 @@ public class DbRefMappingMongoConverterUnitTests {
|
||||
|
||||
public EqualsAndHashCodeObjectMethodOverrideLazyDbRefTarget() {}
|
||||
|
||||
public EqualsAndHashCodeObjectMethodOverrideLazyDbRefTarget(String id, String value) {
|
||||
EqualsAndHashCodeObjectMethodOverrideLazyDbRefTarget(String id, String value) {
|
||||
super(id, value);
|
||||
}
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@ import org.mockito.quality.Strictness;
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.data.mongodb.MongoDatabaseFactory;
|
||||
import org.springframework.data.mongodb.core.DocumentTestUtils;
|
||||
import org.springframework.data.mongodb.core.MongoExceptionTranslator;
|
||||
|
||||
import com.mongodb.DBRef;
|
||||
import com.mongodb.client.FindIterable;
|
||||
@@ -63,6 +64,7 @@ class DefaultDbRefResolverUnitTests {
|
||||
void setUp() {
|
||||
|
||||
when(factoryMock.getMongoDatabase()).thenReturn(dbMock);
|
||||
when(factoryMock.getExceptionTranslator()).thenReturn(new MongoExceptionTranslator());
|
||||
when(dbMock.getCollection(anyString(), any(Class.class))).thenReturn(collectionMock);
|
||||
when(collectionMock.find(any(Document.class))).thenReturn(cursorMock);
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.dao.support.PersistenceExceptionTranslator;
|
||||
import org.springframework.data.mongodb.LazyLoadingException;
|
||||
import org.springframework.data.mongodb.core.convert.DefaultDbRefResolver.LazyLoadingInterceptor;
|
||||
import org.springframework.data.mongodb.core.convert.LazyLoadingProxyFactory.LazyLoadingInterceptor;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
|
||||
|
||||
import com.mongodb.DBRef;
|
||||
@@ -37,20 +37,20 @@ import com.mongodb.DBRef;
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
public class LazyLoadingInterceptorUnitTests {
|
||||
class LazyLoadingInterceptorUnitTests {
|
||||
|
||||
@Mock MongoPersistentProperty propertyMock;
|
||||
@Mock DBRef dbrefMock;
|
||||
@Mock DbRefResolverCallback callbackMock;
|
||||
|
||||
@Test // DATAMONGO-1437
|
||||
public void shouldPreserveCauseForNonTranslatableExceptions() throws Throwable {
|
||||
void shouldPreserveCauseForNonTranslatableExceptions() throws Throwable {
|
||||
|
||||
NullPointerException npe = new NullPointerException("Some Exception we did not think about.");
|
||||
when(callbackMock.resolve(propertyMock)).thenThrow(npe);
|
||||
|
||||
assertThatExceptionOfType(LazyLoadingException.class).isThrownBy(() -> {
|
||||
new LazyLoadingInterceptor(propertyMock, dbrefMock, new NullExceptionTranslator(), callbackMock).intercept(null,
|
||||
new LazyLoadingInterceptor(propertyMock, callbackMock, dbrefMock, new NullExceptionTranslator()).intercept(null,
|
||||
LazyLoadingProxy.class.getMethod("getTarget"), null, null);
|
||||
}).withCause(npe);
|
||||
}
|
||||
|
||||
@@ -16,12 +16,12 @@
|
||||
package org.springframework.data.mongodb.core.convert;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.springframework.data.mongodb.core.convert.LazyLoadingProxyFactory.*;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.springframework.aop.framework.Advised;
|
||||
import org.springframework.cglib.proxy.Factory;
|
||||
import org.springframework.data.mongodb.core.convert.DefaultDbRefResolver.LazyLoadingInterceptor;
|
||||
import org.springframework.data.mongodb.core.mapping.Unwrapped;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
@@ -54,7 +54,7 @@ public class LazyLoadingTestUtils {
|
||||
|
||||
public static void assertProxy(Object proxy, Consumer<LazyLoadingProxyValueRetriever> verification) {
|
||||
|
||||
LazyLoadingProxyFactory.LazyLoadingInterceptor interceptor = (LazyLoadingProxyFactory.LazyLoadingInterceptor) (proxy instanceof Advised
|
||||
LazyLoadingInterceptor interceptor = (LazyLoadingInterceptor) (proxy instanceof Advised
|
||||
? ((Advised) proxy).getAdvisors()[0].getAdvice()
|
||||
: ((Factory) proxy).getCallback(0));
|
||||
|
||||
@@ -68,9 +68,9 @@ public class LazyLoadingTestUtils {
|
||||
|
||||
public static class LazyLoadingProxyValueRetriever {
|
||||
|
||||
LazyLoadingProxyFactory.LazyLoadingInterceptor interceptor;
|
||||
LazyLoadingInterceptor interceptor;
|
||||
|
||||
public LazyLoadingProxyValueRetriever(LazyLoadingProxyFactory.LazyLoadingInterceptor interceptor) {
|
||||
public LazyLoadingProxyValueRetriever(LazyLoadingInterceptor interceptor) {
|
||||
this.interceptor = interceptor;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user