From 1177f5c0a30b94b42b3aed38eb9d2dcf380c0119 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Fri, 22 May 2015 17:23:57 +0200 Subject: [PATCH] ByteBufferConverter explicitly declares applicability to byte[] Includes an optimization for simple ByteBuffer duplication. Issue: SPR-13056 (cherry picked from commit 792b7b9) --- .../convert/support/ByteBufferConverter.java | 50 ++++++++++--------- .../support/ByteBufferConverterTests.java | 31 ++++++++---- 2 files changed, 48 insertions(+), 33 deletions(-) diff --git a/spring-core/src/main/java/org/springframework/core/convert/support/ByteBufferConverter.java b/spring-core/src/main/java/org/springframework/core/convert/support/ByteBufferConverter.java index 75f1997702..c3f773f6a5 100644 --- a/spring-core/src/main/java/org/springframework/core/convert/support/ByteBufferConverter.java +++ b/spring-core/src/main/java/org/springframework/core/convert/support/ByteBufferConverter.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-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. @@ -26,10 +26,11 @@ import org.springframework.core.convert.TypeDescriptor; import org.springframework.core.convert.converter.ConditionalGenericConverter; /** - * Converts a {@link ByteBuffer} directly to and from {@code byte[]}s and indirectly to - * any type that the {@link ConversionService} support via {@code byte[]}. + * Converts a {@link ByteBuffer} directly to and from {@code byte[]}s and indirectly + * to any type that the {@link ConversionService} support via {@code byte[]}. * * @author Phillip Webb + * @author Juergen Hoeller * @since 4.0 */ final class ByteBufferConverter implements ConditionalGenericConverter { @@ -39,15 +40,18 @@ final class ByteBufferConverter implements ConditionalGenericConverter { private static final TypeDescriptor BYTE_ARRAY_TYPE = TypeDescriptor.valueOf(byte[].class); private static final Set CONVERTIBLE_PAIRS; + static { - Set convertiblePairs = new HashSet(); + Set convertiblePairs = new HashSet(4); + convertiblePairs.add(new ConvertiblePair(ByteBuffer.class, byte[].class)); + convertiblePairs.add(new ConvertiblePair(byte[].class, ByteBuffer.class)); convertiblePairs.add(new ConvertiblePair(ByteBuffer.class, Object.class)); convertiblePairs.add(new ConvertiblePair(Object.class, ByteBuffer.class)); CONVERTIBLE_PAIRS = Collections.unmodifiableSet(convertiblePairs); } - private ConversionService conversionService; + private final ConversionService conversionService; public ByteBufferConverter(ConversionService conversionService) { @@ -62,32 +66,31 @@ final class ByteBufferConverter implements ConditionalGenericConverter { @Override public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) { + boolean byteBufferTarget = targetType.isAssignableTo(BYTE_BUFFER_TYPE); if (sourceType.isAssignableTo(BYTE_BUFFER_TYPE)) { - return matchesFromByteBuffer(targetType); + return (byteBufferTarget || matchesFromByteBuffer(targetType)); } - if (targetType.isAssignableTo(BYTE_BUFFER_TYPE)) { - return matchesToByteBuffer(sourceType); - } - return false; + return (byteBufferTarget && matchesToByteBuffer(sourceType)); } private boolean matchesFromByteBuffer(TypeDescriptor targetType) { - return (targetType.isAssignableTo(BYTE_ARRAY_TYPE) || this.conversionService.canConvert( - BYTE_ARRAY_TYPE, targetType)); + return (targetType.isAssignableTo(BYTE_ARRAY_TYPE) || + this.conversionService.canConvert(BYTE_ARRAY_TYPE, targetType)); } private boolean matchesToByteBuffer(TypeDescriptor sourceType) { - return (sourceType.isAssignableTo(BYTE_ARRAY_TYPE) || this.conversionService.canConvert( - sourceType, BYTE_ARRAY_TYPE)); + return (sourceType.isAssignableTo(BYTE_ARRAY_TYPE) || + this.conversionService.canConvert(sourceType, BYTE_ARRAY_TYPE)); } @Override - public Object convert(Object source, TypeDescriptor sourceType, - TypeDescriptor targetType) { - if (sourceType.isAssignableTo(BYTE_BUFFER_TYPE)) { - return convertFromByteBuffer((ByteBuffer) source, targetType); + public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { + boolean byteBufferTarget = targetType.isAssignableTo(BYTE_BUFFER_TYPE); + if (source instanceof ByteBuffer) { + ByteBuffer buffer = (ByteBuffer) source; + return (byteBufferTarget ? buffer.duplicate() : convertFromByteBuffer(buffer, targetType)); } - if (targetType.isAssignableTo(BYTE_BUFFER_TYPE)) { + if (byteBufferTarget) { return convertToByteBuffer(source, sourceType); } // Should not happen @@ -97,6 +100,7 @@ final class ByteBufferConverter implements ConditionalGenericConverter { private Object convertFromByteBuffer(ByteBuffer source, TypeDescriptor targetType) { byte[] bytes = new byte[source.remaining()]; source.get(bytes); + if (targetType.isAssignableTo(BYTE_ARRAY_TYPE)) { return bytes; } @@ -104,12 +108,12 @@ final class ByteBufferConverter implements ConditionalGenericConverter { } private Object convertToByteBuffer(Object source, TypeDescriptor sourceType) { - byte[] bytes = (byte[]) (source instanceof byte[] ? source - : this.conversionService.convert(source, sourceType, BYTE_ARRAY_TYPE)); + byte[] bytes = (byte[]) (source instanceof byte[] ? source : + this.conversionService.convert(source, sourceType, BYTE_ARRAY_TYPE)); + ByteBuffer byteBuffer = ByteBuffer.allocate(bytes.length); byteBuffer.put(bytes); - byteBuffer.rewind(); - return byteBuffer; + return byteBuffer.rewind(); } } diff --git a/spring-core/src/test/java/org/springframework/core/convert/support/ByteBufferConverterTests.java b/spring-core/src/test/java/org/springframework/core/convert/support/ByteBufferConverterTests.java index e3ecf541ad..d23a2ad680 100644 --- a/spring-core/src/test/java/org/springframework/core/convert/support/ByteBufferConverterTests.java +++ b/spring-core/src/test/java/org/springframework/core/convert/support/ByteBufferConverterTests.java @@ -30,6 +30,7 @@ import static org.junit.Assert.*; * Tests for {@link ByteBufferConverter}. * * @author Phillip Webb + * @author Juergen Hoeller */ public class ByteBufferConverterTests { @@ -38,8 +39,7 @@ public class ByteBufferConverterTests { @Before public void setup() { - this.conversionService = new GenericConversionService(); - this.conversionService.addConverter(new ByteBufferConverter(conversionService)); + this.conversionService = new DefaultConversionService(); this.conversionService.addConverter(new ByteArrayToOtherTypeConverter()); this.conversionService.addConverter(new OtherTypeToByteArrayConverter()); } @@ -49,8 +49,8 @@ public class ByteBufferConverterTests { public void byteArrayToByteBuffer() throws Exception { byte[] bytes = new byte[] { 1, 2, 3 }; ByteBuffer convert = this.conversionService.convert(bytes, ByteBuffer.class); - assertThat(bytes, not(sameInstance(convert.array()))); - assertThat(bytes, equalTo(convert.array())); + assertThat(convert.array(), not(sameInstance(bytes))); + assertThat(convert.array(), equalTo(bytes)); } @Test @@ -58,8 +58,8 @@ public class ByteBufferConverterTests { byte[] bytes = new byte[] { 1, 2, 3 }; ByteBuffer byteBuffer = ByteBuffer.wrap(bytes); byte[] convert = this.conversionService.convert(byteBuffer, byte[].class); - assertThat(bytes, not(sameInstance(convert))); - assertThat(bytes, equalTo(convert)); + assertThat(convert, not(sameInstance(bytes))); + assertThat(convert, equalTo(bytes)); } @Test @@ -67,8 +67,8 @@ public class ByteBufferConverterTests { byte[] bytes = new byte[] { 1, 2, 3 }; ByteBuffer byteBuffer = ByteBuffer.wrap(bytes); OtherType convert = this.conversionService.convert(byteBuffer, OtherType.class); - assertThat(bytes, not(sameInstance(convert.bytes))); - assertThat(bytes, equalTo(convert.bytes)); + assertThat(convert.bytes, not(sameInstance(bytes))); + assertThat(convert.bytes, equalTo(bytes)); } @Test @@ -76,8 +76,19 @@ public class ByteBufferConverterTests { byte[] bytes = new byte[] { 1, 2, 3 }; OtherType otherType = new OtherType(bytes); ByteBuffer convert = this.conversionService.convert(otherType, ByteBuffer.class); - assertThat(bytes, not(sameInstance(convert.array()))); - assertThat(bytes, equalTo(convert.array())); + assertThat(convert.array(), not(sameInstance(bytes))); + assertThat(convert.array(), equalTo(bytes)); + } + + @Test + public void byteBufferToByteBuffer() throws Exception { + byte[] bytes = new byte[] { 1, 2, 3 }; + ByteBuffer byteBuffer = ByteBuffer.wrap(bytes); + ByteBuffer convert = this.conversionService.convert(byteBuffer, ByteBuffer.class); + assertThat(convert, not(sameInstance(byteBuffer.rewind()))); + assertThat(convert, equalTo(byteBuffer.rewind())); + assertThat(convert, equalTo(ByteBuffer.wrap(bytes))); + assertThat(convert.array(), equalTo(bytes)); }