Skip to content

Commit 10f69f6

Browse files
Thomas Darimontodrotbohm
authored andcommitted
DATAMONGO-884 - Fix potential NullPointerException for lazy DBRefs.
We now initialize the proxy in case an Object-method is called that is overridden in the traget class. Removed the additional check for initialization and to-DBRef-methods as they're repeated in the target method. Original pull requests: spring-projects#152, spring-projects#153.
1 parent d7b0391 commit 10f69f6

File tree

2 files changed

+132
-11
lines changed

2 files changed

+132
-11
lines changed

spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/DefaultDbRefResolver.java

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
*/
1616
package org.springframework.data.mongodb.core.convert;
1717

18+
import static org.springframework.util.ReflectionUtils.*;
19+
1820
import java.io.IOException;
1921
import java.io.ObjectInputStream;
2022
import java.io.ObjectOutputStream;
@@ -39,7 +41,6 @@
3941
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
4042
import org.springframework.util.Assert;
4143
import org.springframework.util.ClassUtils;
42-
import org.springframework.util.ReflectionUtils;
4344
import org.springframework.util.StringUtils;
4445

4546
import com.mongodb.DB;
@@ -211,15 +212,6 @@ public LazyLoadingInterceptor(MongoPersistentProperty property, DBRef dbref,
211212
*/
212213
@Override
213214
public Object invoke(MethodInvocation invocation) throws Throwable {
214-
215-
if (invocation.getMethod().equals(INITIALIZE_METHOD)) {
216-
return ensureResolved();
217-
}
218-
219-
if (invocation.getMethod().equals(TO_DBREF_METHOD)) {
220-
return this.dbref;
221-
}
222-
223215
return intercept(invocation.getThis(), invocation.getMethod(), invocation.getArguments(), null);
224216
}
225217

@@ -238,7 +230,10 @@ public Object intercept(Object obj, Method method, Object[] args, MethodProxy pr
238230
return this.dbref;
239231
}
240232

241-
return ReflectionUtils.isObjectMethod(method) ? method.invoke(obj, args) : method.invoke(ensureResolved(), args);
233+
Object target = isObjectMethod(method) && Object.class.equals(method.getDeclaringClass()) ? obj
234+
: ensureResolved();
235+
236+
return method.invoke(target, args);
242237
}
243238

