PROTON-2236 Report more meaningful unexpected encoding errors
When the decoder reads a type encoding that does not match the
encoding code of the primitive type expected then report a more
menaingful error including the type expected and the type / code
that was read, or unknown / code if type code read is not valid.
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/codec/DecoderImpl.java b/proton-j/src/main/java/org/apache/qpid/proton/codec/DecoderImpl.java
index a85b0ff..a34bd6f 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/codec/DecoderImpl.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/codec/DecoderImpl.java
@@ -189,7 +189,7 @@
case EncodingCodes.NULL:
return defaultVal;
default:
- throw new DecodeException("Expected boolean type but found encoding: " + encodingCode);
+ throw new ProtonException("Expected Boolean type but found encoding: " + EncodingCodes.toString(encodingCode));
}
}
@@ -209,7 +209,7 @@
case EncodingCodes.NULL:
return defaultVal;
default:
- throw new DecodeException("Expected boolean type but found encoding: " + encodingCode);
+ throw new ProtonException("Expected Boolean type but found encoding: " + EncodingCodes.toString(encodingCode));
}
}
@@ -230,7 +230,7 @@
case EncodingCodes.NULL:
return defaultVal;
default:
- throw new DecodeException("Expected byte type but found encoding: " + encodingCode);
+ throw new ProtonException("Expected Byte type but found encoding: " + EncodingCodes.toString(encodingCode));
}
}
@@ -274,7 +274,7 @@
case EncodingCodes.NULL:
return defaultVal;
default:
- throw new DecodeException("Expected Short type but found encoding: " + encodingCode);
+ throw new ProtonException("Expected Short type but found encoding: " + EncodingCodes.toString(encodingCode));
}
}
@@ -320,7 +320,7 @@
case EncodingCodes.NULL:
return defaultVal;
default:
- throw new DecodeException("Expected Integer type but found encoding: " + encodingCode);
+ throw new ProtonException("Expected Integer type but found encoding: " + EncodingCodes.toString(encodingCode));
}
}
@@ -366,7 +366,7 @@
case EncodingCodes.NULL:
return defaultVal;
default:
- throw new DecodeException("Expected Long type but found encoding: " + encodingCode);
+ throw new ProtonException("Expected Long type but found encoding: " + EncodingCodes.toString(encodingCode));
}
}
@@ -410,7 +410,7 @@
case EncodingCodes.NULL:
return defaultVal;
default:
- throw new DecodeException("Expected unsigned byte type but found encoding: " + encodingCode);
+ throw new ProtonException("Expected UnsignedByte type but found encoding: " + EncodingCodes.toString(encodingCode));
}
}
@@ -432,7 +432,7 @@
case EncodingCodes.NULL:
return defaultVal;
default:
- throw new DecodeException("Expected UnsignedShort type but found encoding: " + encodingCode);
+ throw new ProtonException("Expected UnsignedShort type but found encoding: " + EncodingCodes.toString(encodingCode));
}
}
@@ -458,7 +458,7 @@
case EncodingCodes.NULL:
return defaultVal;
default:
- throw new DecodeException("Expected UnsignedInteger type but found encoding: " + encodingCode);
+ throw new ProtonException("Expected UnsignedInteger type but found encoding: " + EncodingCodes.toString(encodingCode));
}
}
@@ -484,7 +484,7 @@
case EncodingCodes.NULL:
return defaultVal;
default:
- throw new DecodeException("Expected UnsignedLong type but found encoding: " + encodingCode);
+ throw new ProtonException("Expected UnsignedLong type but found encoding: " + EncodingCodes.toString(encodingCode));
}
}
@@ -506,7 +506,7 @@
case EncodingCodes.NULL:
return defaultVal;
default:
- throw new DecodeException("Expected Character type but found encoding: " + encodingCode);
+ throw new ProtonException("Expected Character type but found encoding: " + EncodingCodes.toString(encodingCode));
}
}
@@ -522,7 +522,7 @@
case EncodingCodes.NULL:
return defaultVal;
default:
- throw new DecodeException("Expected Character type but found encoding: " + encodingCode);
+ throw new ProtonException("Expected Character type but found encoding: " + EncodingCodes.toString(encodingCode));
}
}
@@ -544,7 +544,7 @@
case EncodingCodes.NULL:
return defaultVal;
default:
- throw new ProtonException("Expected Float type but found encoding: " + encodingCode);
+ throw new ProtonException("Expected Float type but found encoding: " + EncodingCodes.toString(encodingCode));
}
}
@@ -588,7 +588,7 @@
case EncodingCodes.NULL:
return defaultVal;
default:
- throw new ProtonException("Expected Double type but found encoding: " + encodingCode);
+ throw new ProtonException("Expected Double type but found encoding: " + EncodingCodes.toString(encodingCode));
}
}
@@ -632,7 +632,7 @@
case EncodingCodes.NULL:
return defaultVal;
default:
- throw new ProtonException("Expected UUID type but found encoding: " + encodingCode);
+ throw new ProtonException("Expected UUID type but found encoding: " + EncodingCodes.toString(encodingCode));
}
}
@@ -654,7 +654,7 @@
case EncodingCodes.NULL:
return defaultValue;
default:
- throw new ProtonException("Expected Decimal32 type but found encoding: " + encodingCode);
+ throw new ProtonException("Expected Decimal32 type but found encoding: " + EncodingCodes.toString(encodingCode));
}
}
@@ -676,7 +676,7 @@
case EncodingCodes.NULL:
return defaultValue;
default:
- throw new ProtonException("Expected Decimal64 type but found encoding: " + encodingCode);
+ throw new ProtonException("Expected Decimal64 type but found encoding: " + EncodingCodes.toString(encodingCode));
}
}
@@ -698,7 +698,7 @@
case EncodingCodes.NULL:
return defaultValue;
default:
- throw new ProtonException("Expected Decimal128 type but found encoding: " + encodingCode);
+ throw new ProtonException("Expected Decimal128 type but found encoding: " + EncodingCodes.toString(encodingCode));
}
}
@@ -720,7 +720,7 @@
case EncodingCodes.NULL:
return defaultValue;
default:
- throw new ProtonException("Expected Timestamp type but found encoding: " + encodingCode);
+ throw new ProtonException("Expected Timestamp type but found encoding: " + EncodingCodes.toString(encodingCode));
}
}
@@ -744,7 +744,7 @@
case EncodingCodes.NULL:
return defaultValue;
default:
- throw new ProtonException("Expected Binary type but found encoding: " + encodingCode);
+ throw new ProtonException("Expected Binary type but found encoding: " + EncodingCodes.toString(encodingCode));
}
}
@@ -768,7 +768,7 @@
case EncodingCodes.NULL:
return defaultValue;
default:
- throw new ProtonException("Expected Symbol type but found encoding: " + encodingCode);
+ throw new ProtonException("Expected Symbol type but found encoding: " + EncodingCodes.toString(encodingCode));
}
}
@@ -792,7 +792,7 @@
case EncodingCodes.NULL:
return defaultValue;
default:
- throw new ProtonException("Expected String type but found encoding: " + encodingCode);
+ throw new ProtonException("Expected String type but found encoding: " + EncodingCodes.toString(encodingCode));
}
}
@@ -813,7 +813,7 @@
case EncodingCodes.NULL:
return null;
default:
- throw new ProtonException("Expected List type but found encoding: " + encodingCode);
+ throw new ProtonException("Expected List type but found encoding: " + EncodingCodes.toString(encodingCode));
}
}
@@ -838,7 +838,7 @@
case EncodingCodes.NULL:
return null;
default:
- throw new ProtonException("Expected Map type but found encoding: " + encodingCode);
+ throw new ProtonException("Expected Map type but found encoding: " + EncodingCodes.toString(encodingCode));
}
}
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/codec/EncodingCodes.java b/proton-j/src/main/java/org/apache/qpid/proton/codec/EncodingCodes.java
index ec55a90..bd08ab9 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/codec/EncodingCodes.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/codec/EncodingCodes.java
@@ -87,4 +87,90 @@
public static final byte ARRAY8 = (byte) 0xe0;
public static final byte ARRAY32 = (byte) 0xf0;
+ static String toString(byte encoding) {
+ switch (encoding) {
+ case DESCRIBED_TYPE_INDICATOR:
+ return "DESCRIBED_TYPE_INDICATOR:0x00";
+ case NULL:
+ return "NULL:0x40";
+ case BOOLEAN:
+ return "BOOLEAN:0x56";
+ case BOOLEAN_TRUE:
+ return "BOOLEAN_TRUE:0x41";
+ case BOOLEAN_FALSE:
+ return "BOOLEAN_FALSE:0x42";
+ case UBYTE:
+ return "UBYTE:0x50";
+ case USHORT:
+ return "USHORT:0x60";
+ case UINT:
+ return "UINT:0x70";
+ case SMALLUINT:
+ return "SMALLUINT:0x52";
+ case UINT0:
+ return "UINT0:0x43";
+ case ULONG:
+ return "ULONG:0x80";
+ case SMALLULONG:
+ return "SMALLULONG:0x53";
+ case ULONG0:
+ return "ULONG0:0x44";
+ case BYTE:
+ return "BYTE:0x51";
+ case SHORT:
+ return "SHORT:0x61";
+ case INT:
+ return "INT:0x71";
+ case SMALLINT:
+ return "SMALLINT:0x54";
+ case LONG:
+ return "LONG:0x81";
+ case SMALLLONG:
+ return "SMALLLONG:0x55";
+ case FLOAT:
+ return "FLOAT:0x72";
+ case DOUBLE:
+ return "DOUBLE:0x82";
+ case DECIMAL32:
+ return "DECIMAL32:0x74";
+ case DECIMAL64:
+ return "DECIMAL64:0x84";
+ case DECIMAL128:
+ return "DECIMAL128:0x94";
+ case CHAR:
+ return "CHAR:0x73";
+ case TIMESTAMP:
+ return "TIMESTAMP:0x83";
+ case UUID:
+ return "UUID:0x98";
+ case VBIN8:
+ return "VBIN8:0xa0";
+ case VBIN32:
+ return "VBIN32:0xb0";
+ case STR8:
+ return "STR8:0xa1";
+ case STR32:
+ return "STR32:0xb1";
+ case SYM8:
+ return "SYM8:0xa3";
+ case SYM32:
+ return "SYM32:0xb3";
+ case LIST0:
+ return "LIST0:0x45";
+ case LIST8:
+ return "LIST8:0xc0";
+ case LIST32:
+ return "LIST32:0xd0";
+ case MAP8:
+ return "MAP8:0xc1";
+ case MAP32:
+ return "MAP32:0xd1";
+ case ARRAY8:
+ return "ARRAY32:0xe0";
+ case ARRAY32:
+ return "ARRAY32:0xf0";
+ default:
+ return "Unknown-Type:" + String.format("0x%02X ", encoding);
+ }
+ }
}
diff --git a/proton-j/src/test/java/org/apache/qpid/proton/codec/StringTypeTest.java b/proton-j/src/test/java/org/apache/qpid/proton/codec/StringTypeTest.java
index 3efe81d..5f9415e 100644
--- a/proton-j/src/test/java/org/apache/qpid/proton/codec/StringTypeTest.java
+++ b/proton-j/src/test/java/org/apache/qpid/proton/codec/StringTypeTest.java
@@ -33,7 +33,9 @@
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
+import java.util.UUID;
+import org.apache.qpid.proton.ProtonException;
import org.apache.qpid.proton.amqp.messaging.AmqpValue;
import org.junit.Test;
import org.mockito.Mockito;
@@ -209,6 +211,74 @@
assertEquals("", result);
}
+ @Test
+ public void testDecodeNonStringWhenStringExpectedReportsUsefulError() {
+ final DecoderImpl decoder = new DecoderImpl();
+ final EncoderImpl encoder = new EncoderImpl(decoder);
+
+ AMQPDefinedTypes.registerAllTypes(decoder, encoder);
+
+ final ByteBuffer buffer = ByteBuffer.allocate(64);
+ final UUID encoded = UUID.randomUUID();
+
+ buffer.put(EncodingCodes.UUID);
+ buffer.putLong(encoded.getMostSignificantBits());
+ buffer.putLong(encoded.getLeastSignificantBits());
+ buffer.flip();
+
+ byte[] copy = new byte[buffer.remaining()];
+ buffer.get(copy);
+
+ CompositeReadableBuffer composite = new CompositeReadableBuffer();
+ composite.append(copy);
+
+ decoder.setBuffer(composite);
+
+ TypeConstructor<?> stringType = decoder.peekConstructor();
+ assertEquals(UUID.class, stringType.getTypeClass());
+
+ composite.mark();
+
+ try {
+ decoder.readString();
+ } catch (ProtonException ex) {
+ // Should indicate the type that it found in the error
+ assertTrue(ex.getMessage().contains(EncodingCodes.toString(EncodingCodes.UUID)));
+ }
+
+ composite.reset();
+ UUID actual = decoder.readUUID();
+ assertEquals(encoded, actual);
+ }
+
+ @Test
+ public void testDecodeUnknownTypeWhenStringExpectedReportsUsefulError() {
+ final DecoderImpl decoder = new DecoderImpl();
+ final EncoderImpl encoder = new EncoderImpl(decoder);
+
+ AMQPDefinedTypes.registerAllTypes(decoder, encoder);
+
+ final ByteBuffer buffer = ByteBuffer.allocate(64);
+
+ buffer.put((byte) 0x01);
+ buffer.flip();
+
+ byte[] copy = new byte[buffer.remaining()];
+ buffer.get(copy);
+
+ CompositeReadableBuffer composite = new CompositeReadableBuffer();
+ composite.append(copy);
+
+ decoder.setBuffer(composite);
+
+ try {
+ decoder.readString();
+ } catch (ProtonException ex) {
+ // Should indicate the type that it found in the error
+ assertTrue(ex.getMessage().contains("Unknown-Type:0x01"));
+ }
+ }
+
// build up some test data with a set of suitable Unicode characters
private static List<String> generateTestData()
{