diff --git a/.gitignore b/.gitignore index 64a5132fd7..cf03e8a97c 100644 --- a/.gitignore +++ b/.gitignore @@ -31,3 +31,4 @@ vf.gf.dmn-* hostkey.ser .springBeans .sts4-cache +.vscode/ diff --git a/build.gradle b/build.gradle index 6e4aa3c07a..0767badbf9 100644 --- a/build.gradle +++ b/build.gradle @@ -94,6 +94,7 @@ ext { mysqlVersion = '8.0.32' pahoMqttClientVersion = '1.2.5' postgresVersion = '42.5.4' + protobufVersion = '3.21.12' r2dbch2Version = '1.0.0.RELEASE' reactorVersion = '2022.0.3' resilience4jVersion = '2.0.2' @@ -542,7 +543,7 @@ project('spring-integration-core') { optionalApi('com.fasterxml.jackson.module:jackson-module-kotlin') { exclude group: 'org.jetbrains.kotlin' } - + optionalApi "com.google.protobuf:protobuf-java:$protobufVersion" optionalApi "com.jayway.jsonpath:json-path:$jsonpathVersion" optionalApi "com.esotericsoftware:kryo:$kryoVersion" optionalApi 'io.micrometer:micrometer-core' @@ -553,6 +554,7 @@ project('spring-integration-core') { optionalApi "org.apache.avro:avro:$avroVersion" optionalApi 'org.jetbrains.kotlinx:kotlinx-coroutines-reactor' + testImplementation "com.google.protobuf:protobuf-java-util:$protobufVersion" testImplementation "org.aspectj:aspectjweaver:$aspectjVersion" testImplementation 'io.micrometer:micrometer-observation-test' testImplementation ('io.micrometer:micrometer-tracing-integration-test') { diff --git a/spring-integration-core/src/main/java/org/springframework/integration/transformer/FromProtobufTransformer.java b/spring-integration-core/src/main/java/org/springframework/integration/transformer/FromProtobufTransformer.java new file mode 100644 index 0000000000..691635732a --- /dev/null +++ b/spring-integration-core/src/main/java/org/springframework/integration/transformer/FromProtobufTransformer.java @@ -0,0 +1,140 @@ +/* + * Copyright 2023 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.integration.transformer; + +import org.springframework.beans.factory.BeanClassLoaderAware; +import org.springframework.expression.EvaluationContext; +import org.springframework.expression.Expression; +import org.springframework.integration.context.IntegrationContextUtils; +import org.springframework.integration.expression.FunctionExpression; +import org.springframework.integration.expression.ValueExpression; +import org.springframework.integration.transformer.support.ProtoHeaders; +import org.springframework.messaging.Message; +import org.springframework.messaging.converter.ProtobufMessageConverter; +import org.springframework.util.Assert; +import org.springframework.util.ClassUtils; + +/** + * A Protocol Buffer transformer to instantiate {@link com.google.protobuf.Message} objects + * from either {@code byte[]} if content type is {@code application/x-protobuf} + * or from {@code String} in case of {@code application/json} content type. + * + * @author Christian Tzolov + * + * @since 6.1 + */ +public class FromProtobufTransformer extends AbstractTransformer implements BeanClassLoaderAware { + + private final ProtobufMessageConverter protobufMessageConverter; + + private ClassLoader beanClassLoader; + + private Expression expectedTypeExpression = + new FunctionExpression>((message) -> message.getHeaders().get(ProtoHeaders.TYPE)); + + private EvaluationContext evaluationContext; + + /** + * Construct an instance with the supplied default type to create. + */ + public FromProtobufTransformer() { + this(new ProtobufMessageConverter()); + } + + /** + * Construct an instance with the supplied default type and ProtobufMessageConverter instance. + * @param protobufMessageConverter the message converter used. + */ + public FromProtobufTransformer(ProtobufMessageConverter protobufMessageConverter) { + Assert.notNull(protobufMessageConverter, "'protobufMessageConverter' must not be null"); + this.protobufMessageConverter = protobufMessageConverter; + } + + @Override + public void setBeanClassLoader(ClassLoader classLoader) { + this.beanClassLoader = classLoader; + } + + /** + * Set an expected protobuf class type. + * Mutually exclusive with {@link #setExpectedTypeExpression} and + * {@link #setExpectedTypeExpressionString}. + * @param expectedType expected protobuf class type. + * @return updated FromProtobufTransformer instance. + */ + public FromProtobufTransformer setExpectedType(Class expectedType) { + return setExpectedTypeExpression(new ValueExpression<>(expectedType)); + } + + /** + * Set an expression to evaluate against the message to determine the type id. + * Defaults to{@code headers['proto_type']}. Mutually exclusive with + * {@link #setExpectedType} and {@link #setExpectedTypeExpression}. + * @param expression the expression. + * @return updated FromProtobufTransformer instance. + */ + public FromProtobufTransformer setExpectedTypeExpressionString(String expression) { + return setExpectedTypeExpression(EXPRESSION_PARSER.parseExpression(expression)); + } + + /** + * Set an expression to evaluate against the message to determine the type. + * Default {@code headers['proto_type']}. + * Mutually exclusive with {@link #setExpectedType} and + * {@link #setExpectedTypeExpressionString}. + * @param expression the expression. + * @return updated FromProtobufTransformer instance. + */ + public FromProtobufTransformer setExpectedTypeExpression(Expression expression) { + Assert.notNull(expression, "'expression' must not be null"); + this.expectedTypeExpression = expression; + return this; + } + + @Override + protected void onInit() { + this.evaluationContext = IntegrationContextUtils.getEvaluationContext(getBeanFactory()); + } + + @SuppressWarnings("unchecked") + @Override + protected Object doTransform(Message message) { + Class targetClass = null; + Object value = this.expectedTypeExpression.getValue(this.evaluationContext, message); + if (value instanceof Class) { + targetClass = (Class) value; + } + else if (value instanceof String) { + try { + targetClass = + (Class) + ClassUtils.forName((String) value, this.beanClassLoader); + } + catch (ClassNotFoundException | LinkageError e) { + throw new IllegalStateException(e); + } + } + + if (targetClass == null) { + throw new MessageTransformationException(message, + "The 'expectedTypeExpression' (" + this.expectedTypeExpression + ") returned 'null'."); + } + + return this.protobufMessageConverter.fromMessage(message, targetClass); + } + +} diff --git a/spring-integration-core/src/main/java/org/springframework/integration/transformer/ToProtobufTransformer.java b/spring-integration-core/src/main/java/org/springframework/integration/transformer/ToProtobufTransformer.java new file mode 100644 index 0000000000..fa8f399851 --- /dev/null +++ b/spring-integration-core/src/main/java/org/springframework/integration/transformer/ToProtobufTransformer.java @@ -0,0 +1,67 @@ +/* + * Copyright 2023 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.integration.transformer; + +import org.springframework.integration.transformer.support.ProtoHeaders; +import org.springframework.messaging.Message; +import org.springframework.messaging.MessageHeaders; +import org.springframework.messaging.converter.ProtobufMessageConverter; +import org.springframework.messaging.support.MessageHeaderAccessor; +import org.springframework.util.Assert; + +/** + * A Protocol Buffer transformer for generated {@link com.google.protobuf.Message} objects. + *

+ * If the content type is set to {@code application/x-protobuf} (default if no content type), + * then the output message payload is of type byte array. + *

+ * If the content type is set to {@code application/json} and + * the {@code com.google.protobuf:protobuf-java-util} dependency is on the + * classpath, the output message payload if of type String. + * + * @author Christian Tzolov + * + * @since 6.1 + */ +public class ToProtobufTransformer extends AbstractTransformer { + + private final ProtobufMessageConverter protobufMessageConverter; + + public ToProtobufTransformer() { + this(new ProtobufMessageConverter()); + } + + public ToProtobufTransformer(ProtobufMessageConverter protobufMessageConverter) { + Assert.notNull(protobufMessageConverter, "'protobufMessageConverter' must not be null"); + this.protobufMessageConverter = protobufMessageConverter; + } + + @Override + protected Object doTransform(Message message) { + Assert.isInstanceOf(com.google.protobuf.Message.class, message.getPayload(), + "Payload must be an implementation of 'com.google.protobuf.Message'"); + + MessageHeaderAccessor accessor = new MessageHeaderAccessor(message); + accessor.setHeader(ProtoHeaders.TYPE, message.getPayload().getClass().getName()); + if (!message.getHeaders().containsKey(MessageHeaders.CONTENT_TYPE)) { + accessor.setContentType(ProtobufMessageConverter.PROTOBUF); + } + + return this.protobufMessageConverter.toMessage(message.getPayload(), accessor.getMessageHeaders()); + } + +} diff --git a/spring-integration-core/src/main/java/org/springframework/integration/transformer/support/ProtoHeaders.java b/spring-integration-core/src/main/java/org/springframework/integration/transformer/support/ProtoHeaders.java new file mode 100644 index 0000000000..059642b78c --- /dev/null +++ b/spring-integration-core/src/main/java/org/springframework/integration/transformer/support/ProtoHeaders.java @@ -0,0 +1,42 @@ +/* + * Copyright 2023 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.integration.transformer.support; + +/** + * Pre-defined names and prefixes for Protocol Buffers related headers. + * + * @author Christian Tzolov + * + * @since 6.1 + */ +public final class ProtoHeaders { + + private ProtoHeaders() { + } + + /** + * The prefix for Protocol Buffers specific message headers. + */ + public static final String PREFIX = "proto_"; + + /** + * The {@code com.google.protobuf.Message} type. By default, it's the fully qualified + * {@code com.google.protobuf.Message} type but can be a key that is mapped to the actual type. + */ + public static final String TYPE = PREFIX + "type"; + +} diff --git a/spring-integration-core/src/test/java/org/springframework/integration/transformer/ProtoTests.java b/spring-integration-core/src/test/java/org/springframework/integration/transformer/ProtoTests.java new file mode 100644 index 0000000000..2ade213c76 --- /dev/null +++ b/spring-integration-core/src/test/java/org/springframework/integration/transformer/ProtoTests.java @@ -0,0 +1,240 @@ +/* + * Copyright 2023 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.integration.transformer; + +import java.util.Collections; + +import org.junit.jupiter.api.Test; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.integration.channel.DirectChannel; +import org.springframework.integration.channel.QueueChannel; +import org.springframework.integration.config.EnableIntegration; +import org.springframework.integration.dsl.IntegrationFlow; +import org.springframework.integration.transformer.proto.TestClass1; +import org.springframework.integration.transformer.proto.TestClass2; +import org.springframework.integration.transformer.support.ProtoHeaders; +import org.springframework.messaging.Message; +import org.springframework.messaging.MessageHeaders; +import org.springframework.messaging.PollableChannel; +import org.springframework.messaging.support.GenericMessage; +import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * + * @author Christian Tzolov + * + * @since 6.1 + */ +@SpringJUnitConfig +public class ProtoTests { + + @Test + void testTransformers(@Autowired ProtoConfig config) { + TestClass1 test = TestClass1.newBuilder() + .setBar("foo") + .setQux(678) + .build(); + + config.in1().send(new GenericMessage<>(test)); + assertThat(config.tapped().receive(0)) + .isNotNull() + .extracting(Message::getPayload) + .isInstanceOf(byte[].class); + Message received = config.out().receive(0); + assertThat(received) + .isNotNull() + .extracting(Message::getPayload) + .isEqualTo(test) + .isNotSameAs(test); + assertThat(received.getHeaders().get("flow")).isEqualTo("flow1"); + } + + @Test + void testTransformersJson(@Autowired ProtoConfig config) { + TestClass1 test = TestClass1.newBuilder() + .setBar("foo") + .setQux(678) + .build(); + + config.in1().send(new GenericMessage<>(test, + Collections.singletonMap(MessageHeaders.CONTENT_TYPE, "application/json"))); + assertThat(config.tapped().receive(0)) + .isNotNull() + .extracting(Message::getPayload) + .isInstanceOf(String.class) + .isEqualTo("{\n \"bar\": \"foo\",\n \"qux\": 678\n}"); + Message received = config.out().receive(0); + assertThat(received) + .isNotNull() + .extracting(Message::getPayload) + .isEqualTo(test) + .isNotSameAs(test); + assertThat(received.getHeaders().get("flow")).isEqualTo("flow1"); + } + + @Test + void testMultiTypeTransformers(@Autowired ProtoConfig config) { + TestClass1 test = TestClass1.newBuilder() + .setBar("foo") + .setQux(678) + .build(); + config.in2().send(new GenericMessage<>(test)); + assertThat(config.tapped().receive(0)) + .isNotNull() + .extracting(Message::getPayload) + .isInstanceOf(byte[].class); + Message received = config.out().receive(0); + assertThat(received) + .isNotNull() + .extracting(Message::getPayload) + .isNotEqualTo(test) + .isInstanceOf(TestClass2.class); + assertThat(received.getHeaders().get("flow")).isEqualTo("flow2"); + } + + @Test + void testMultiTypeTransformersClassName(@Autowired ProtoConfig config) { + TestClass1 test = TestClass1.newBuilder() + .setBar("foo") + .setQux(678) + .build(); + config.in3().send(new GenericMessage<>(test)); + assertThat(config.tapped().receive(0)) + .isNotNull() + .extracting(Message::getPayload) + .isInstanceOf(byte[].class); + Message received = config.out().receive(0); + assertThat(received) + .isNotNull() + .extracting(Message::getPayload) + .isNotEqualTo(test) + .isInstanceOf(TestClass2.class); + assertThat(received.getHeaders().get("flow")).isEqualTo("flow3"); + } + + @Test + void testTransformersNoHeaderPresent(@Autowired ProtoConfig config) { + TestClass1 test = TestClass1.newBuilder() + .setBar("foo") + .setQux(678) + .build(); + config.in4().send(new GenericMessage<>(test)); + assertThat(config.tapped().receive(0)) + .isNotNull() + .extracting(Message::getPayload) + .isInstanceOf(byte[].class); + Message received = config.out().receive(0); + assertThat(received) + .isNotNull() + .extracting(Message::getPayload) + .isEqualTo(test) + .isNotSameAs(test); + assertThat(received.getHeaders().get("flow")).isEqualTo("flow4"); + } + + @Configuration + @EnableIntegration + public static class ProtoConfig { + + @Bean + public IntegrationFlow flow1() { + return IntegrationFlow.from(in1()) + .transform(new ToProtobufTransformer()) + .wireTap(tapped()) + .transform(new FromProtobufTransformer()) + .enrichHeaders(h -> h.header("flow", "flow1")) + .channel(out()) + .get(); + } + + @Bean + public IntegrationFlow flow2() { + return IntegrationFlow.from(in2()) + .transform(new ToProtobufTransformer()) + .wireTap(tapped()) + .enrichHeaders(h -> h.header(ProtoHeaders.TYPE, TestClass2.class, true)) + .transform(new FromProtobufTransformer()) + .enrichHeaders(h -> h.header("flow", "flow2")) + .channel(out()) + .get(); + } + + @Bean + public IntegrationFlow flow3() { + return IntegrationFlow.from(in3()) + .transform(new ToProtobufTransformer()) + .wireTap(tapped()) + .enrichHeaders(h -> h.header(ProtoHeaders.TYPE, TestClass2.class.getName(), + true)) + .transform(new FromProtobufTransformer()) + .enrichHeaders(h -> h.header("flow", "flow3")) + .channel(out()) + .get(); + } + + @Bean + public IntegrationFlow flow4() { + return IntegrationFlow.from(in4()) + .transform(new ToProtobufTransformer()) + .wireTap(tapped()) + .enrichHeaders(h -> h.header(ProtoHeaders.TYPE, null, true) + .shouldSkipNulls(false)) + .transform(new FromProtobufTransformer() + .setExpectedType(TestClass1.class)) + .enrichHeaders(h -> h.header("flow", "flow4")) + .channel(out()) + .get(); + } + + @Bean + public DirectChannel in1() { + return new DirectChannel(); + } + + @Bean + public DirectChannel in2() { + return new DirectChannel(); + } + + @Bean + public DirectChannel in3() { + return new DirectChannel(); + } + + @Bean + public DirectChannel in4() { + return new DirectChannel(); + } + + @Bean + public PollableChannel tapped() { + return new QueueChannel(); + } + + @Bean + public PollableChannel out() { + return new QueueChannel(); + } + + } + +} diff --git a/spring-integration-core/src/test/java/org/springframework/integration/transformer/proto/TestClass1.java b/spring-integration-core/src/test/java/org/springframework/integration/transformer/proto/TestClass1.java new file mode 100644 index 0000000000..2e8e1306e8 --- /dev/null +++ b/spring-integration-core/src/test/java/org/springframework/integration/transformer/proto/TestClass1.java @@ -0,0 +1,671 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: ProtoTest.proto + +package org.springframework.integration.transformer.proto; + +/** + * Protobuf type {@code tutorial.TestClass1} + */ +public final class TestClass1 extends + com.google.protobuf.GeneratedMessageV3 implements + // @@protoc_insertion_point(message_implements:tutorial.TestClass1) + TestClass1OrBuilder { +private static final long serialVersionUID = 0L; + // Use TestClass1.newBuilder() to construct. + private TestClass1(com.google.protobuf.GeneratedMessageV3.Builder builder) { + super(builder); + } + private TestClass1() { + bar_ = ""; + } + + @java.lang.Override + @SuppressWarnings({"unused"}) + protected java.lang.Object newInstance( + UnusedPrivateParameter unused) { + return new TestClass1(); + } + + @java.lang.Override + public final com.google.protobuf.UnknownFieldSet + getUnknownFields() { + return this.unknownFields; + } + private TestClass1( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + this(); + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + int mutable_bitField0_ = 0; + com.google.protobuf.UnknownFieldSet.Builder unknownFields = + com.google.protobuf.UnknownFieldSet.newBuilder(); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + com.google.protobuf.ByteString bs = input.readBytes(); + bitField0_ |= 0x00000001; + bar_ = bs; + break; + } + case 16: { + bitField0_ |= 0x00000002; + qux_ = input.readInt32(); + break; + } + default: { + if (!parseUnknownField( + input, unknownFields, extensionRegistry, tag)) { + done = true; + } + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e).setUnfinishedMessage(this); + } finally { + this.unknownFields = unknownFields.build(); + makeExtensionsImmutable(); + } + } + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.springframework.integration.transformer.proto.TestProtos.internal_static_tutorial_TestClass1_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.springframework.integration.transformer.proto.TestProtos.internal_static_tutorial_TestClass1_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.springframework.integration.transformer.proto.TestClass1.class, org.springframework.integration.transformer.proto.TestClass1.Builder.class); + } + + private int bitField0_; + public static final int BAR_FIELD_NUMBER = 1; + private volatile java.lang.Object bar_; + /** + * optional string bar = 1; + * @return Whether the bar field is set. + */ + public boolean hasBar() { + return ((bitField0_ & 0x00000001) != 0); + } + /** + * optional string bar = 1; + * @return The bar. + */ + public java.lang.String getBar() { + java.lang.Object ref = bar_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + bar_ = s; + } + return s; + } + } + /** + * optional string bar = 1; + * @return The bytes for bar. + */ + public com.google.protobuf.ByteString + getBarBytes() { + java.lang.Object ref = bar_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + bar_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int QUX_FIELD_NUMBER = 2; + private int qux_; + /** + * optional int32 qux = 2; + * @return Whether the qux field is set. + */ + public boolean hasQux() { + return ((bitField0_ & 0x00000002) != 0); + } + /** + * optional int32 qux = 2; + * @return The qux. + */ + public int getQux() { + return qux_; + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (((bitField0_ & 0x00000001) != 0)) { + com.google.protobuf.GeneratedMessageV3.writeString(output, 1, bar_); + } + if (((bitField0_ & 0x00000002) != 0)) { + output.writeInt32(2, qux_); + } + unknownFields.writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) != 0)) { + size += com.google.protobuf.GeneratedMessageV3.computeStringSize(1, bar_); + } + if (((bitField0_ & 0x00000002) != 0)) { + size += com.google.protobuf.CodedOutputStream + .computeInt32Size(2, qux_); + } + size += unknownFields.getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.springframework.integration.transformer.proto.TestClass1)) { + return super.equals(obj); + } + org.springframework.integration.transformer.proto.TestClass1 other = (org.springframework.integration.transformer.proto.TestClass1) obj; + + if (hasBar() != other.hasBar()) return false; + if (hasBar()) { + if (!getBar() + .equals(other.getBar())) return false; + } + if (hasQux() != other.hasQux()) return false; + if (hasQux()) { + if (getQux() + != other.getQux()) return false; + } + if (!unknownFields.equals(other.unknownFields)) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + if (hasBar()) { + hash = (37 * hash) + BAR_FIELD_NUMBER; + hash = (53 * hash) + getBar().hashCode(); + } + if (hasQux()) { + hash = (37 * hash) + QUX_FIELD_NUMBER; + hash = (53 * hash) + getQux(); + } + hash = (29 * hash) + unknownFields.hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.springframework.integration.transformer.proto.TestClass1 parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.springframework.integration.transformer.proto.TestClass1 parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.springframework.integration.transformer.proto.TestClass1 parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.springframework.integration.transformer.proto.TestClass1 parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.springframework.integration.transformer.proto.TestClass1 parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.springframework.integration.transformer.proto.TestClass1 parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.springframework.integration.transformer.proto.TestClass1 parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + public static org.springframework.integration.transformer.proto.TestClass1 parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + public static org.springframework.integration.transformer.proto.TestClass1 parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input); + } + public static org.springframework.integration.transformer.proto.TestClass1 parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.springframework.integration.transformer.proto.TestClass1 parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + public static org.springframework.integration.transformer.proto.TestClass1 parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.springframework.integration.transformer.proto.TestClass1 prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + * Protobuf type {@code tutorial.TestClass1} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageV3.Builder implements + // @@protoc_insertion_point(builder_implements:tutorial.TestClass1) + org.springframework.integration.transformer.proto.TestClass1OrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.springframework.integration.transformer.proto.TestProtos.internal_static_tutorial_TestClass1_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.springframework.integration.transformer.proto.TestProtos.internal_static_tutorial_TestClass1_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.springframework.integration.transformer.proto.TestClass1.class, org.springframework.integration.transformer.proto.TestClass1.Builder.class); + } + + // Construct using org.springframework.integration.transformer.proto.TestClass1.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessageV3 + .alwaysUseFieldBuilders) { + } + } + @java.lang.Override + public Builder clear() { + super.clear(); + bar_ = ""; + bitField0_ = (bitField0_ & ~0x00000001); + qux_ = 0; + bitField0_ = (bitField0_ & ~0x00000002); + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return org.springframework.integration.transformer.proto.TestProtos.internal_static_tutorial_TestClass1_descriptor; + } + + @java.lang.Override + public org.springframework.integration.transformer.proto.TestClass1 getDefaultInstanceForType() { + return org.springframework.integration.transformer.proto.TestClass1.getDefaultInstance(); + } + + @java.lang.Override + public org.springframework.integration.transformer.proto.TestClass1 build() { + org.springframework.integration.transformer.proto.TestClass1 result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.springframework.integration.transformer.proto.TestClass1 buildPartial() { + org.springframework.integration.transformer.proto.TestClass1 result = new org.springframework.integration.transformer.proto.TestClass1(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) != 0)) { + to_bitField0_ |= 0x00000001; + } + result.bar_ = bar_; + if (((from_bitField0_ & 0x00000002) != 0)) { + result.qux_ = qux_; + to_bitField0_ |= 0x00000002; + } + result.bitField0_ = to_bitField0_; + onBuilt(); + return result; + } + + @java.lang.Override + public Builder clone() { + return super.clone(); + } + @java.lang.Override + public Builder setField( + com.google.protobuf.Descriptors.FieldDescriptor field, + java.lang.Object value) { + return super.setField(field, value); + } + @java.lang.Override + public Builder clearField( + com.google.protobuf.Descriptors.FieldDescriptor field) { + return super.clearField(field); + } + @java.lang.Override + public Builder clearOneof( + com.google.protobuf.Descriptors.OneofDescriptor oneof) { + return super.clearOneof(oneof); + } + @java.lang.Override + public Builder setRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, + int index, java.lang.Object value) { + return super.setRepeatedField(field, index, value); + } + @java.lang.Override + public Builder addRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, + java.lang.Object value) { + return super.addRepeatedField(field, value); + } + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.springframework.integration.transformer.proto.TestClass1) { + return mergeFrom((org.springframework.integration.transformer.proto.TestClass1)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.springframework.integration.transformer.proto.TestClass1 other) { + if (other == org.springframework.integration.transformer.proto.TestClass1.getDefaultInstance()) return this; + if (other.hasBar()) { + bitField0_ |= 0x00000001; + bar_ = other.bar_; + onChanged(); + } + if (other.hasQux()) { + setQux(other.getQux()); + } + this.mergeUnknownFields(other.unknownFields); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + org.springframework.integration.transformer.proto.TestClass1 parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (org.springframework.integration.transformer.proto.TestClass1) e.getUnfinishedMessage(); + throw e.unwrapIOException(); + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private java.lang.Object bar_ = ""; + /** + * optional string bar = 1; + * @return Whether the bar field is set. + */ + public boolean hasBar() { + return ((bitField0_ & 0x00000001) != 0); + } + /** + * optional string bar = 1; + * @return The bar. + */ + public java.lang.String getBar() { + java.lang.Object ref = bar_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + bar_ = s; + } + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * optional string bar = 1; + * @return The bytes for bar. + */ + public com.google.protobuf.ByteString + getBarBytes() { + java.lang.Object ref = bar_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + bar_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * optional string bar = 1; + * @param value The bar to set. + * @return This builder for chaining. + */ + public Builder setBar( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000001; + bar_ = value; + onChanged(); + return this; + } + /** + * optional string bar = 1; + * @return This builder for chaining. + */ + public Builder clearBar() { + bitField0_ = (bitField0_ & ~0x00000001); + bar_ = getDefaultInstance().getBar(); + onChanged(); + return this; + } + /** + * optional string bar = 1; + * @param value The bytes for bar to set. + * @return This builder for chaining. + */ + public Builder setBarBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000001; + bar_ = value; + onChanged(); + return this; + } + + private int qux_ ; + /** + * optional int32 qux = 2; + * @return Whether the qux field is set. + */ + public boolean hasQux() { + return ((bitField0_ & 0x00000002) != 0); + } + /** + * optional int32 qux = 2; + * @return The qux. + */ + public int getQux() { + return qux_; + } + /** + * optional int32 qux = 2; + * @param value The qux to set. + * @return This builder for chaining. + */ + public Builder setQux(int value) { + bitField0_ |= 0x00000002; + qux_ = value; + onChanged(); + return this; + } + /** + * optional int32 qux = 2; + * @return This builder for chaining. + */ + public Builder clearQux() { + bitField0_ = (bitField0_ & ~0x00000002); + qux_ = 0; + onChanged(); + return this; + } + @java.lang.Override + public final Builder setUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return super.setUnknownFields(unknownFields); + } + + @java.lang.Override + public final Builder mergeUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return super.mergeUnknownFields(unknownFields); + } + + + // @@protoc_insertion_point(builder_scope:tutorial.TestClass1) + } + + // @@protoc_insertion_point(class_scope:tutorial.TestClass1) + private static final org.springframework.integration.transformer.proto.TestClass1 DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.springframework.integration.transformer.proto.TestClass1(); + } + + public static org.springframework.integration.transformer.proto.TestClass1 getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + @java.lang.Deprecated public static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public TestClass1 parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new TestClass1(input, extensionRegistry); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.springframework.integration.transformer.proto.TestClass1 getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/spring-integration-core/src/test/java/org/springframework/integration/transformer/proto/TestClass1OrBuilder.java b/spring-integration-core/src/test/java/org/springframework/integration/transformer/proto/TestClass1OrBuilder.java new file mode 100644 index 0000000000..18c6b84006 --- /dev/null +++ b/spring-integration-core/src/test/java/org/springframework/integration/transformer/proto/TestClass1OrBuilder.java @@ -0,0 +1,37 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: ProtoTest.proto + +package org.springframework.integration.transformer.proto; + +public interface TestClass1OrBuilder extends + // @@protoc_insertion_point(interface_extends:tutorial.TestClass1) + com.google.protobuf.MessageOrBuilder { + + /** + * optional string bar = 1; + * @return Whether the bar field is set. + */ + boolean hasBar(); + /** + * optional string bar = 1; + * @return The bar. + */ + java.lang.String getBar(); + /** + * optional string bar = 1; + * @return The bytes for bar. + */ + com.google.protobuf.ByteString + getBarBytes(); + + /** + * optional int32 qux = 2; + * @return Whether the qux field is set. + */ + boolean hasQux(); + /** + * optional int32 qux = 2; + * @return The qux. + */ + int getQux(); +} diff --git a/spring-integration-core/src/test/java/org/springframework/integration/transformer/proto/TestClass2.java b/spring-integration-core/src/test/java/org/springframework/integration/transformer/proto/TestClass2.java new file mode 100644 index 0000000000..7cd71369c2 --- /dev/null +++ b/spring-integration-core/src/test/java/org/springframework/integration/transformer/proto/TestClass2.java @@ -0,0 +1,671 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: ProtoTest.proto + +package org.springframework.integration.transformer.proto; + +/** + * Protobuf type {@code tutorial.TestClass2} + */ +public final class TestClass2 extends + com.google.protobuf.GeneratedMessageV3 implements + // @@protoc_insertion_point(message_implements:tutorial.TestClass2) + TestClass2OrBuilder { +private static final long serialVersionUID = 0L; + // Use TestClass2.newBuilder() to construct. + private TestClass2(com.google.protobuf.GeneratedMessageV3.Builder builder) { + super(builder); + } + private TestClass2() { + bar_ = ""; + } + + @java.lang.Override + @SuppressWarnings({"unused"}) + protected java.lang.Object newInstance( + UnusedPrivateParameter unused) { + return new TestClass2(); + } + + @java.lang.Override + public final com.google.protobuf.UnknownFieldSet + getUnknownFields() { + return this.unknownFields; + } + private TestClass2( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + this(); + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + int mutable_bitField0_ = 0; + com.google.protobuf.UnknownFieldSet.Builder unknownFields = + com.google.protobuf.UnknownFieldSet.newBuilder(); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + com.google.protobuf.ByteString bs = input.readBytes(); + bitField0_ |= 0x00000001; + bar_ = bs; + break; + } + case 16: { + bitField0_ |= 0x00000002; + qux_ = input.readInt32(); + break; + } + default: { + if (!parseUnknownField( + input, unknownFields, extensionRegistry, tag)) { + done = true; + } + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e).setUnfinishedMessage(this); + } finally { + this.unknownFields = unknownFields.build(); + makeExtensionsImmutable(); + } + } + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.springframework.integration.transformer.proto.TestProtos.internal_static_tutorial_TestClass2_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.springframework.integration.transformer.proto.TestProtos.internal_static_tutorial_TestClass2_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.springframework.integration.transformer.proto.TestClass2.class, org.springframework.integration.transformer.proto.TestClass2.Builder.class); + } + + private int bitField0_; + public static final int BAR_FIELD_NUMBER = 1; + private volatile java.lang.Object bar_; + /** + * optional string bar = 1; + * @return Whether the bar field is set. + */ + public boolean hasBar() { + return ((bitField0_ & 0x00000001) != 0); + } + /** + * optional string bar = 1; + * @return The bar. + */ + public java.lang.String getBar() { + java.lang.Object ref = bar_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + bar_ = s; + } + return s; + } + } + /** + * optional string bar = 1; + * @return The bytes for bar. + */ + public com.google.protobuf.ByteString + getBarBytes() { + java.lang.Object ref = bar_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + bar_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int QUX_FIELD_NUMBER = 2; + private int qux_; + /** + * optional int32 qux = 2; + * @return Whether the qux field is set. + */ + public boolean hasQux() { + return ((bitField0_ & 0x00000002) != 0); + } + /** + * optional int32 qux = 2; + * @return The qux. + */ + public int getQux() { + return qux_; + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (((bitField0_ & 0x00000001) != 0)) { + com.google.protobuf.GeneratedMessageV3.writeString(output, 1, bar_); + } + if (((bitField0_ & 0x00000002) != 0)) { + output.writeInt32(2, qux_); + } + unknownFields.writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) != 0)) { + size += com.google.protobuf.GeneratedMessageV3.computeStringSize(1, bar_); + } + if (((bitField0_ & 0x00000002) != 0)) { + size += com.google.protobuf.CodedOutputStream + .computeInt32Size(2, qux_); + } + size += unknownFields.getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.springframework.integration.transformer.proto.TestClass2)) { + return super.equals(obj); + } + org.springframework.integration.transformer.proto.TestClass2 other = (org.springframework.integration.transformer.proto.TestClass2) obj; + + if (hasBar() != other.hasBar()) return false; + if (hasBar()) { + if (!getBar() + .equals(other.getBar())) return false; + } + if (hasQux() != other.hasQux()) return false; + if (hasQux()) { + if (getQux() + != other.getQux()) return false; + } + if (!unknownFields.equals(other.unknownFields)) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + if (hasBar()) { + hash = (37 * hash) + BAR_FIELD_NUMBER; + hash = (53 * hash) + getBar().hashCode(); + } + if (hasQux()) { + hash = (37 * hash) + QUX_FIELD_NUMBER; + hash = (53 * hash) + getQux(); + } + hash = (29 * hash) + unknownFields.hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.springframework.integration.transformer.proto.TestClass2 parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.springframework.integration.transformer.proto.TestClass2 parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.springframework.integration.transformer.proto.TestClass2 parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.springframework.integration.transformer.proto.TestClass2 parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.springframework.integration.transformer.proto.TestClass2 parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.springframework.integration.transformer.proto.TestClass2 parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.springframework.integration.transformer.proto.TestClass2 parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + public static org.springframework.integration.transformer.proto.TestClass2 parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + public static org.springframework.integration.transformer.proto.TestClass2 parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input); + } + public static org.springframework.integration.transformer.proto.TestClass2 parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.springframework.integration.transformer.proto.TestClass2 parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + public static org.springframework.integration.transformer.proto.TestClass2 parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.springframework.integration.transformer.proto.TestClass2 prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + * Protobuf type {@code tutorial.TestClass2} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageV3.Builder implements + // @@protoc_insertion_point(builder_implements:tutorial.TestClass2) + org.springframework.integration.transformer.proto.TestClass2OrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.springframework.integration.transformer.proto.TestProtos.internal_static_tutorial_TestClass2_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.springframework.integration.transformer.proto.TestProtos.internal_static_tutorial_TestClass2_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.springframework.integration.transformer.proto.TestClass2.class, org.springframework.integration.transformer.proto.TestClass2.Builder.class); + } + + // Construct using org.springframework.integration.transformer.proto.TestClass2.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessageV3 + .alwaysUseFieldBuilders) { + } + } + @java.lang.Override + public Builder clear() { + super.clear(); + bar_ = ""; + bitField0_ = (bitField0_ & ~0x00000001); + qux_ = 0; + bitField0_ = (bitField0_ & ~0x00000002); + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return org.springframework.integration.transformer.proto.TestProtos.internal_static_tutorial_TestClass2_descriptor; + } + + @java.lang.Override + public org.springframework.integration.transformer.proto.TestClass2 getDefaultInstanceForType() { + return org.springframework.integration.transformer.proto.TestClass2.getDefaultInstance(); + } + + @java.lang.Override + public org.springframework.integration.transformer.proto.TestClass2 build() { + org.springframework.integration.transformer.proto.TestClass2 result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.springframework.integration.transformer.proto.TestClass2 buildPartial() { + org.springframework.integration.transformer.proto.TestClass2 result = new org.springframework.integration.transformer.proto.TestClass2(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) != 0)) { + to_bitField0_ |= 0x00000001; + } + result.bar_ = bar_; + if (((from_bitField0_ & 0x00000002) != 0)) { + result.qux_ = qux_; + to_bitField0_ |= 0x00000002; + } + result.bitField0_ = to_bitField0_; + onBuilt(); + return result; + } + + @java.lang.Override + public Builder clone() { + return super.clone(); + } + @java.lang.Override + public Builder setField( + com.google.protobuf.Descriptors.FieldDescriptor field, + java.lang.Object value) { + return super.setField(field, value); + } + @java.lang.Override + public Builder clearField( + com.google.protobuf.Descriptors.FieldDescriptor field) { + return super.clearField(field); + } + @java.lang.Override + public Builder clearOneof( + com.google.protobuf.Descriptors.OneofDescriptor oneof) { + return super.clearOneof(oneof); + } + @java.lang.Override + public Builder setRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, + int index, java.lang.Object value) { + return super.setRepeatedField(field, index, value); + } + @java.lang.Override + public Builder addRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, + java.lang.Object value) { + return super.addRepeatedField(field, value); + } + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.springframework.integration.transformer.proto.TestClass2) { + return mergeFrom((org.springframework.integration.transformer.proto.TestClass2)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.springframework.integration.transformer.proto.TestClass2 other) { + if (other == org.springframework.integration.transformer.proto.TestClass2.getDefaultInstance()) return this; + if (other.hasBar()) { + bitField0_ |= 0x00000001; + bar_ = other.bar_; + onChanged(); + } + if (other.hasQux()) { + setQux(other.getQux()); + } + this.mergeUnknownFields(other.unknownFields); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + org.springframework.integration.transformer.proto.TestClass2 parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (org.springframework.integration.transformer.proto.TestClass2) e.getUnfinishedMessage(); + throw e.unwrapIOException(); + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + private java.lang.Object bar_ = ""; + /** + * optional string bar = 1; + * @return Whether the bar field is set. + */ + public boolean hasBar() { + return ((bitField0_ & 0x00000001) != 0); + } + /** + * optional string bar = 1; + * @return The bar. + */ + public java.lang.String getBar() { + java.lang.Object ref = bar_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + bar_ = s; + } + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * optional string bar = 1; + * @return The bytes for bar. + */ + public com.google.protobuf.ByteString + getBarBytes() { + java.lang.Object ref = bar_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + bar_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * optional string bar = 1; + * @param value The bar to set. + * @return This builder for chaining. + */ + public Builder setBar( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000001; + bar_ = value; + onChanged(); + return this; + } + /** + * optional string bar = 1; + * @return This builder for chaining. + */ + public Builder clearBar() { + bitField0_ = (bitField0_ & ~0x00000001); + bar_ = getDefaultInstance().getBar(); + onChanged(); + return this; + } + /** + * optional string bar = 1; + * @param value The bytes for bar to set. + * @return This builder for chaining. + */ + public Builder setBarBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000001; + bar_ = value; + onChanged(); + return this; + } + + private int qux_ ; + /** + * optional int32 qux = 2; + * @return Whether the qux field is set. + */ + public boolean hasQux() { + return ((bitField0_ & 0x00000002) != 0); + } + /** + * optional int32 qux = 2; + * @return The qux. + */ + public int getQux() { + return qux_; + } + /** + * optional int32 qux = 2; + * @param value The qux to set. + * @return This builder for chaining. + */ + public Builder setQux(int value) { + bitField0_ |= 0x00000002; + qux_ = value; + onChanged(); + return this; + } + /** + * optional int32 qux = 2; + * @return This builder for chaining. + */ + public Builder clearQux() { + bitField0_ = (bitField0_ & ~0x00000002); + qux_ = 0; + onChanged(); + return this; + } + @java.lang.Override + public final Builder setUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return super.setUnknownFields(unknownFields); + } + + @java.lang.Override + public final Builder mergeUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return super.mergeUnknownFields(unknownFields); + } + + + // @@protoc_insertion_point(builder_scope:tutorial.TestClass2) + } + + // @@protoc_insertion_point(class_scope:tutorial.TestClass2) + private static final org.springframework.integration.transformer.proto.TestClass2 DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.springframework.integration.transformer.proto.TestClass2(); + } + + public static org.springframework.integration.transformer.proto.TestClass2 getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + @java.lang.Deprecated public static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public TestClass2 parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new TestClass2(input, extensionRegistry); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.springframework.integration.transformer.proto.TestClass2 getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + +} + diff --git a/spring-integration-core/src/test/java/org/springframework/integration/transformer/proto/TestClass2OrBuilder.java b/spring-integration-core/src/test/java/org/springframework/integration/transformer/proto/TestClass2OrBuilder.java new file mode 100644 index 0000000000..85324537e9 --- /dev/null +++ b/spring-integration-core/src/test/java/org/springframework/integration/transformer/proto/TestClass2OrBuilder.java @@ -0,0 +1,37 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: ProtoTest.proto + +package org.springframework.integration.transformer.proto; + +public interface TestClass2OrBuilder extends + // @@protoc_insertion_point(interface_extends:tutorial.TestClass2) + com.google.protobuf.MessageOrBuilder { + + /** + * optional string bar = 1; + * @return Whether the bar field is set. + */ + boolean hasBar(); + /** + * optional string bar = 1; + * @return The bar. + */ + java.lang.String getBar(); + /** + * optional string bar = 1; + * @return The bytes for bar. + */ + com.google.protobuf.ByteString + getBarBytes(); + + /** + * optional int32 qux = 2; + * @return Whether the qux field is set. + */ + boolean hasQux(); + /** + * optional int32 qux = 2; + * @return The qux. + */ + int getQux(); +} diff --git a/spring-integration-core/src/test/java/org/springframework/integration/transformer/proto/TestProtos.java b/spring-integration-core/src/test/java/org/springframework/integration/transformer/proto/TestProtos.java new file mode 100644 index 0000000000..0f6d383ca5 --- /dev/null +++ b/spring-integration-core/src/test/java/org/springframework/integration/transformer/proto/TestProtos.java @@ -0,0 +1,61 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: ProtoTest.proto + +package org.springframework.integration.transformer.proto; + +public final class TestProtos { + private TestProtos() {} + public static void registerAllExtensions( + com.google.protobuf.ExtensionRegistryLite registry) { + } + + public static void registerAllExtensions( + com.google.protobuf.ExtensionRegistry registry) { + registerAllExtensions( + (com.google.protobuf.ExtensionRegistryLite) registry); + } + static final com.google.protobuf.Descriptors.Descriptor + internal_static_tutorial_TestClass1_descriptor; + static final + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internal_static_tutorial_TestClass1_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_tutorial_TestClass2_descriptor; + static final + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internal_static_tutorial_TestClass2_fieldAccessorTable; + + public static com.google.protobuf.Descriptors.FileDescriptor + getDescriptor() { + return descriptor; + } + private static com.google.protobuf.Descriptors.FileDescriptor + descriptor; + static { + java.lang.String[] descriptorData = { + "\n\017ProtoTest.proto\022\010tutorial\"&\n\nTestClass" + + "1\022\013\n\003bar\030\001 \001(\t\022\013\n\003qux\030\002 \001(\005\"&\n\nTestClass" + + "2\022\013\n\003bar\030\001 \001(\t\022\013\n\003qux\030\002 \001(\005BA\n1org.sprin" + + "gframework.integration.transformer.proto" + + "B\nTestProtosP\001" + }; + descriptor = com.google.protobuf.Descriptors.FileDescriptor + .internalBuildGeneratedFileFrom(descriptorData, + new com.google.protobuf.Descriptors.FileDescriptor[] { + }); + internal_static_tutorial_TestClass1_descriptor = + getDescriptor().getMessageTypes().get(0); + internal_static_tutorial_TestClass1_fieldAccessorTable = new + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( + internal_static_tutorial_TestClass1_descriptor, + new java.lang.String[] { "Bar", "Qux", }); + internal_static_tutorial_TestClass2_descriptor = + getDescriptor().getMessageTypes().get(1); + internal_static_tutorial_TestClass2_fieldAccessorTable = new + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( + internal_static_tutorial_TestClass2_descriptor, + new java.lang.String[] { "Bar", "Qux", }); + } + + // @@protoc_insertion_point(outer_class_scope) +} diff --git a/spring-integration-core/src/test/resources/proto/ProtoTest.proto b/spring-integration-core/src/test/resources/proto/ProtoTest.proto new file mode 100644 index 0000000000..a0ae119f80 --- /dev/null +++ b/spring-integration-core/src/test/resources/proto/ProtoTest.proto @@ -0,0 +1,17 @@ +syntax = "proto2"; + +package tutorial; + +option java_multiple_files = true; +option java_package = "org.springframework.integration.transformer.proto"; +option java_outer_classname = "TestProtos"; + +message TestClass1 { + optional string bar = 1; + optional int32 qux = 2; +} + +message TestClass2 { + optional string bar = 1; + optional int32 qux = 2; +} diff --git a/src/checkstyle/checkstyle-suppressions.xml b/src/checkstyle/checkstyle-suppressions.xml index d51d566bde..e769990b97 100644 --- a/src/checkstyle/checkstyle-suppressions.xml +++ b/src/checkstyle/checkstyle-suppressions.xml @@ -13,4 +13,5 @@ + diff --git a/src/reference/asciidoc/transformer.adoc b/src/reference/asciidoc/transformer.adoc index cdee7739f8..dff9c18175 100644 --- a/src/reference/asciidoc/transformer.adoc +++ b/src/reference/asciidoc/transformer.adoc @@ -249,8 +249,8 @@ Spring Integration provides namespace support for Map-to-Object, as the followin ==== [source,xml] ---- - ---- ==== @@ -258,7 +258,7 @@ Spring Integration provides namespace support for Map-to-Object, as the followin Alternatively, you could use a `ref` attribute and a prototype-scoped bean, as the following example shows: [source,xml] ---- - @@ -267,7 +267,7 @@ Alternatively, you could use a `ref` attribute and a prototype-scoped bean, as t NOTE: The 'ref' and 'type' attributes are mutually exclusive. Also, if you use the 'ref' attribute, you must point to a 'prototype' scoped bean. -Otherwise, a `BeanCreationException` is thrown. +Otherwise, a `BeanCreationException` is thrown. Starting with version 5.0, you can supply the `ObjectToMapTransformer` with a customized `JsonObjectMapper` -- for when you need special formats for dates or nulls for empty collections (and other uses). See <> for more information about `JsonObjectMapper` implementations. @@ -446,6 +446,64 @@ If the expression returns `null`, the `defaultType` is used. The `SimpleToAvroTransformer` also has a `setTypeExpression` method. This allows decoupling of the producer and consumer where the sender can set the header to some token representing the type and the consumer then maps that token to a type. +[[Protobuf-transformers]] +===== Protocol Buffers Transformers + +Version 6.1 adds support for transforming from and to https://protobuf.dev/[Protocol Buffers] data content. + +The `ToProtobufTransformer` transforms a `com.google.protobuf.Message` message payloads into native byte array or json text payloads. +The `application/x-protobuf` content type (used by default) produces byte array output payload. +If the content type is `application/json` add the `com.google.protobuf:protobuf-java-util` if found on the classpath, then the output is text json payload. +If the content type header is not set the `ToProtobufTransformer` defaults to `application/x-protobuf`. + +The `FromProtobufTransformer` transforms byte array or text protobuf payload (depending on the content type) back into `com.google.protobuf.Message` instances. +The `FromProtobufTransformer` should specify either an expected class type explicitly (use the `setExpectedType` method) or use a SpEL expression to determine the type to deserialize using the `setExpectedTypeExpression` method. +The default SpEL expression is `headers[proto_type]` (`ProtoHeaders.TYPE`) which is populated by the `ToProtobufTransformer` with the fully qualified class name of the source `com.google.protobuf.Message` class. + +For example, compiling the following IDL: + +==== +[source,proto] +---- +syntax = "proto2"; +package tutorial; + +option java_multiple_files = true; +option java_package = "org.example"; +option java_outer_classname = "MyProtos"; + +message MyMessageClass { + optional string foo = 1; + optional string bar = 2; +} +---- +==== + +will generate a new `org.example.MyMessageClass` class. + +Then use the: +==== +[source,java] +---- +// Transforms a MyMessageClass instance into a byte array. +ToProtobufTransformer toTransformer = new ToProtobufTransformer(); + +MyMessageClass test = MyMessageClass.newBuilder() + .setFoo("foo") + .setBar("bar") + .build(); +// message1 payload is byte array protocol buffer wire format. +Message message1 = toTransformer.transform(new GenericMessage<>(test)); + +// Transforms a byte array payload into a MyMessageClass instance. +FromProtobufTransformer fromTransformer = new FromProtobufTransformer(); + +// message2 payload == test +Message message2 = fromTransformer.transform(message1); + +---- +==== + [[transformer-annotation]] ==== Configuring a Transformer with Annotations diff --git a/src/reference/asciidoc/whats-new.adoc b/src/reference/asciidoc/whats-new.adoc index 9caae84fe3..6f952ebabf 100644 --- a/src/reference/asciidoc/whats-new.adoc +++ b/src/reference/asciidoc/whats-new.adoc @@ -27,6 +27,10 @@ See <<./zip.adoc#zip,Zip Support>> for more information. [[x6.1-general]] === General Changes + - Added support for transforming to/from Protocol Buffers. + See <<./transformer.adoc#Protobuf-transformers, Protocol Buffers Transformers>> for more information. + + [[x6.1-web-sockets]] === Web Sockets Changes