Remove duplicate LazyLoadingInterceptor code by reusing LazyLoadingProxyFactory.

Original pull request: #3647.
Closes #3602.
This commit is contained in:
Mark Paluch
2021-05-21 10:56:58 +02:00
parent 5ab75eb65a
commit dae0ac3b4d
9 changed files with 173 additions and 411 deletions

View File

@@ -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}.
*

View File

@@ -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);
}
}

View File

@@ -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 {

View File

@@ -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);
}
}
}

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -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;
}