From f282a9a6d943e25ee7de273614c97d32a1e4a5b1 Mon Sep 17 00:00:00 2001 From: Chris Bono Date: Thu, 23 Mar 2023 12:54:20 -0500 Subject: [PATCH] Dependency hygiene required by Spring Boot (#376) --- spring-pulsar-reactive/build.gradle | 10 +++++++++- .../build.gradle | 1 + .../autoconfigure/PulsarAutoConfiguration.java | 2 ++ .../autoconfigure/PulsarAutoConfigurationTests.java | 13 +++++++++++++ spring-pulsar-spring-boot-starter/build.gradle | 1 + spring-pulsar/build.gradle | 6 ++++-- .../pulsar/core/DefaultSchemaResolver.java | 6 +++--- 7 files changed, 33 insertions(+), 6 deletions(-) diff --git a/spring-pulsar-reactive/build.gradle b/spring-pulsar-reactive/build.gradle index 4064543f..326f06cc 100644 --- a/spring-pulsar-reactive/build.gradle +++ b/spring-pulsar-reactive/build.gradle @@ -6,15 +6,23 @@ description = 'Spring Pulsar Reactive Support' dependencies { api project (':spring-pulsar') - api 'org.apache.pulsar:pulsar-client-reactive-adapter' + api ('org.apache.pulsar:pulsar-client-reactive-adapter') { + // remove when reactive client updates to 2.11 + exclude group: 'org.apache.pulsar', module: 'pulsar-client' + } implementation 'com.fasterxml.jackson.core:jackson-core' implementation 'com.fasterxml.jackson.core:jackson-databind' implementation 'com.google.code.findbugs:jsr305' optional 'com.fasterxml.jackson.datatype:jackson-datatype-jdk8' optional 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310' optional 'com.fasterxml.jackson.datatype:jackson-datatype-joda' + optional 'com.google.protobuf:protobuf-java' optional 'com.jayway.jsonpath:json-path' optional 'io.projectreactor:reactor-core' + optional ('org.apache.pulsar:pulsar-client-reactive-producer-cache-caffeine') { + // remove when reactive client updates to 2.11 + exclude group: 'org.apache.pulsar', module: 'pulsar-client-reactive-adapter' + } testImplementation project(':spring-pulsar-test') testRuntimeOnly 'ch.qos.logback:logback-classic' diff --git a/spring-pulsar-spring-boot-autoconfigure/build.gradle b/spring-pulsar-spring-boot-autoconfigure/build.gradle index 2ed2f534..02a1fd99 100644 --- a/spring-pulsar-spring-boot-autoconfigure/build.gradle +++ b/spring-pulsar-spring-boot-autoconfigure/build.gradle @@ -12,6 +12,7 @@ dependencies { optional project (':spring-pulsar') optional project (':spring-pulsar-reactive') + optional 'com.github.ben-manes.caffeine:caffeine' optional 'org.apache.pulsar:pulsar-client-reactive-producer-cache-caffeine' implementation 'org.springframework.boot:spring-boot-starter' implementation 'com.google.code.findbugs:jsr305' diff --git a/spring-pulsar-spring-boot-autoconfigure/src/main/java/org/springframework/pulsar/autoconfigure/PulsarAutoConfiguration.java b/spring-pulsar-spring-boot-autoconfigure/src/main/java/org/springframework/pulsar/autoconfigure/PulsarAutoConfiguration.java index 2bf071ba..eddc2a20 100644 --- a/spring-pulsar-spring-boot-autoconfigure/src/main/java/org/springframework/pulsar/autoconfigure/PulsarAutoConfiguration.java +++ b/spring-pulsar-spring-boot-autoconfigure/src/main/java/org/springframework/pulsar/autoconfigure/PulsarAutoConfiguration.java @@ -51,6 +51,7 @@ import org.springframework.pulsar.function.PulsarSink; import org.springframework.pulsar.function.PulsarSource; import org.springframework.pulsar.observation.PulsarTemplateObservationConvention; +import com.github.benmanes.caffeine.cache.Caffeine; import io.micrometer.observation.ObservationRegistry; /** @@ -88,6 +89,7 @@ public class PulsarAutoConfiguration { @Bean @ConditionalOnMissingBean + @ConditionalOnClass(Caffeine.class) @ConditionalOnProperty(name = "spring.pulsar.producer.cache.enabled", havingValue = "true", matchIfMissing = true) public PulsarProducerFactory cachingPulsarProducerFactory(PulsarClient pulsarClient, TopicResolver topicResolver) { diff --git a/spring-pulsar-spring-boot-autoconfigure/src/test/java/org/springframework/pulsar/autoconfigure/PulsarAutoConfigurationTests.java b/spring-pulsar-spring-boot-autoconfigure/src/test/java/org/springframework/pulsar/autoconfigure/PulsarAutoConfigurationTests.java index 3e998edc..55fc61b2 100644 --- a/spring-pulsar-spring-boot-autoconfigure/src/test/java/org/springframework/pulsar/autoconfigure/PulsarAutoConfigurationTests.java +++ b/spring-pulsar-spring-boot-autoconfigure/src/test/java/org/springframework/pulsar/autoconfigure/PulsarAutoConfigurationTests.java @@ -35,6 +35,7 @@ import org.assertj.core.api.InstanceOfAssertFactories; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.test.context.FilteredClassLoader; import org.springframework.boot.test.context.assertj.AssertableApplicationContext; @@ -68,6 +69,7 @@ import org.springframework.pulsar.listener.PulsarContainerProperties; import org.springframework.pulsar.observation.PulsarListenerObservationConvention; import org.springframework.pulsar.observation.PulsarTemplateObservationConvention; +import com.github.benmanes.caffeine.cache.Caffeine; import io.micrometer.observation.ObservationRegistry; /** @@ -498,6 +500,17 @@ class PulsarAutoConfigurationTests { .run((context -> assertHasProducerFactoryOfType(CachingPulsarProducerFactory.class, context))); } + @Test + void cachingEnabledButCaffeineNotOnClasspath() { + contextRunner.withClassLoader(new FilteredClassLoader(Caffeine.class)) + .withPropertyValues("spring.pulsar.producer.cache.enabled=true") + .run((context -> assertThat(context).hasFailed().getFailure().cause() + .isInstanceOf(NoSuchBeanDefinitionException.class) + .asInstanceOf(InstanceOfAssertFactories.type(NoSuchBeanDefinitionException.class)) + .extracting(NoSuchBeanDefinitionException::getBeanType) + .isEqualTo(PulsarProducerFactory.class))); + } + @Test void cachingProducerFactoryCanBeConfigured() { contextRunner diff --git a/spring-pulsar-spring-boot-starter/build.gradle b/spring-pulsar-spring-boot-starter/build.gradle index 422c14de..50b051c6 100644 --- a/spring-pulsar-spring-boot-starter/build.gradle +++ b/spring-pulsar-spring-boot-starter/build.gradle @@ -7,5 +7,6 @@ description = 'Spring Pulsar Spring Boot Starter' dependencies { api project (':spring-pulsar') api project (':spring-pulsar-spring-boot-autoconfigure') + api 'com.github.ben-manes.caffeine:caffeine' api 'org.springframework.boot:spring-boot-starter' } diff --git a/spring-pulsar/build.gradle b/spring-pulsar/build.gradle index c9dd99a6..1cc1a975 100644 --- a/spring-pulsar/build.gradle +++ b/spring-pulsar/build.gradle @@ -5,11 +5,11 @@ plugins { description = 'Spring Pulsar Support' dependencies { - api 'com.github.ben-manes.caffeine:caffeine' - api 'com.google.protobuf:protobuf-java' api 'io.micrometer:micrometer-observation' api ('org.apache.pulsar:pulsar-client-all') { exclude group: 'org.apache.logging.log4j' + exclude group: 'com.sun.activation', module: 'javax.activation' + exclude group: 'javax.validation', module: 'validation-api' } api 'org.springframework:spring-context' api 'org.springframework:spring-messaging' @@ -23,6 +23,8 @@ dependencies { optional 'com.fasterxml.jackson.datatype:jackson-datatype-jdk8' optional 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310' optional 'com.fasterxml.jackson.datatype:jackson-datatype-joda' + optional 'com.github.ben-manes.caffeine:caffeine' + optional 'com.google.protobuf:protobuf-java' optional 'com.jayway.jsonpath:json-path' testImplementation project(':spring-pulsar-test') diff --git a/spring-pulsar/src/main/java/org/springframework/pulsar/core/DefaultSchemaResolver.java b/spring-pulsar/src/main/java/org/springframework/pulsar/core/DefaultSchemaResolver.java index 8ad74c1a..a236dbfc 100644 --- a/spring-pulsar/src/main/java/org/springframework/pulsar/core/DefaultSchemaResolver.java +++ b/spring-pulsar/src/main/java/org/springframework/pulsar/core/DefaultSchemaResolver.java @@ -42,8 +42,6 @@ import org.springframework.core.ResolvableType; import org.springframework.core.log.LogAccessor; import org.springframework.lang.Nullable; -import com.google.protobuf.GeneratedMessageV3; - /** * Default schema resolver capable of handling basic message types. * @@ -178,8 +176,10 @@ public class DefaultSchemaResolver implements SchemaResolver { case JSON -> JSONSchema.of(requireNonNullMessageType(schemaType, messageType)); case AVRO -> AvroSchema.of(requireNonNullMessageType(schemaType, messageType)); case PROTOBUF -> { + // WARN! Leave GeneratedMessageV3 fully-qualified as the dependency is + // optional Class messageClass = requireNonNullMessageType(schemaType, messageType); - yield ProtobufSchema.of((Class) messageClass); + yield ProtobufSchema.of((Class) messageClass); } case KEY_VALUE -> { requireNonNullMessageType(schemaType, messageType);