From 45af8efd96da8e7a9000e38c6d5ecf330a3cd8d0 Mon Sep 17 00:00:00 2001 From: Georgios Andrianakis Date: Thu, 27 Aug 2020 15:01:59 +0300 Subject: [PATCH] Use proper package for @MongoClientName For now we just deprecate the one annotation and support both Relates to: https://github.com/quarkusio/quarkus/pull/11568#discussion_r478327219 --- docs/src/main/asciidoc/mongodb.adoc | 11 ++- .../deployment/MongoClientNameBuildItem.java | 2 +- .../deployment/MongoClientProcessor.java | 21 +++- .../LegacyNamedMongoClientConfigTest.java | 71 +++++++++++++ ...acyNamedReactiveMongoClientConfigTest.java | 99 +++++++++++++++++++ .../mongodb/NamedMongoClientConfigTest.java | 1 - .../NamedReactiveMongoClientConfigTest.java | 1 - .../io/quarkus/mongodb/MongoClientName.java | 40 ++++++++ .../mongodb/runtime/MongoClientName.java | 3 + 9 files changed, 238 insertions(+), 11 deletions(-) create mode 100644 extensions/mongodb-client/deployment/src/test/java/io/quarkus/mongodb/LegacyNamedMongoClientConfigTest.java create mode 100644 extensions/mongodb-client/deployment/src/test/java/io/quarkus/mongodb/LegacyNamedReactiveMongoClientConfigTest.java create mode 100644 extensions/mongodb-client/runtime/src/main/java/io/quarkus/mongodb/MongoClientName.java diff --git a/docs/src/main/asciidoc/mongodb.adoc b/docs/src/main/asciidoc/mongodb.adoc index 50c53ee202163f..bc6b8b6d18e9c0 100644 --- a/docs/src/main/asciidoc/mongodb.adoc +++ b/docs/src/main/asciidoc/mongodb.adoc @@ -260,11 +260,11 @@ multiple clients are **not** necessary as a single client is able to access all === Named Mongo client Injection -When using multiple clients, each `MongoClient`, you can select the client to inject using the `io.quarkus.mongodb.runtime.MongoClientName` qualifier. +When using multiple clients, each `MongoClient`, you can select the client to inject using the `io.quarkus.mongodb.MongoClientName` qualifier. Using the above properties to configure three different clients, you can also inject each one as follows: [source,java,indent=0] --- +---- @Inject MongoClient defaultMongoClient; @@ -275,7 +275,12 @@ MongoClient mongoClient1; @Inject @MongoClientName("inventory") ReactiveMongoClient mongoClient2; --- +---- + +[NOTE] +==== +The old `io.quarkus.mongodb.runtime.MongoClientName` has been deprecated. It still works, but will soon be removed, therefore users are encouraged to not use it. +==== == Running a MongoDB Database As by default, `MongoClient` is configured to access a local MongoDB database on port 27017 (the default MongoDB port), if you have a local running database on this port, there is nothing more to do before being able to test it! diff --git a/extensions/mongodb-client/deployment/src/main/java/io/quarkus/mongodb/deployment/MongoClientNameBuildItem.java b/extensions/mongodb-client/deployment/src/main/java/io/quarkus/mongodb/deployment/MongoClientNameBuildItem.java index 34576e8736771e..2236b56790c630 100644 --- a/extensions/mongodb-client/deployment/src/main/java/io/quarkus/mongodb/deployment/MongoClientNameBuildItem.java +++ b/extensions/mongodb-client/deployment/src/main/java/io/quarkus/mongodb/deployment/MongoClientNameBuildItem.java @@ -1,7 +1,7 @@ package io.quarkus.mongodb.deployment; import io.quarkus.builder.item.MultiBuildItem; -import io.quarkus.mongodb.runtime.MongoClientName; +import io.quarkus.mongodb.MongoClientName; /** * Represents the values of the {@link MongoClientName} diff --git a/extensions/mongodb-client/deployment/src/main/java/io/quarkus/mongodb/deployment/MongoClientProcessor.java b/extensions/mongodb-client/deployment/src/main/java/io/quarkus/mongodb/deployment/MongoClientProcessor.java index 1a7e0ef26b7a5c..e41eaf47a75fb2 100644 --- a/extensions/mongodb-client/deployment/src/main/java/io/quarkus/mongodb/deployment/MongoClientProcessor.java +++ b/extensions/mongodb-client/deployment/src/main/java/io/quarkus/mongodb/deployment/MongoClientProcessor.java @@ -44,9 +44,9 @@ import io.quarkus.deployment.builditem.SslNativeConfigBuildItem; import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem; import io.quarkus.deployment.metrics.MetricsCapabilityBuildItem; +import io.quarkus.mongodb.MongoClientName; import io.quarkus.mongodb.reactive.ReactiveMongoClient; import io.quarkus.mongodb.runtime.MongoClientBeanUtil; -import io.quarkus.mongodb.runtime.MongoClientName; import io.quarkus.mongodb.runtime.MongoClientRecorder; import io.quarkus.mongodb.runtime.MongoClientSupport; import io.quarkus.mongodb.runtime.MongoClients; @@ -54,7 +54,10 @@ import io.quarkus.smallrye.health.deployment.spi.HealthBuildItem; public class MongoClientProcessor { + private static final DotName LEGACY_MONGO_CLIENT_ANNOTATION = DotName + .createSimple(io.quarkus.mongodb.runtime.MongoClientName.class.getName()); private static final DotName MONGO_CLIENT_ANNOTATION = DotName.createSimple(MongoClientName.class.getName()); + private static final DotName MONGO_CLIENT = DotName.createSimple(MongoClient.class.getName()); private static final DotName REACTIVE_MONGO_CLIENT = DotName.createSimple(ReactiveMongoClient.class.getName()); @@ -93,15 +96,20 @@ public void mongoClientNames(ApplicationArchivesBuildItem applicationArchivesBui BuildProducer mongoClientName) { Set values = new HashSet<>(); IndexView indexView = applicationArchivesBuildItem.getRootArchive().getIndex(); - Collection mongoClientAnnotations = indexView.getAnnotations(MONGO_CLIENT_ANNOTATION); - for (AnnotationInstance annotation : mongoClientAnnotations) { - values.add(annotation.value().asString()); - } + addMongoClientNameValues(LEGACY_MONGO_CLIENT_ANNOTATION, indexView, values); + addMongoClientNameValues(MONGO_CLIENT_ANNOTATION, indexView, values); for (String value : values) { mongoClientName.produce(new MongoClientNameBuildItem(value)); } } + private void addMongoClientNameValues(DotName annotationName, IndexView indexView, Set values) { + Collection mongoClientAnnotations = indexView.getAnnotations(annotationName); + for (AnnotationInstance annotation : mongoClientAnnotations) { + values.add(annotation.value().asString()); + } + } + @BuildStep FeatureBuildItem feature() { return new FeatureBuildItem(Feature.MONGODB_CLIENT); @@ -139,6 +147,8 @@ void build( BuildProducer additionalBeans) { // add the @MongoClientName class otherwise it won't registered as a qualifier + additionalBeans.produce( + AdditionalBeanBuildItem.builder().addBeanClass(io.quarkus.mongodb.runtime.MongoClientName.class).build()); additionalBeans.produce(AdditionalBeanBuildItem.builder().addBeanClass(MongoClientName.class).build()); List poolListenerList = connectionPoolListenerProvider.stream() @@ -260,6 +270,7 @@ private SyntheticBeanBuildItem applyCommonBeanConfig(boolean makeUnremovable, St configurator.addQualifier().annotation(DotNames.NAMED).addValue("value", namedQualifier).done(); if (addMongoClientQualifier) { configurator.addQualifier().annotation(MONGO_CLIENT_ANNOTATION).addValue("value", clientName).done(); + configurator.addQualifier().annotation(LEGACY_MONGO_CLIENT_ANNOTATION).addValue("value", clientName).done(); } } return configurator.done(); diff --git a/extensions/mongodb-client/deployment/src/test/java/io/quarkus/mongodb/LegacyNamedMongoClientConfigTest.java b/extensions/mongodb-client/deployment/src/test/java/io/quarkus/mongodb/LegacyNamedMongoClientConfigTest.java new file mode 100644 index 00000000000000..04400ecd330666 --- /dev/null +++ b/extensions/mongodb-client/deployment/src/test/java/io/quarkus/mongodb/LegacyNamedMongoClientConfigTest.java @@ -0,0 +1,71 @@ +package io.quarkus.mongodb; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.lang.annotation.Annotation; + +import javax.enterprise.inject.Default; +import javax.inject.Inject; + +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.spec.JavaArchive; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import com.mongodb.client.MongoClient; + +import io.quarkus.arc.Arc; +import io.quarkus.arc.InjectableBean; +import io.quarkus.arc.InstanceHandle; +import io.quarkus.mongodb.runtime.MongoClientName; +import io.quarkus.test.QuarkusUnitTest; + +public class LegacyNamedMongoClientConfigTest extends MongoWithReplicasTestBase { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class).addClasses(MongoTestBase.class)) + .withConfigurationResource("application-named-mongoclient.properties"); + + @Inject + @MongoClientName("cluster1") + MongoClient client; + + @Inject + @MongoClientName("cluster2") + MongoClient client2; + + @AfterEach + void cleanup() { + if (client != null) { + client.close(); + } + if (client2 != null) { + client2.close(); + } + } + + @Test + public void testNamedDataSourceInjection() { + assertThat(client.listDatabases().first()).isNotEmpty(); + assertThat(client2.listDatabases().first()).isNotEmpty(); + + assertNoDefaultClient(); + } + + private void assertNoDefaultClient() { + boolean hasDefault = false; + for (InstanceHandle handle : Arc.container().select(MongoClient.class).handles()) { + InjectableBean bean = handle.getBean(); + for (Annotation qualifier : bean.getQualifiers()) { + if (qualifier.annotationType().equals(Default.class)) { + hasDefault = true; + } + } + } + Assertions.assertFalse(hasDefault, + "The default mongo client should not have been present as it is not used in any injection point"); + } +} diff --git a/extensions/mongodb-client/deployment/src/test/java/io/quarkus/mongodb/LegacyNamedReactiveMongoClientConfigTest.java b/extensions/mongodb-client/deployment/src/test/java/io/quarkus/mongodb/LegacyNamedReactiveMongoClientConfigTest.java new file mode 100644 index 00000000000000..54528d44f722b8 --- /dev/null +++ b/extensions/mongodb-client/deployment/src/test/java/io/quarkus/mongodb/LegacyNamedReactiveMongoClientConfigTest.java @@ -0,0 +1,99 @@ +package io.quarkus.mongodb; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; + +import javax.enterprise.inject.Default; +import javax.inject.Inject; + +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.spec.JavaArchive; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import com.mongodb.reactivestreams.client.MongoClient; +import com.mongodb.reactivestreams.client.internal.MongoClientImpl; + +import io.quarkus.arc.Arc; +import io.quarkus.arc.InjectableBean; +import io.quarkus.arc.InstanceHandle; +import io.quarkus.mongodb.impl.ReactiveMongoClientImpl; +import io.quarkus.mongodb.reactive.ReactiveMongoClient; +import io.quarkus.mongodb.runtime.MongoClientName; +import io.quarkus.test.QuarkusUnitTest; + +public class LegacyNamedReactiveMongoClientConfigTest extends MongoWithReplicasTestBase { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class).addClasses(MongoTestBase.class)) + .withConfigurationResource("application-named-mongoclient.properties"); + + @Inject + @MongoClientName("cluster1") + ReactiveMongoClient client; + + @Inject + @MongoClientName("cluster2") + ReactiveMongoClient client2; + + @AfterEach + void cleanup() { + if (client != null) { + client.close(); + } + if (client2 != null) { + client2.close(); + } + } + + @Test + public void testNamedDataSourceInjection() { + assertProperConnection(client, 27018); + assertProperConnection(client2, 27019); + + assertThat(client.listDatabases().collectItems().first().await().indefinitely()).isNotEmpty(); + assertThat(client2.listDatabases().collectItems().first().await().indefinitely()).isNotEmpty(); + + assertNoDefaultClient(); + } + + private void assertProperConnection(ReactiveMongoClient client, int expectedPort) { + assertThat(client).isInstanceOfSatisfying(ReactiveMongoClientImpl.class, rc -> { + Field mongoClientField; + try { + mongoClientField = ReactiveMongoClientImpl.class.getDeclaredField("client"); + } catch (NoSuchFieldException e) { + throw new RuntimeException(e); + } + mongoClientField.setAccessible(true); + MongoClient c; + try { + c = (MongoClientImpl) mongoClientField.get(rc); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + assertThat(c.getClusterDescription().getClusterSettings().getHosts()).hasOnlyOneElementSatisfying(sa -> { + assertThat(sa.getPort()).isEqualTo(expectedPort); + }); + }); + } + + private void assertNoDefaultClient() { + boolean hasDefault = false; + for (InstanceHandle handle : Arc.container().select(ReactiveMongoClient.class).handles()) { + InjectableBean bean = handle.getBean(); + for (Annotation qualifier : bean.getQualifiers()) { + if (qualifier.annotationType().equals(Default.class)) { + hasDefault = true; + } + } + } + Assertions.assertFalse(hasDefault, + "The default reactive mongo client should not have been present as it is not used in any injection point"); + } +} diff --git a/extensions/mongodb-client/deployment/src/test/java/io/quarkus/mongodb/NamedMongoClientConfigTest.java b/extensions/mongodb-client/deployment/src/test/java/io/quarkus/mongodb/NamedMongoClientConfigTest.java index 4362b6459752d4..1700b5d8304d5b 100644 --- a/extensions/mongodb-client/deployment/src/test/java/io/quarkus/mongodb/NamedMongoClientConfigTest.java +++ b/extensions/mongodb-client/deployment/src/test/java/io/quarkus/mongodb/NamedMongoClientConfigTest.java @@ -19,7 +19,6 @@ import io.quarkus.arc.Arc; import io.quarkus.arc.InjectableBean; import io.quarkus.arc.InstanceHandle; -import io.quarkus.mongodb.runtime.MongoClientName; import io.quarkus.test.QuarkusUnitTest; public class NamedMongoClientConfigTest extends MongoWithReplicasTestBase { diff --git a/extensions/mongodb-client/deployment/src/test/java/io/quarkus/mongodb/NamedReactiveMongoClientConfigTest.java b/extensions/mongodb-client/deployment/src/test/java/io/quarkus/mongodb/NamedReactiveMongoClientConfigTest.java index 25fa1a12c00893..494591a41f7ab4 100644 --- a/extensions/mongodb-client/deployment/src/test/java/io/quarkus/mongodb/NamedReactiveMongoClientConfigTest.java +++ b/extensions/mongodb-client/deployment/src/test/java/io/quarkus/mongodb/NamedReactiveMongoClientConfigTest.java @@ -23,7 +23,6 @@ import io.quarkus.arc.InstanceHandle; import io.quarkus.mongodb.impl.ReactiveMongoClientImpl; import io.quarkus.mongodb.reactive.ReactiveMongoClient; -import io.quarkus.mongodb.runtime.MongoClientName; import io.quarkus.test.QuarkusUnitTest; public class NamedReactiveMongoClientConfigTest extends MongoWithReplicasTestBase { diff --git a/extensions/mongodb-client/runtime/src/main/java/io/quarkus/mongodb/MongoClientName.java b/extensions/mongodb-client/runtime/src/main/java/io/quarkus/mongodb/MongoClientName.java new file mode 100644 index 00000000000000..d42db07bd2b33a --- /dev/null +++ b/extensions/mongodb-client/runtime/src/main/java/io/quarkus/mongodb/MongoClientName.java @@ -0,0 +1,40 @@ +package io.quarkus.mongodb; + +import javax.inject.Qualifier; +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * Marker annotation to select mongo connection of cluster configuration + * Use name parameter to select it + * + * For example, if a mongo connection is configured like so in {@code application.properties}: + * + *
+ * quarkus.mongodb.cluster1.connection-string=mongodb://localhost:27018
+ * 
+ * + * Then to inject the proper {@code MongoClient}, you would need to use {@code MongoClientName} like so: + * + *
+ *     @Inject
+ *     @MongoClientName("cluster1")
+ *     MongoClient client;
+ * 
+ */ +@Target({ ElementType.TYPE, ElementType.METHOD, ElementType.FIELD }) +@Retention(RUNTIME) +@Documented +@Qualifier +public @interface MongoClientName { + /** + * Specify the cluster name of the connection. + * + * @return the value + */ + String value() default ""; +} diff --git a/extensions/mongodb-client/runtime/src/main/java/io/quarkus/mongodb/runtime/MongoClientName.java b/extensions/mongodb-client/runtime/src/main/java/io/quarkus/mongodb/runtime/MongoClientName.java index 49cf1818c93305..705669547eeba8 100644 --- a/extensions/mongodb-client/runtime/src/main/java/io/quarkus/mongodb/runtime/MongoClientName.java +++ b/extensions/mongodb-client/runtime/src/main/java/io/quarkus/mongodb/runtime/MongoClientName.java @@ -12,11 +12,14 @@ /** * Marker annotation to select mongo connection of cluster configuration * Use name parameter to select it + * + * @deprecated in favor of {@link io.quarkus.mongodb.MongoClientName} */ @Target({ ElementType.TYPE, ElementType.METHOD, ElementType.FIELD }) @Retention(RUNTIME) @Documented @Qualifier +@Deprecated public @interface MongoClientName { /** * Specify the cluster name of the connection.