diff --git a/spring-cloud-stream-binder-kafka-streams/src/main/java/org/springframework/cloud/stream/binder/kafka/streams/KafkaStreamsBinderSupportAutoConfiguration.java b/spring-cloud-stream-binder-kafka-streams/src/main/java/org/springframework/cloud/stream/binder/kafka/streams/KafkaStreamsBinderSupportAutoConfiguration.java
index e0507c4fd..4a96c91b1 100644
--- a/spring-cloud-stream-binder-kafka-streams/src/main/java/org/springframework/cloud/stream/binder/kafka/streams/KafkaStreamsBinderSupportAutoConfiguration.java
+++ b/spring-cloud-stream-binder-kafka-streams/src/main/java/org/springframework/cloud/stream/binder/kafka/streams/KafkaStreamsBinderSupportAutoConfiguration.java
@@ -41,6 +41,7 @@ import org.springframework.cloud.stream.binder.kafka.streams.function.FunctionDe
import org.springframework.cloud.stream.binder.kafka.streams.properties.KafkaStreamsBinderConfigurationProperties;
import org.springframework.cloud.stream.binder.kafka.streams.properties.KafkaStreamsExtendedBindingProperties;
import org.springframework.cloud.stream.binder.kafka.streams.serde.CompositeNonNativeSerde;
+import org.springframework.cloud.stream.binder.kafka.streams.serde.MessageConverterDelegateSerde;
import org.springframework.cloud.stream.binding.BindingService;
import org.springframework.cloud.stream.binding.StreamListenerResultAdapter;
import org.springframework.cloud.stream.config.BinderProperties;
@@ -274,6 +275,12 @@ public class KafkaStreamsBinderSupportAutoConfiguration {
KafkaStreamsBindingInformationCatalogue, binderConfigurationProperties);
}
+ @Bean
+ public MessageConverterDelegateSerde messageConverterDelegateSerde(
+ CompositeMessageConverter compositeMessageConverterFactory) {
+ return new MessageConverterDelegateSerde(compositeMessageConverterFactory);
+ }
+
@Bean
public CompositeNonNativeSerde compositeNonNativeSerde(
CompositeMessageConverter compositeMessageConverterFactory) {
diff --git a/spring-cloud-stream-binder-kafka-streams/src/main/java/org/springframework/cloud/stream/binder/kafka/streams/serde/CompositeNonNativeSerde.java b/spring-cloud-stream-binder-kafka-streams/src/main/java/org/springframework/cloud/stream/binder/kafka/streams/serde/CompositeNonNativeSerde.java
index d6a0ce117..ddfe65ff7 100644
--- a/spring-cloud-stream-binder-kafka-streams/src/main/java/org/springframework/cloud/stream/binder/kafka/streams/serde/CompositeNonNativeSerde.java
+++ b/spring-cloud-stream-binder-kafka-streams/src/main/java/org/springframework/cloud/stream/binder/kafka/streams/serde/CompositeNonNativeSerde.java
@@ -16,211 +16,22 @@
package org.springframework.cloud.stream.binder.kafka.streams.serde;
-import java.nio.charset.StandardCharsets;
-import java.util.HashMap;
-import java.util.Map;
-
-import org.apache.kafka.common.serialization.Deserializer;
-import org.apache.kafka.common.serialization.Serde;
-import org.apache.kafka.common.serialization.Serializer;
-
-import org.springframework.messaging.Message;
-import org.springframework.messaging.MessageHeaders;
import org.springframework.messaging.converter.CompositeMessageConverter;
-import org.springframework.messaging.converter.MessageConverter;
-import org.springframework.messaging.support.MessageBuilder;
-import org.springframework.util.Assert;
-import org.springframework.util.MimeType;
-import org.springframework.util.MimeTypeUtils;
/**
- * A {@link Serde} implementation that wraps the list of {@link MessageConverter}s from
- * {@link CompositeMessageConverter}.
+ * This class provides the same functionality as {@link MessageConverterDelegateSerde} and is deprecated.
+ * It is kept for backward compatibility reasons and will be removed in version 3.1
*
- * The primary motivation for this class is to provide an avro based {@link Serde} that is
- * compatible with the schema registry that Spring Cloud Stream provides. When using the
- * schema registry support from Spring Cloud Stream in a Kafka Streams binder based
- * application, the applications can deserialize the incoming Kafka Streams records using
- * the built in Avro {@link MessageConverter}. However, this same message conversion
- * approach will not work downstream in other operations in the topology for Kafka Streams
- * as some of them needs a {@link Serde} instance that can talk to the Spring Cloud Stream
- * provided Schema Registry. This implementation will solve that problem.
- *
- * Only Avro and JSON based converters are exposed as binder provided {@link Serde}
- * implementations currently.
- *
- * Users of this class must call the
- * {@link CompositeNonNativeSerde#configure(Map, boolean)} method to configure the
- * {@link Serde} object. At the very least the configuration map must include a key called
- * "valueClass" to indicate the type of the target object for deserialization. If any
- * other content type other than JSON is needed (only Avro is available now other than
- * JSON), that needs to be included in the configuration map with the key "contentType".
- * For example,
- *
- *
- * Map<String, Object> config = new HashMap<>();
- * config.put("valueClass", Foo.class);
- * config.put("contentType", "application/avro");
- *
- *
- * Then use the above map when calling the configure method.
- *
- * This class is only intended to be used when writing a Spring Cloud Stream Kafka Streams
- * application that uses Spring Cloud Stream schema registry for schema evolution.
- *
- * An instance of this class is provided as a bean by the binder configuration and
- * typically the applications can autowire that bean. This is the expected usage pattern
- * of this class.
- *
- * @param type of the object to marshall
* @author Soby Chacko
- * @since 2.1
+ * @sine 2.1
+ *
+ * @deprecated in favour of {@link MessageConverterDelegateSerde}
*/
-public class CompositeNonNativeSerde implements Serde {
-
- private static final String VALUE_CLASS_HEADER = "valueClass";
-
- private static final String AVRO_FORMAT = "avro";
-
- private static final MimeType DEFAULT_AVRO_MIME_TYPE = new MimeType("application",
- "*+" + AVRO_FORMAT);
-
- private final CompositeNonNativeDeserializer compositeNonNativeDeserializer;
-
- private final CompositeNonNativeSerializer compositeNonNativeSerializer;
-
- public CompositeNonNativeSerde(
- CompositeMessageConverter compositeMessageConverter) {
- this.compositeNonNativeDeserializer = new CompositeNonNativeDeserializer<>(
- compositeMessageConverter);
- this.compositeNonNativeSerializer = new CompositeNonNativeSerializer<>(
- compositeMessageConverter);
- }
-
- @Override
- public void configure(Map configs, boolean isKey) {
- this.compositeNonNativeDeserializer.configure(configs, isKey);
- this.compositeNonNativeSerializer.configure(configs, isKey);
- }
-
- @Override
- public void close() {
- // No-op
- }
-
- @Override
- public Serializer serializer() {
- return this.compositeNonNativeSerializer;
- }
-
- @Override
- public Deserializer deserializer() {
- return this.compositeNonNativeDeserializer;
- }
-
- private static MimeType resolveMimeType(Map configs) {
- if (configs.containsKey(MessageHeaders.CONTENT_TYPE)) {
- String contentType = (String) configs.get(MessageHeaders.CONTENT_TYPE);
- if (DEFAULT_AVRO_MIME_TYPE.equals(MimeTypeUtils.parseMimeType(contentType))) {
- return DEFAULT_AVRO_MIME_TYPE;
- }
- else if (contentType.contains("avro")) {
- return MimeTypeUtils.parseMimeType("application/avro");
- }
- else {
- return new MimeType("application", "json", StandardCharsets.UTF_8);
- }
- }
- else {
- return new MimeType("application", "json", StandardCharsets.UTF_8);
- }
- }
-
- /**
- * Custom {@link Deserializer} that uses the {@link CompositeMessageConverterFactory}.
- *
- * @param parameterized target type for deserialization
- */
- private static class CompositeNonNativeDeserializer implements Deserializer {
-
- private final MessageConverter messageConverter;
-
- private MimeType mimeType;
-
- private Class> valueClass;
-
- CompositeNonNativeDeserializer(
- CompositeMessageConverter compositeMessageConverter) {
- this.messageConverter = compositeMessageConverter;
- }
-
- @Override
- public void configure(Map configs, boolean isKey) {
- Assert.isTrue(configs.containsKey(VALUE_CLASS_HEADER),
- "Deserializers must provide a configuration for valueClass.");
- final Object valueClass = configs.get(VALUE_CLASS_HEADER);
- Assert.isTrue(valueClass instanceof Class,
- "Deserializers must provide a valid value for valueClass.");
- this.valueClass = (Class>) valueClass;
- this.mimeType = resolveMimeType(configs);
- }
-
- @SuppressWarnings("unchecked")
- @Override
- public U deserialize(String topic, byte[] data) {
- Message> message = MessageBuilder.withPayload(data)
- .setHeader(MessageHeaders.CONTENT_TYPE, this.mimeType.toString())
- .build();
- U messageConverted = (U) this.messageConverter.fromMessage(message,
- this.valueClass);
- Assert.notNull(messageConverted, "Deserialization failed.");
- return messageConverted;
- }
-
- @Override
- public void close() {
- // No-op
- }
-
- }
-
- /**
- * Custom {@link Serializer} that uses the {@link CompositeMessageConverterFactory}.
- *
- * @param parameterized type for serialization
- */
- private static class CompositeNonNativeSerializer implements Serializer {
-
- private final MessageConverter messageConverter;
-
- private MimeType mimeType;
-
- CompositeNonNativeSerializer(
- CompositeMessageConverter compositeMessageConverter) {
- this.messageConverter = compositeMessageConverter;
- }
-
- @Override
- public void configure(Map configs, boolean isKey) {
- this.mimeType = resolveMimeType(configs);
- }
-
- @Override
- public byte[] serialize(String topic, V data) {
- Message> message = MessageBuilder.withPayload(data).build();
- Map headers = new HashMap<>(message.getHeaders());
- headers.put(MessageHeaders.CONTENT_TYPE, this.mimeType.toString());
- MessageHeaders messageHeaders = new MessageHeaders(headers);
- final Object payload = this.messageConverter
- .toMessage(message.getPayload(), messageHeaders).getPayload();
- return (byte[]) payload;
- }
-
- @Override
- public void close() {
- // No-op
- }
+@Deprecated
+public class CompositeNonNativeSerde extends MessageConverterDelegateSerde {
+ public CompositeNonNativeSerde(CompositeMessageConverter compositeMessageConverter) {
+ super(compositeMessageConverter);
}
}
diff --git a/spring-cloud-stream-binder-kafka-streams/src/main/java/org/springframework/cloud/stream/binder/kafka/streams/serde/MessageConverterDelegateSerde.java b/spring-cloud-stream-binder-kafka-streams/src/main/java/org/springframework/cloud/stream/binder/kafka/streams/serde/MessageConverterDelegateSerde.java
new file mode 100644
index 000000000..1f6b5a5d7
--- /dev/null
+++ b/spring-cloud-stream-binder-kafka-streams/src/main/java/org/springframework/cloud/stream/binder/kafka/streams/serde/MessageConverterDelegateSerde.java
@@ -0,0 +1,226 @@
+/*
+ * Copyright 2019-2019 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.cloud.stream.binder.kafka.streams.serde;
+
+import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.kafka.common.serialization.Deserializer;
+import org.apache.kafka.common.serialization.Serde;
+import org.apache.kafka.common.serialization.Serializer;
+
+import org.springframework.messaging.Message;
+import org.springframework.messaging.MessageHeaders;
+import org.springframework.messaging.converter.CompositeMessageConverter;
+import org.springframework.messaging.converter.MessageConverter;
+import org.springframework.messaging.support.MessageBuilder;
+import org.springframework.util.Assert;
+import org.springframework.util.MimeType;
+import org.springframework.util.MimeTypeUtils;
+
+/**
+ * A {@link Serde} implementation that wraps the list of {@link MessageConverter}s from
+ * {@link CompositeMessageConverter}.
+ *
+ * The primary motivation for this class is to provide an avro based {@link Serde} that is
+ * compatible with the schema registry that Spring Cloud Stream provides. When using the
+ * schema registry support from Spring Cloud Stream in a Kafka Streams binder based
+ * application, the applications can deserialize the incoming Kafka Streams records using
+ * the built in Avro {@link MessageConverter}. However, this same message conversion
+ * approach will not work downstream in other operations in the topology for Kafka Streams
+ * as some of them needs a {@link Serde} instance that can talk to the Spring Cloud Stream
+ * provided Schema Registry. This implementation will solve that problem.
+ *
+ * Only Avro and JSON based converters are exposed as binder provided {@link Serde}
+ * implementations currently.
+ *
+ * Users of this class must call the
+ * {@link MessageConverterDelegateSerde#configure(Map, boolean)} method to configure the
+ * {@link Serde} object. At the very least the configuration map must include a key called
+ * "valueClass" to indicate the type of the target object for deserialization. If any
+ * other content type other than JSON is needed (only Avro is available now other than
+ * JSON), that needs to be included in the configuration map with the key "contentType".
+ * For example,
+ *
+ *
+ * Map<String, Object> config = new HashMap<>();
+ * config.put("valueClass", Foo.class);
+ * config.put("contentType", "application/avro");
+ *
+ *
+ * Then use the above map when calling the configure method.
+ *
+ * This class is only intended to be used when writing a Spring Cloud Stream Kafka Streams
+ * application that uses Spring Cloud Stream schema registry for schema evolution.
+ *
+ * An instance of this class is provided as a bean by the binder configuration and
+ * typically the applications can autowire that bean. This is the expected usage pattern
+ * of this class.
+ *
+ * @param type of the object to marshall
+ * @author Soby Chacko
+ * @since 3.0
+ */
+public class MessageConverterDelegateSerde implements Serde {
+
+ private static final String VALUE_CLASS_HEADER = "valueClass";
+
+ private static final String AVRO_FORMAT = "avro";
+
+ private static final MimeType DEFAULT_AVRO_MIME_TYPE = new MimeType("application",
+ "*+" + AVRO_FORMAT);
+
+ private final MessageConverterDelegateDeserializer messageConverterDelegateDeserializer;
+
+ private final MessageConverterDelegateSerializer messageConverterDelegateSerializer;
+
+ public MessageConverterDelegateSerde(
+ CompositeMessageConverter compositeMessageConverter) {
+ this.messageConverterDelegateDeserializer = new MessageConverterDelegateDeserializer<>(
+ compositeMessageConverter);
+ this.messageConverterDelegateSerializer = new MessageConverterDelegateSerializer<>(
+ compositeMessageConverter);
+ }
+
+ @Override
+ public void configure(Map configs, boolean isKey) {
+ this.messageConverterDelegateDeserializer.configure(configs, isKey);
+ this.messageConverterDelegateSerializer.configure(configs, isKey);
+ }
+
+ @Override
+ public void close() {
+ // No-op
+ }
+
+ @Override
+ public Serializer serializer() {
+ return this.messageConverterDelegateSerializer;
+ }
+
+ @Override
+ public Deserializer deserializer() {
+ return this.messageConverterDelegateDeserializer;
+ }
+
+ private static MimeType resolveMimeType(Map configs) {
+ if (configs.containsKey(MessageHeaders.CONTENT_TYPE)) {
+ String contentType = (String) configs.get(MessageHeaders.CONTENT_TYPE);
+ if (DEFAULT_AVRO_MIME_TYPE.equals(MimeTypeUtils.parseMimeType(contentType))) {
+ return DEFAULT_AVRO_MIME_TYPE;
+ }
+ else if (contentType.contains("avro")) {
+ return MimeTypeUtils.parseMimeType("application/avro");
+ }
+ else {
+ return new MimeType("application", "json", StandardCharsets.UTF_8);
+ }
+ }
+ else {
+ return new MimeType("application", "json", StandardCharsets.UTF_8);
+ }
+ }
+
+ /**
+ * Custom {@link Deserializer} that uses the {@link org.springframework.cloud.stream.converter.CompositeMessageConverterFactory}.
+ *
+ * @param parameterized target type for deserialization
+ */
+ private static class MessageConverterDelegateDeserializer implements Deserializer {
+
+ private final MessageConverter messageConverter;
+
+ private MimeType mimeType;
+
+ private Class> valueClass;
+
+ MessageConverterDelegateDeserializer(
+ CompositeMessageConverter compositeMessageConverter) {
+ this.messageConverter = compositeMessageConverter;
+ }
+
+ @Override
+ public void configure(Map configs, boolean isKey) {
+ Assert.isTrue(configs.containsKey(VALUE_CLASS_HEADER),
+ "Deserializers must provide a configuration for valueClass.");
+ final Object valueClass = configs.get(VALUE_CLASS_HEADER);
+ Assert.isTrue(valueClass instanceof Class,
+ "Deserializers must provide a valid value for valueClass.");
+ this.valueClass = (Class>) valueClass;
+ this.mimeType = resolveMimeType(configs);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public U deserialize(String topic, byte[] data) {
+ Message> message = MessageBuilder.withPayload(data)
+ .setHeader(MessageHeaders.CONTENT_TYPE, this.mimeType.toString())
+ .build();
+ U messageConverted = (U) this.messageConverter.fromMessage(message,
+ this.valueClass);
+ Assert.notNull(messageConverted, "Deserialization failed.");
+ return messageConverted;
+ }
+
+ @Override
+ public void close() {
+ // No-op
+ }
+
+ }
+
+ /**
+ * Custom {@link Serializer} that uses the {@link org.springframework.cloud.stream.converter.CompositeMessageConverterFactory}.
+ *
+ * @param parameterized type for serialization
+ */
+ private static class MessageConverterDelegateSerializer implements Serializer {
+
+ private final MessageConverter messageConverter;
+
+ private MimeType mimeType;
+
+ MessageConverterDelegateSerializer(
+ CompositeMessageConverter compositeMessageConverter) {
+ this.messageConverter = compositeMessageConverter;
+ }
+
+ @Override
+ public void configure(Map configs, boolean isKey) {
+ this.mimeType = resolveMimeType(configs);
+ }
+
+ @Override
+ public byte[] serialize(String topic, V data) {
+ Message> message = MessageBuilder.withPayload(data).build();
+ Map headers = new HashMap<>(message.getHeaders());
+ headers.put(MessageHeaders.CONTENT_TYPE, this.mimeType.toString());
+ MessageHeaders messageHeaders = new MessageHeaders(headers);
+ final Object payload = this.messageConverter
+ .toMessage(message.getPayload(), messageHeaders).getPayload();
+ return (byte[]) payload;
+ }
+
+ @Override
+ public void close() {
+ // No-op
+ }
+
+ }
+
+}
diff --git a/spring-cloud-stream-binder-kafka-streams/src/test/java/org/springframework/cloud/stream/binder/kafka/streams/serde/CompositeNonNativeSerdeTest.java b/spring-cloud-stream-binder-kafka-streams/src/test/java/org/springframework/cloud/stream/binder/kafka/streams/serde/MessageConverterDelegateSerdeTest.java
similarity index 84%
rename from spring-cloud-stream-binder-kafka-streams/src/test/java/org/springframework/cloud/stream/binder/kafka/streams/serde/CompositeNonNativeSerdeTest.java
rename to spring-cloud-stream-binder-kafka-streams/src/test/java/org/springframework/cloud/stream/binder/kafka/streams/serde/MessageConverterDelegateSerdeTest.java
index 2f3e0345a..82c68ff0b 100644
--- a/spring-cloud-stream-binder-kafka-streams/src/test/java/org/springframework/cloud/stream/binder/kafka/streams/serde/CompositeNonNativeSerdeTest.java
+++ b/spring-cloud-stream-binder-kafka-streams/src/test/java/org/springframework/cloud/stream/binder/kafka/streams/serde/MessageConverterDelegateSerdeTest.java
@@ -35,11 +35,11 @@ import org.springframework.messaging.converter.MessageConverter;
import static org.assertj.core.api.Assertions.assertThat;
/**
- * Refer {@link CompositeNonNativeSerde} for motivations.
+ * Refer {@link MessageConverterDelegateSerde} for motivations.
*
* @author Soby Chacko
*/
-public class CompositeNonNativeSerdeTest {
+public class MessageConverterDelegateSerdeTest {
@Test
@SuppressWarnings("unchecked")
@@ -55,17 +55,17 @@ public class CompositeNonNativeSerdeTest {
messageConverters.add(new AvroSchemaMessageConverter(new AvroSchemaServiceManagerImpl()));
CompositeMessageConverterFactory compositeMessageConverterFactory = new CompositeMessageConverterFactory(
messageConverters, new ObjectMapper());
- CompositeNonNativeSerde compositeNonNativeSerde = new CompositeNonNativeSerde(
+ MessageConverterDelegateSerde messageConverterDelegateSerde = new MessageConverterDelegateSerde(
compositeMessageConverterFactory.getMessageConverterForAllRegistered());
Map configs = new HashMap<>();
configs.put("valueClass", Sensor.class);
configs.put("contentType", "application/avro");
- compositeNonNativeSerde.configure(configs, false);
- final byte[] serialized = compositeNonNativeSerde.serializer().serialize(null,
+ messageConverterDelegateSerde.configure(configs, false);
+ final byte[] serialized = messageConverterDelegateSerde.serializer().serialize(null,
sensor);
- final Object deserialized = compositeNonNativeSerde.deserializer()
+ final Object deserialized = messageConverterDelegateSerde.deserializer()
.deserialize(null, serialized);
assertThat(deserialized).isEqualTo(sensor);