244239
/**

spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/DbRefMappingMongoConverterUnitTests.java

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
* Unit tests dor {@link DbRefMappingMongoConverterUnitTests}.
5454
*
5555
* @author Oliver Gierke
56+
* @author Thomas Darimont
5657
*/
5758
@RunWith(MockitoJUnitRunner.class)
5859
public class DbRefMappingMongoConverterUnitTests {
@@ -285,6 +286,62 @@ public void lazyLoadingProxyForSerializableLazyDbRefOnConcreteType() {
285286
assertThat(deserializedResult.dbRefToSerializableTarget.getValue(), is(value));
286287
}
287288

289+
/**
290+
* @see DATAMONGO-884
291+
*/
292+
@Test
293+
public void lazyLoadingProxyForToStringObjectMethodOverridingDbref() {
294+
295+
String id = "42";
296+
String value = "bubu";
297+
MappingMongoConverter converterSpy = spy(converter);
298+
doReturn(new BasicDBObject("_id", id).append("value", value)).when(converterSpy).readRef((DBRef) any());
299+
300+
BasicDBObject dbo = new BasicDBObject();
301+
WithObjectMethodOverrideLazyDbRefs lazyDbRefs = new WithObjectMethodOverrideLazyDbRefs();
302+
lazyDbRefs.dbRefToToStringObjectMethodOverride = new ToStringObjectMethodOverrideLazyDbRefTarget(id, value);
303+
converterSpy.write(lazyDbRefs, dbo);
304+
305+
WithObjectMethodOverrideLazyDbRefs result = converterSpy.read(WithObjectMethodOverrideLazyDbRefs.class, dbo);
306+
307+
assertThat(result.dbRefToToStringObjectMethodOverride, is(notNullValue()));
308+
assertProxyIsResolved(result.dbRefToToStringObjectMethodOverride, false);
309+
assertThat(result.dbRefToToStringObjectMethodOverride.toString(), is(id + ":" + value));
310+
assertProxyIsResolved(result.dbRefToToStringObjectMethodOverride, true);
311+
}
312+
313+
/**
314+
* @see DATAMONGO-884
315+
*/
316+
@Test
317+
public void lazyLoadingProxyForEqualsAndHashcodeObjectMethodOverridingDbref() {
318+
319+
String id = "42";
320+
String value = "bubu";
321+
MappingMongoConverter converterSpy = spy(converter);
322+
doReturn(new BasicDBObject("_id", id).append("value", value)).when(converterSpy).readRef((DBRef) any());
323+
324+
BasicDBObject dbo = new BasicDBObject();
325+
WithObjectMethodOverrideLazyDbRefs lazyDbRefs = new WithObjectMethodOverrideLazyDbRefs();
326+
lazyDbRefs.dbRefEqualsAndHashcodeObjectMethodOverride1 = new EqualsAndHashCodeObjectMethodOverrideLazyDbRefTarget(
327+
id, value);
328+
lazyDbRefs.dbRefEqualsAndHashcodeObjectMethodOverride2 = new EqualsAndHashCodeObjectMethodOverrideLazyDbRefTarget(
329+
id, value);
330+
converterSpy.write(lazyDbRefs, dbo);
331+
332+
WithObjectMethodOverrideLazyDbRefs result = converterSpy.read(WithObjectMethodOverrideLazyDbRefs.class, dbo);
333+
334+
assertProxyIsResolved(result.dbRefEqualsAndHashcodeObjectMethodOverride1, false);
335+
assertThat(result.dbRefEqualsAndHashcodeObjectMethodOverride1, is(notNullValue()));
336+
result.dbRefEqualsAndHashcodeObjectMethodOverride1.equals(null);
337+
assertProxyIsResolved(result.dbRefEqualsAndHashcodeObjectMethodOverride1, true);
338+
339+
assertProxyIsResolved(result.dbRefEqualsAndHashcodeObjectMethodOverride2, false);
340+
assertThat(result.dbRefEqualsAndHashcodeObjectMethodOverride2, is(notNullValue()));
341+
result.dbRefEqualsAndHashcodeObjectMethodOverride2.hashCode();
342+
assertProxyIsResolved(result.dbRefEqualsAndHashcodeObjectMethodOverride2, true);
343+
}
344+
288345
private Object transport(Object result) {
289346
return SerializationUtils.deserialize(SerializationUtils.serialize(result));
290347
}
@@ -391,4 +448,73 @@ public SerializableLazyDbRefTarget(String id, String value) {
391448

392449
private static final long serialVersionUID = 1L;
393450
}
451+
452+
static class ToStringObjectMethodOverrideLazyDbRefTarget extends LazyDbRefTarget {
453+
454+
private static final long serialVersionUID = 1L;
455+
456+
public ToStringObjectMethodOverrideLazyDbRefTarget() {}
457+
458+
public ToStringObjectMethodOverrideLazyDbRefTarget(String id, String value) {
459+
super(id, value);
460+
}
461+
462+
/*
463+
* (non-Javadoc)
464+
* @see java.lang.Object#toString()
465+
*/
466+
@Override
467+
public String toString() {
468+
return this.id + ":" + this.value;
469+
}
470+
}
471+
472+
static class EqualsAndHashCodeObjectMethodOverrideLazyDbRefTarget extends LazyDbRefTarget {
473+
474+
private static final long serialVersionUID = 1L;
475+
476+
public EqualsAndHashCodeObjectMethodOverrideLazyDbRefTarget() {}
477+
478+
public EqualsAndHashCodeObjectMethodOverrideLazyDbRefTarget(String id, String value) {
479+
super(id, value);
480+
}
481+
482+
@Override
483+
public int hashCode() {
484+
final int prime = 31;
485+
int result = 1;
486+
result = prime * result + ((id == null) ? 0 : id.hashCode());
487+
result = prime * result + ((value == null) ? 0 : value.hashCode());
488+
return result;
489+
}
490+
491+
@Override
492+
public boolean equals(Object obj) {
493+
if (this == obj)
494+
return true;
495+
if (obj == null)
496+
return false;
497+
if (getClass() != obj.getClass())
498+
return false;
499+
EqualsAndHashCodeObjectMethodOverrideLazyDbRefTarget other = (EqualsAndHashCodeObjectMethodOverrideLazyDbRefTarget) obj;
500+
if (id == null) {
501+
if (other.id != null)
502+
return false;
503+
} else if (!id.equals(other.id))
504+
return false;
505+
if (value == null) {
506+
if (other.value != null)
507+
return false;
508+
} else if (!value.equals(other.value))
509+
return false;
510+
return true;
511+
}
512+
}
513+
514+
static class WithObjectMethodOverrideLazyDbRefs {
515+
516+
@org.springframework.data.mongodb.core.mapping.DBRef(lazy = true) ToStringObjectMethodOverrideLazyDbRefTarget dbRefToToStringObjectMethodOverride;
517+
@org.springframework.data.mongodb.core.mapping.DBRef(lazy = true) EqualsAndHashCodeObjectMethodOverrideLazyDbRefTarget dbRefEqualsAndHashcodeObjectMethodOverride2;
518+
@org.springframework.data.mongodb.core.mapping.DBRef(lazy = true) EqualsAndHashCodeObjectMethodOverrideLazyDbRefTarget dbRefEqualsAndHashcodeObjectMethodOverride1;
519+
}
394520
}

0 commit comments

Comments
 (0)