Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
492f09fbdf | ||
|
|
e3e73f5351 | ||
|
|
e5aff2645b | ||
|
|
b3c0fbb02d | ||
|
|
51de522e88 | ||
|
|
d2842b246f |
16
pom.xml
16
pom.xml
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
<groupId>org.springframework.data</groupId>
|
<groupId>org.springframework.data</groupId>
|
||||||
<artifactId>spring-data-mongodb-parent</artifactId>
|
<artifactId>spring-data-mongodb-parent</artifactId>
|
||||||
<version>4.2.0-M2</version>
|
<version>4.2.0-SNAPSHOT</version>
|
||||||
<packaging>pom</packaging>
|
<packaging>pom</packaging>
|
||||||
|
|
||||||
<name>Spring Data MongoDB</name>
|
<name>Spring Data MongoDB</name>
|
||||||
@@ -15,7 +15,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>org.springframework.data.build</groupId>
|
<groupId>org.springframework.data.build</groupId>
|
||||||
<artifactId>spring-data-parent</artifactId>
|
<artifactId>spring-data-parent</artifactId>
|
||||||
<version>3.2.0-M2</version>
|
<version>3.2.0-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<modules>
|
<modules>
|
||||||
@@ -26,7 +26,7 @@
|
|||||||
<properties>
|
<properties>
|
||||||
<project.type>multi</project.type>
|
<project.type>multi</project.type>
|
||||||
<dist.id>spring-data-mongodb</dist.id>
|
<dist.id>spring-data-mongodb</dist.id>
|
||||||
<springdata.commons>3.2.0-M2</springdata.commons>
|
<springdata.commons>3.2.0-SNAPSHOT</springdata.commons>
|
||||||
<mongo>4.10.2</mongo>
|
<mongo>4.10.2</mongo>
|
||||||
<mongo.reactivestreams>${mongo}</mongo.reactivestreams>
|
<mongo.reactivestreams>${mongo}</mongo.reactivestreams>
|
||||||
<jmh.version>1.19</jmh.version>
|
<jmh.version>1.19</jmh.version>
|
||||||
@@ -144,6 +144,16 @@
|
|||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<repositories>
|
<repositories>
|
||||||
|
<repository>
|
||||||
|
<id>spring-snapshot</id>
|
||||||
|
<url>https://repo.spring.io/snapshot</url>
|
||||||
|
<snapshots>
|
||||||
|
<enabled>true</enabled>
|
||||||
|
</snapshots>
|
||||||
|
<releases>
|
||||||
|
<enabled>false</enabled>
|
||||||
|
</releases>
|
||||||
|
</repository>
|
||||||
<repository>
|
<repository>
|
||||||
<id>spring-milestone</id>
|
<id>spring-milestone</id>
|
||||||
<url>https://repo.spring.io/milestone</url>
|
<url>https://repo.spring.io/milestone</url>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>org.springframework.data</groupId>
|
<groupId>org.springframework.data</groupId>
|
||||||
<artifactId>spring-data-mongodb-parent</artifactId>
|
<artifactId>spring-data-mongodb-parent</artifactId>
|
||||||
<version>4.2.0-M2</version>
|
<version>4.2.0-SNAPSHOT</version>
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>org.springframework.data</groupId>
|
<groupId>org.springframework.data</groupId>
|
||||||
<artifactId>spring-data-mongodb-parent</artifactId>
|
<artifactId>spring-data-mongodb-parent</artifactId>
|
||||||
<version>4.2.0-M2</version>
|
<version>4.2.0-SNAPSHOT</version>
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>org.springframework.data</groupId>
|
<groupId>org.springframework.data</groupId>
|
||||||
<artifactId>spring-data-mongodb-parent</artifactId>
|
<artifactId>spring-data-mongodb-parent</artifactId>
|
||||||
<version>4.2.0-M2</version>
|
<version>4.2.0-SNAPSHOT</version>
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
|
|||||||
@@ -98,6 +98,7 @@ import com.mongodb.DBRef;
|
|||||||
* @author Roman Puchkovskiy
|
* @author Roman Puchkovskiy
|
||||||
* @author Heesu Jung
|
* @author Heesu Jung
|
||||||
* @author Divya Srivastava
|
* @author Divya Srivastava
|
||||||
|
* @author Julia Lee
|
||||||
*/
|
*/
|
||||||
public class MappingMongoConverter extends AbstractMongoConverter implements ApplicationContextAware {
|
public class MappingMongoConverter extends AbstractMongoConverter implements ApplicationContextAware {
|
||||||
|
|
||||||
@@ -1976,8 +1977,9 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (property.isDocumentReference()) {
|
if (property.isDocumentReference()) {
|
||||||
return (T) dbRefResolver.resolveReference(property, accessor.get(property), referenceLookupDelegate,
|
return (T) dbRefResolver.resolveReference(property,
|
||||||
context::convert);
|
new DocumentReferenceSource(accessor.getDocument(), accessor.get(property)),
|
||||||
|
referenceLookupDelegate, context::convert);
|
||||||
}
|
}
|
||||||
|
|
||||||
return super.getPropertyValue(property);
|
return super.getPropertyValue(property);
|
||||||
|
|||||||
@@ -255,6 +255,11 @@ class UnwrappedMongoPersistentProperty implements MongoPersistentProperty {
|
|||||||
return delegate.isWritable();
|
return delegate.isWritable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isReadable() {
|
||||||
|
return delegate.isReadable();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isImmutable() {
|
public boolean isImmutable() {
|
||||||
return delegate.isImmutable();
|
return delegate.isImmutable();
|
||||||
|
|||||||
@@ -15,6 +15,12 @@
|
|||||||
*/
|
*/
|
||||||
package org.springframework.data.mongodb.observability;
|
package org.springframework.data.mongodb.observability;
|
||||||
|
|
||||||
|
import io.micrometer.observation.Observation;
|
||||||
|
import io.micrometer.observation.ObservationRegistry;
|
||||||
|
import io.micrometer.observation.contextpropagation.ObservationThreadLocalAccessor;
|
||||||
|
|
||||||
|
import java.util.function.BiConsumer;
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
import org.springframework.lang.Nullable;
|
import org.springframework.lang.Nullable;
|
||||||
@@ -27,10 +33,6 @@ import com.mongodb.event.CommandListener;
|
|||||||
import com.mongodb.event.CommandStartedEvent;
|
import com.mongodb.event.CommandStartedEvent;
|
||||||
import com.mongodb.event.CommandSucceededEvent;
|
import com.mongodb.event.CommandSucceededEvent;
|
||||||
|
|
||||||
import io.micrometer.observation.Observation;
|
|
||||||
import io.micrometer.observation.ObservationRegistry;
|
|
||||||
import io.micrometer.observation.contextpropagation.ObservationThreadLocalAccessor;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implement MongoDB's {@link CommandListener} using Micrometer's {@link Observation} API.
|
* Implement MongoDB's {@link CommandListener} using Micrometer's {@link Observation} API.
|
||||||
*
|
*
|
||||||
@@ -126,50 +128,54 @@ public class MongoObservationCommandListener implements CommandListener {
|
|||||||
@Override
|
@Override
|
||||||
public void commandSucceeded(CommandSucceededEvent event) {
|
public void commandSucceeded(CommandSucceededEvent event) {
|
||||||
|
|
||||||
RequestContext requestContext = event.getRequestContext();
|
doInObservation(event.getRequestContext(), (observation, context) -> {
|
||||||
|
|
||||||
if (requestContext == null) {
|
context.setCommandSucceededEvent(event);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Observation observation = requestContext.getOrDefault(ObservationThreadLocalAccessor.KEY, null);
|
if (log.isDebugEnabled()) {
|
||||||
if (observation == null) {
|
log.debug("Command succeeded - will stop observation [" + observation + "]");
|
||||||
return;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
MongoHandlerContext context = (MongoHandlerContext) observation.getContext();
|
observation.stop();
|
||||||
context.setCommandSucceededEvent(event);
|
});
|
||||||
|
|
||||||
if (log.isDebugEnabled()) {
|
|
||||||
log.debug("Command succeeded - will stop observation [" + observation + "]");
|
|
||||||
}
|
|
||||||
|
|
||||||
observation.stop();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void commandFailed(CommandFailedEvent event) {
|
public void commandFailed(CommandFailedEvent event) {
|
||||||
|
|
||||||
RequestContext requestContext = event.getRequestContext();
|
doInObservation(event.getRequestContext(), (observation, context) -> {
|
||||||
|
|
||||||
|
context.setCommandFailedEvent(event);
|
||||||
|
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("Command failed - will stop observation [" + observation + "]");
|
||||||
|
}
|
||||||
|
|
||||||
|
observation.error(event.getThrowable());
|
||||||
|
observation.stop();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs the given action for the {@link Observation} and {@link MongoHandlerContext} if there is an ongoing Mongo
|
||||||
|
* Observation. Exceptions thrown by the action are relayed to the caller.
|
||||||
|
*
|
||||||
|
* @param requestContext the context to extract the Observation from.
|
||||||
|
* @param action the action to invoke.
|
||||||
|
*/
|
||||||
|
private void doInObservation(@Nullable RequestContext requestContext,
|
||||||
|
BiConsumer<Observation, MongoHandlerContext> action) {
|
||||||
|
|
||||||
if (requestContext == null) {
|
if (requestContext == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Observation observation = requestContext.getOrDefault(ObservationThreadLocalAccessor.KEY, null);
|
Observation observation = requestContext.getOrDefault(ObservationThreadLocalAccessor.KEY, null);
|
||||||
if (observation == null) {
|
if (observation == null || !(observation.getContext()instanceof MongoHandlerContext context)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
MongoHandlerContext context = (MongoHandlerContext) observation.getContext();
|
action.accept(observation, context);
|
||||||
context.setCommandFailedEvent(event);
|
|
||||||
|
|
||||||
if (log.isDebugEnabled()) {
|
|
||||||
log.debug("Command failed - will stop observation [" + observation + "]");
|
|
||||||
}
|
|
||||||
|
|
||||||
observation.error(event.getThrowable());
|
|
||||||
observation.stop();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ import com.mongodb.client.model.Filters;
|
|||||||
* {@link DocumentReference} related integration tests for {@link MongoTemplate}.
|
* {@link DocumentReference} related integration tests for {@link MongoTemplate}.
|
||||||
*
|
*
|
||||||
* @author Christoph Strobl
|
* @author Christoph Strobl
|
||||||
|
* @author Julia Lee
|
||||||
*/
|
*/
|
||||||
@ExtendWith(MongoClientExtension.class)
|
@ExtendWith(MongoClientExtension.class)
|
||||||
public class MongoTemplateDocumentReferenceTests {
|
public class MongoTemplateDocumentReferenceTests {
|
||||||
@@ -1265,6 +1266,32 @@ public class MongoTemplateDocumentReferenceTests {
|
|||||||
.isEqualTo(new ObjectRefHavingStringIdTargetType(id.toHexString(), "me-the-referenced-object"));
|
.isEqualTo(new ObjectRefHavingStringIdTargetType(id.toHexString(), "me-the-referenced-object"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test // GH-4484
|
||||||
|
void resolveReferenceForOneToManyLookupWithSelfVariableWhenUsedInCtorArgument() {
|
||||||
|
|
||||||
|
OneToManyStylePublisherWithRequiredArgsCtor publisher = new OneToManyStylePublisherWithRequiredArgsCtor("p-100", null);
|
||||||
|
template.save(publisher);
|
||||||
|
|
||||||
|
OneToManyStyleBook book1 = new OneToManyStyleBook();
|
||||||
|
book1.id = "id-1";
|
||||||
|
book1.publisherId = publisher.id;
|
||||||
|
|
||||||
|
OneToManyStyleBook book2 = new OneToManyStyleBook();
|
||||||
|
book2.id = "id-2";
|
||||||
|
book2.publisherId = "p-200";
|
||||||
|
|
||||||
|
OneToManyStyleBook book3 = new OneToManyStyleBook();
|
||||||
|
book3.id = "id-3";
|
||||||
|
book3.publisherId = publisher.id;
|
||||||
|
|
||||||
|
template.save(book1);
|
||||||
|
template.save(book2);
|
||||||
|
template.save(book3);
|
||||||
|
|
||||||
|
OneToManyStylePublisherWithRequiredArgsCtor target = template.findOne(query(where("id").is(publisher.id)), OneToManyStylePublisherWithRequiredArgsCtor.class);
|
||||||
|
assertThat(target.books).containsExactlyInAnyOrder(book1, book3);
|
||||||
|
}
|
||||||
|
|
||||||
static class SingleRefRoot {
|
static class SingleRefRoot {
|
||||||
|
|
||||||
String id;
|
String id;
|
||||||
@@ -2249,4 +2276,40 @@ public class MongoTemplateDocumentReferenceTests {
|
|||||||
return "MongoTemplateDocumentReferenceTests.WithListOfRefs(id=" + this.getId() + ", refs=" + this.getRefs() + ")";
|
return "MongoTemplateDocumentReferenceTests.WithListOfRefs(id=" + this.getId() + ", refs=" + this.getRefs() + ")";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static class OneToManyStylePublisherWithRequiredArgsCtor {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
String id;
|
||||||
|
|
||||||
|
@ReadOnlyProperty
|
||||||
|
@DocumentReference(lookup="{'publisherId':?#{#self._id} }")
|
||||||
|
List<OneToManyStyleBook> books;
|
||||||
|
|
||||||
|
public OneToManyStylePublisherWithRequiredArgsCtor(String id, List<OneToManyStyleBook> books) {
|
||||||
|
this.id = id;
|
||||||
|
this.books = books;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getId() {
|
||||||
|
return this.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<OneToManyStyleBook> getBooks() {
|
||||||
|
return this.books;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(String id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBooks(List<OneToManyStyleBook> books) {
|
||||||
|
this.books = books;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return "MongoTemplateDocumentReferenceTests.OneToManyStylePublisherWithRequiredArgsCtor(id=" + this.getId() + ", book="
|
||||||
|
+ this.getBooks() + ")";
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,15 @@
|
|||||||
package org.springframework.data.mongodb.observability;
|
package org.springframework.data.mongodb.observability;
|
||||||
|
|
||||||
import static io.micrometer.core.tck.MeterRegistryAssert.*;
|
import static io.micrometer.core.tck.MeterRegistryAssert.*;
|
||||||
|
import static org.mockito.Mockito.*;
|
||||||
|
|
||||||
|
import io.micrometer.common.KeyValues;
|
||||||
|
import io.micrometer.core.instrument.MeterRegistry;
|
||||||
|
import io.micrometer.core.instrument.observation.DefaultMeterObservationHandler;
|
||||||
|
import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
|
||||||
|
import io.micrometer.observation.Observation;
|
||||||
|
import io.micrometer.observation.ObservationRegistry;
|
||||||
|
import io.micrometer.observation.contextpropagation.ObservationThreadLocalAccessor;
|
||||||
|
|
||||||
import org.bson.BsonDocument;
|
import org.bson.BsonDocument;
|
||||||
import org.bson.BsonString;
|
import org.bson.BsonString;
|
||||||
@@ -33,18 +42,12 @@ import com.mongodb.event.CommandFailedEvent;
|
|||||||
import com.mongodb.event.CommandStartedEvent;
|
import com.mongodb.event.CommandStartedEvent;
|
||||||
import com.mongodb.event.CommandSucceededEvent;
|
import com.mongodb.event.CommandSucceededEvent;
|
||||||
|
|
||||||
import io.micrometer.common.KeyValues;
|
|
||||||
import io.micrometer.core.instrument.MeterRegistry;
|
|
||||||
import io.micrometer.core.instrument.observation.DefaultMeterObservationHandler;
|
|
||||||
import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
|
|
||||||
import io.micrometer.observation.Observation;
|
|
||||||
import io.micrometer.observation.ObservationRegistry;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Series of test cases exercising {@link MongoObservationCommandListener}.
|
* Series of test cases exercising {@link MongoObservationCommandListener}.
|
||||||
*
|
*
|
||||||
* @author Marcin Grzejszczak
|
* @author Marcin Grzejszczak
|
||||||
* @author Greg Turnquist
|
* @author Greg Turnquist
|
||||||
|
* @author Mark Paluch
|
||||||
*/
|
*/
|
||||||
class MongoObservationCommandListenerTests {
|
class MongoObservationCommandListenerTests {
|
||||||
|
|
||||||
@@ -176,6 +179,38 @@ class MongoObservationCommandListenerTests {
|
|||||||
assertThatTimerRegisteredWithTags();
|
assertThatTimerRegisteredWithTags();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test // GH-4481
|
||||||
|
void completionShouldIgnoreIncompatibleObservationContext() {
|
||||||
|
|
||||||
|
// given
|
||||||
|
RequestContext traceRequestContext = getContext();
|
||||||
|
|
||||||
|
Observation observation = mock(Observation.class);
|
||||||
|
traceRequestContext.put(ObservationThreadLocalAccessor.KEY, observation);
|
||||||
|
|
||||||
|
// when
|
||||||
|
listener.commandSucceeded(new CommandSucceededEvent(traceRequestContext, 0, null, "insert", null, 0));
|
||||||
|
|
||||||
|
verify(observation).getContext();
|
||||||
|
verifyNoMoreInteractions(observation);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test // GH-4481
|
||||||
|
void failureShouldIgnoreIncompatibleObservationContext() {
|
||||||
|
|
||||||
|
// given
|
||||||
|
RequestContext traceRequestContext = getContext();
|
||||||
|
|
||||||
|
Observation observation = mock(Observation.class);
|
||||||
|
traceRequestContext.put(ObservationThreadLocalAccessor.KEY, observation);
|
||||||
|
|
||||||
|
// when
|
||||||
|
listener.commandFailed(new CommandFailedEvent(traceRequestContext, 0, null, "insert", 0, null));
|
||||||
|
|
||||||
|
verify(observation).getContext();
|
||||||
|
verifyNoMoreInteractions(observation);
|
||||||
|
}
|
||||||
|
|
||||||
private RequestContext getContext() {
|
private RequestContext getContext() {
|
||||||
return ((SynchronousContextProvider) ContextProviderFactory.create(observationRegistry)).getContext();
|
return ((SynchronousContextProvider) ContextProviderFactory.create(observationRegistry)).getContext();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user