diff --git a/spring-integration-core/src/main/java/org/springframework/integration/transformer/DecodingTransformer.java b/spring-integration-core/src/main/java/org/springframework/integration/transformer/DecodingTransformer.java new file mode 100644 index 0000000000..583912e5a8 --- /dev/null +++ b/spring-integration-core/src/main/java/org/springframework/integration/transformer/DecodingTransformer.java @@ -0,0 +1,93 @@ +/* + * Copyright 2015 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 + * + * http://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.expression.Expression; +import org.springframework.expression.spel.support.StandardEvaluationContext; +import org.springframework.integration.codec.Codec; +import org.springframework.integration.context.IntegrationContextUtils; +import org.springframework.messaging.Message; +import org.springframework.util.Assert; + +/** + * {@link AbstractPayloadTransformer} that delegates to a codec to decode the + * payload from a byte[]. + * + * @author Gary Russell + * @since 4.2 + * + */ +public class DecodingTransformer extends AbstractTransformer { + + private final Codec codec; + + private final Class type; + + private final Expression typeExpression; + + private volatile StandardEvaluationContext evaluationContext; + + /** + * Construct an instance to use the supplied codec to decode to the supplied type. + * @param codec the codec. + * @param type the type. + */ + public DecodingTransformer(Codec codec, Class type) { + Assert.notNull(codec, "'codec' cannot be null"); + Assert.notNull(type, "'type' cannot be null"); + this.codec = codec; + this.type = type; + this.typeExpression = null; + } + + /** + * Construct an instance to use the supplied codec to decode to the supplied type. + * @param codec the codec. + * @param typeExpression an expression that evaluates to a {@link Class}. + */ + public DecodingTransformer(Codec codec, Expression typeExpression) { + Assert.notNull(codec, "'codec' cannot be null"); + Assert.notNull(typeExpression, "'typeExpression' cannot be null"); + this.codec = codec; + this.type = null; + this.typeExpression = typeExpression; + } + + public void setEvaluationContext(StandardEvaluationContext evaluationContext) { + this.evaluationContext = evaluationContext; + } + + @Override + protected void onInit() throws Exception { + if (this.evaluationContext == null) { + this.evaluationContext = IntegrationContextUtils.getEvaluationContext(getBeanFactory()); + } + } + + @Override + protected T doTransform(Message message) throws Exception { + Assert.isTrue(message.getPayload() instanceof byte[], "Message payload must be byte[]"); + byte[] bytes = (byte[]) message.getPayload(); + return codec.decode(bytes, this.type != null ? this.type : type(message)); + } + + @SuppressWarnings("unchecked") + private Class type(Message message) { + Assert.state(this.evaluationContext != null, "EvaluationContext required"); + return this.typeExpression.getValue(this.evaluationContext, message, Class.class); + } + +} diff --git a/spring-integration-core/src/main/java/org/springframework/integration/transformer/EncodingPayloadTransformer.java b/spring-integration-core/src/main/java/org/springframework/integration/transformer/EncodingPayloadTransformer.java new file mode 100644 index 0000000000..44430f1499 --- /dev/null +++ b/spring-integration-core/src/main/java/org/springframework/integration/transformer/EncodingPayloadTransformer.java @@ -0,0 +1,43 @@ +/* + * Copyright 2015 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 + * + * http://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.codec.Codec; +import org.springframework.util.Assert; + +/** + * {@link AbstractPayloadTransformer} that delegates to a codec to encode the + * payload into a byte[]. + * + * @author Gary Russell + * @since 4.2 + * + */ +public class EncodingPayloadTransformer extends AbstractPayloadTransformer { + + private final Codec codec; + + public EncodingPayloadTransformer(Codec codec) { + Assert.notNull(codec, "'codec' cannot be null"); + this.codec = codec; + } + + @Override + protected byte[] transformPayload(T payload) throws Exception { + return codec.encode(payload); + } + +} diff --git a/spring-integration-core/src/test/java/org/springframework/integration/transformer/CodecTransformerTests.java b/spring-integration-core/src/test/java/org/springframework/integration/transformer/CodecTransformerTests.java new file mode 100644 index 0000000000..6671be583e --- /dev/null +++ b/spring-integration-core/src/test/java/org/springframework/integration/transformer/CodecTransformerTests.java @@ -0,0 +1,86 @@ +/* + * Copyright 2015 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 + * + * http://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 static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Collections; + +import org.junit.Test; + +import org.springframework.expression.spel.standard.SpelExpressionParser; +import org.springframework.expression.spel.support.StandardEvaluationContext; +import org.springframework.integration.codec.Codec; +import org.springframework.messaging.Message; +import org.springframework.messaging.support.GenericMessage; + +/** + * @author Gary Russell + * @since 4.2 + * + */ +public class CodecTransformerTests { + + @Test + public void testCodec() throws Exception { + MyCodec codec = new MyCodec(); + EncodingPayloadTransformer enc = new EncodingPayloadTransformer(codec); + Message message = new GenericMessage("bar"); + byte[] transformed = enc.doTransform(message); + assertArrayEquals("foo".getBytes(), transformed); + DecodingTransformer dec = new DecodingTransformer(codec, String.class); + assertEquals("foo", dec.doTransform(new GenericMessage(transformed))); + + dec = new DecodingTransformer(codec, new SpelExpressionParser().parseExpression("T(Integer)")); + dec.setEvaluationContext(new StandardEvaluationContext()); + assertEquals(42, dec.doTransform(new GenericMessage(transformed))); + + dec = new DecodingTransformer(codec, new SpelExpressionParser().parseExpression("headers['type']")); + dec.setEvaluationContext(new StandardEvaluationContext()); + assertEquals(42, dec.doTransform(new GenericMessage(transformed, + Collections.singletonMap("type", Integer.class)))); + } + + public static class MyCodec implements Codec { + + @Override + public void encode(Object object, OutputStream outputStream) throws IOException { + } + + @Override + public byte[] encode(Object object) throws IOException { + return "foo".getBytes(); + } + + @Override + public T decode(InputStream inputStream, Class type) throws IOException { + return null; + } + + @SuppressWarnings("unchecked") + @Override + public T decode(byte[] bytes, Class type) throws IOException { + return (T) (type.equals(String.class) ? new String(bytes) : + type.equals(Integer.class) ? Integer.valueOf(42) : Integer.valueOf(43)); + } + + } + +}