diff --git a/README.md b/README.md index 4cc7ee4f6..d0eb8234b 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,8 @@ MessagePack for Java * Message Pack specification: -MessagePack v7 (0.7.x) is a faster implementation of the previous version [v06](https://github.com/msgpack/msgpack-java/tree/v06), and supports all of the message pack types, including [extended format](https://github.com/msgpack/msgpack/blob/master/spec.md#formats-ext). +MessagePack v7 (0.7.x) is a faster implementation of the previous version [v06](https://github.com/msgpack/msgpack-java/tree/v06), and +supports all of the message pack types, including [extension format](https://github.com/msgpack/msgpack/blob/master/spec.md#formats-ext). ## Limitation - Value API is in a designing phase: https://github.com/msgpack/msgpack-java/pull/109 @@ -26,7 +27,7 @@ For sbt users: libraryDependencies += "org.msgpack" % "msgpack-core" % "0.7.0-p9" ``` -- [Usage examples](msgpack-core/src/main/java/org/msgpack/core/example/MessagePackExample.java) +- [Usage examples](msgpack-core/src/test/java/org/msgpack/core/example/MessagePackExample.java) msgpack-java supports serialization and deserialization of Java objects through [jackson-databind](https://github.com/FasterXML/jackson-databind). For details, see [msgpack-jackson/README.md](msgpack-jackson/README.md). The template-based serialization mechanism used in v06 is deprecated. diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index b0f19d52a..f7e44f3d7 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -4,7 +4,7 @@ * Fix [#217] when reading from SockectInputStream * 2015-04-09 0.7.0-p8 - * Support Extended type (defined in MessagePack) in msgpack-jackson + * Support Extension type (defined in MessagePack) in msgpack-jackson * Support BigDecimal type (defined in Jackson) in msgpack-jackson * Fix MessageUnpacker#unpackString [#215](https://github.com/msgpack/msgpack-java/pull/215), [#216](https://github.com/msgpack/msgpack-java/pull/216) diff --git a/msgpack-core/src/main/java/org/msgpack/core/ExtendedTypeHeader.java b/msgpack-core/src/main/java/org/msgpack/core/ExtendedTypeHeader.java deleted file mode 100644 index c4d4cc15e..000000000 --- a/msgpack-core/src/main/java/org/msgpack/core/ExtendedTypeHeader.java +++ /dev/null @@ -1,45 +0,0 @@ -package org.msgpack.core; - -import static org.msgpack.core.Preconditions.*; - -/** - * Header of the extended types - */ -public class ExtendedTypeHeader { - private final int length; - private final int type; - - ExtendedTypeHeader(int length, int type) { - checkArgument(length >= 0, String.format("length must be >= 0: %,d", length)); - this.length = length; - this.type = type; - } - - public int getType() { - return type; - } - - public int getLength() { - return length; - } - - @Override - public int hashCode() { - return (type + 31) * 31 + length; - } - - @Override - public boolean equals(Object obj) { - if(obj instanceof ExtendedTypeHeader) { - ExtendedTypeHeader other = (ExtendedTypeHeader) obj; - return this.type == other.type && this.length == other.length; - } - return false; - } - - @Override - public String toString() { - return String.format("ExtendedTypeHeader(type:%d, length:%,d)", type, length); - } - -} diff --git a/msgpack-core/src/main/java/org/msgpack/core/ExtensionTypeHeader.java b/msgpack-core/src/main/java/org/msgpack/core/ExtensionTypeHeader.java new file mode 100644 index 000000000..6d6812fe4 --- /dev/null +++ b/msgpack-core/src/main/java/org/msgpack/core/ExtensionTypeHeader.java @@ -0,0 +1,65 @@ +package org.msgpack.core; + +import static org.msgpack.core.Preconditions.*; + +/** + * Header of the Extension types + */ +public class ExtensionTypeHeader { + private final byte type; + private final int length; + + /** + * Create an extension type header + * Example: + *
+     * {@code
+     * import org.msgpack.core.ExtensionTypeHeader;
+     * import static org.msgpack.core.ExtensionTypeHeader.checkedCastToByte;
+     * ...
+     * ExtensionTypeHeader header = new ExtensionTypeHeader(checkedCastToByte(0x01), 32);
+     * ...
+     * }
+     * 
+ * @param type extension type (byte). You can check the valid byte range with {@link #checkedCastToByte(int)} method. + * @param length extension type data length + */ + public ExtensionTypeHeader(byte type, int length) { + checkArgument(length >= 0, "length must be >= 0"); + this.type = type; + this.length = length; + } + + public static byte checkedCastToByte(int code) { + checkArgument(Byte.MIN_VALUE <= code && code <= Byte.MAX_VALUE, "Extension type code must be within the range of byte"); + return (byte) code; + } + + public byte getType() { + return type; + } + + public int getLength() { + return length; + } + + @Override + public int hashCode() { + return (type + 31) * 31 + length; + } + + @Override + public boolean equals(Object obj) { + if(obj instanceof ExtensionTypeHeader) { + ExtensionTypeHeader other = (ExtensionTypeHeader) obj; + return this.type == other.type && this.length == other.length; + } + return false; + } + + @Override + public String toString() { + return String.format("ExtensionTypeHeader(type:%d, length:%,d)", type, length); + } + +} diff --git a/msgpack-core/src/main/java/org/msgpack/core/MessageFloatOverflowException.java b/msgpack-core/src/main/java/org/msgpack/core/MessageFloatOverflowException.java deleted file mode 100644 index 88449e6d5..000000000 --- a/msgpack-core/src/main/java/org/msgpack/core/MessageFloatOverflowException.java +++ /dev/null @@ -1,20 +0,0 @@ -package org.msgpack.core; - -/** - * This error is thrown when the user tries to read a value that has decimal component as byte, short, int and long. - * - */ -public class MessageFloatOverflowException extends MessageOverflowException { - - private final double value; - - public MessageFloatOverflowException(double value) { - super(); - this.value = value; - } - - public double getValue() { - return value; - } - -} diff --git a/msgpack-core/src/main/java/org/msgpack/core/MessageFormat.java b/msgpack-core/src/main/java/org/msgpack/core/MessageFormat.java index cffb525e2..b00681244 100644 --- a/msgpack-core/src/main/java/org/msgpack/core/MessageFormat.java +++ b/msgpack-core/src/main/java/org/msgpack/core/MessageFormat.java @@ -24,9 +24,9 @@ public enum MessageFormat { BIN8(ValueType.BINARY), BIN16(ValueType.BINARY), BIN32(ValueType.BINARY), - EXT8(ValueType.EXTENDED), - EXT16(ValueType.EXTENDED), - EXT32(ValueType.EXTENDED), + EXT8(ValueType.EXTENSION), + EXT16(ValueType.EXTENSION), + EXT32(ValueType.EXTENSION), FLOAT32(ValueType.FLOAT), FLOAT64(ValueType.FLOAT), UINT8(ValueType.INTEGER), @@ -38,11 +38,11 @@ public enum MessageFormat { INT16(ValueType.INTEGER), INT32(ValueType.INTEGER), INT64(ValueType.INTEGER), - FIXEXT1(ValueType.EXTENDED), - FIXEXT2(ValueType.EXTENDED), - FIXEXT4(ValueType.EXTENDED), - FIXEXT8(ValueType.EXTENDED), - FIXEXT16(ValueType.EXTENDED), + FIXEXT1(ValueType.EXTENSION), + FIXEXT2(ValueType.EXTENSION), + FIXEXT4(ValueType.EXTENSION), + FIXEXT8(ValueType.EXTENSION), + FIXEXT16(ValueType.EXTENSION), STR8(ValueType.STRING), STR16(ValueType.STRING), STR32(ValueType.STRING), @@ -95,7 +95,7 @@ public static MessageFormat valueOf(final byte b) { * @return */ @VisibleForTesting - public static MessageFormat toMessageFormat(final byte b) { + static MessageFormat toMessageFormat(final byte b) { if (Code.isPosFixInt(b)) { return POSFIXINT; } diff --git a/msgpack-core/src/main/java/org/msgpack/core/MessageIntegerOverflowException.java b/msgpack-core/src/main/java/org/msgpack/core/MessageIntegerOverflowException.java index c3d561ec1..28671ae22 100644 --- a/msgpack-core/src/main/java/org/msgpack/core/MessageIntegerOverflowException.java +++ b/msgpack-core/src/main/java/org/msgpack/core/MessageIntegerOverflowException.java @@ -23,8 +23,7 @@ * using a smaller types. For example, calling MessageUnpacker.unpackInt() for an integer value * that is larger than Integer.MAX_VALUE will cause this exception. */ -public class MessageIntegerOverflowException extends MessageOverflowException { - +public class MessageIntegerOverflowException extends MessageTypeException { private final BigInteger bigInteger; public MessageIntegerOverflowException(BigInteger bigInteger) { diff --git a/msgpack-core/src/main/java/org/msgpack/core/MessageOverflowException.java b/msgpack-core/src/main/java/org/msgpack/core/MessageOverflowException.java deleted file mode 100644 index 2190a34c1..000000000 --- a/msgpack-core/src/main/java/org/msgpack/core/MessageOverflowException.java +++ /dev/null @@ -1,16 +0,0 @@ -package org.msgpack.core; - -/** - * Created on 5/28/14. - */ -public class MessageOverflowException extends MessageTypeException { - - public MessageOverflowException() { - super(); - } - - public MessageOverflowException(String message) { - super(message); - } - -} diff --git a/msgpack-core/src/main/java/org/msgpack/core/MessagePacker.java b/msgpack-core/src/main/java/org/msgpack/core/MessagePacker.java index 16f49c656..e86bdc4ea 100644 --- a/msgpack-core/src/main/java/org/msgpack/core/MessagePacker.java +++ b/msgpack-core/src/main/java/org/msgpack/core/MessagePacker.java @@ -379,7 +379,7 @@ public MessagePacker packString(String s) throws IOException { flush(); prepareBuffer(); - boolean isExtended = false; + boolean isExtension = false; ByteBuffer encodeBuffer = buffer.toByteBuffer(position, buffer.size() - position); encoder.reset(); while(in.hasRemaining()) { @@ -400,7 +400,7 @@ public MessagePacker packString(String s) throws IOException { // Coy the current encodeBuffer contents to the new buffer newBuffer.put(encodeBuffer); encodeBuffer = newBuffer; - isExtended = true; + isExtension = true; encoder.reset(); continue; } @@ -434,7 +434,7 @@ public MessagePacker packString(String s) throws IOException { flush(); // We need to dump the data here to MessageBufferOutput so that we can switch back to the original buffer // Reset to the original buffer (or encodeBuffer if new buffer is allocated) - buffer = isExtended ? MessageBuffer.wrap(encodeBuffer) : tmpBuf; + buffer = isExtension ? MessageBuffer.wrap(encodeBuffer) : tmpBuf; // No need exists to write payload since the encoded string (payload) is already written to the buffer position = strLen; return this; @@ -477,41 +477,41 @@ public MessagePacker packValue(Value v) throws IOException { return this; } - public MessagePacker packExtendedTypeHeader(int extType, int payloadLen) throws IOException { + public MessagePacker packExtensionTypeHeader(byte extType, int payloadLen) throws IOException { if(payloadLen < (1 << 8)) { if(payloadLen > 0 && (payloadLen & (payloadLen - 1)) == 0) { // check whether dataLen == 2^x if(payloadLen == 1) { - writeByteAndByte(FIXEXT1, (byte) extType); + writeByteAndByte(FIXEXT1, extType); } else if(payloadLen == 2) { - writeByteAndByte(FIXEXT2, (byte) extType); + writeByteAndByte(FIXEXT2, extType); } else if(payloadLen == 4) { - writeByteAndByte(FIXEXT4, (byte) extType); + writeByteAndByte(FIXEXT4, extType); } else if(payloadLen == 8) { - writeByteAndByte(FIXEXT8, (byte) extType); + writeByteAndByte(FIXEXT8, extType); } else if(payloadLen == 16) { - writeByteAndByte(FIXEXT16, (byte) extType); + writeByteAndByte(FIXEXT16, extType); } else { writeByteAndByte(EXT8, (byte) payloadLen); - writeByte((byte) extType); + writeByte(extType); } } else { writeByteAndByte(EXT8, (byte) payloadLen); - writeByte((byte) extType); + writeByte(extType); } } else if(payloadLen < (1 << 16)) { writeByteAndShort(EXT16, (short) payloadLen); - writeByte((byte) extType); + writeByte(extType); } else { writeByteAndInt(EXT32, payloadLen); - writeByte((byte) extType); + writeByte(extType); // TODO support dataLen > 2^31 - 1 } diff --git a/msgpack-core/src/main/java/org/msgpack/core/MessageTypeCastException.java b/msgpack-core/src/main/java/org/msgpack/core/MessageTypeCastException.java new file mode 100644 index 000000000..6189cc646 --- /dev/null +++ b/msgpack-core/src/main/java/org/msgpack/core/MessageTypeCastException.java @@ -0,0 +1,34 @@ +// +// MessagePack for Java +// +// 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.msgpack.core; + +public class MessageTypeCastException extends MessageTypeException { + public MessageTypeCastException() { + super(); + } + + public MessageTypeCastException(String message) { + super(message); + } + + public MessageTypeCastException(String message, Throwable cause) { + super(message, cause); + } + + public MessageTypeCastException(Throwable cause) { + super(cause); + } +} diff --git a/msgpack-core/src/main/java/org/msgpack/core/MessageUnpacker.java b/msgpack-core/src/main/java/org/msgpack/core/MessageUnpacker.java index 628525990..4ea0949b9 100644 --- a/msgpack-core/src/main/java/org/msgpack/core/MessageUnpacker.java +++ b/msgpack-core/src/main/java/org/msgpack/core/MessageUnpacker.java @@ -15,6 +15,10 @@ // package org.msgpack.core; +import java.util.List; +import java.util.ArrayList; +import java.util.Map; +import java.util.HashMap; import java.io.Closeable; import java.io.EOFException; import java.io.IOException; @@ -30,12 +34,10 @@ import org.msgpack.core.MessagePack.Code; import org.msgpack.core.buffer.MessageBuffer; import org.msgpack.core.buffer.MessageBufferInput; -import org.msgpack.value.Cursor; -import org.msgpack.value.ValueType; -import org.msgpack.value.holder.FloatHolder; -import org.msgpack.value.holder.IntegerHolder; -import org.msgpack.value.holder.ValueHolder; -import org.msgpack.value.impl.CursorImpl; +import org.msgpack.value.Value; +import org.msgpack.value.ImmutableValue; +import org.msgpack.value.Variable; +import org.msgpack.value.ValueFactory; import static org.msgpack.core.Preconditions.*; @@ -79,6 +81,7 @@ public class MessageUnpacker implements Closeable { * Points to the current buffer to read */ private MessageBuffer buffer = EMPTY_BUFFER; + /** * Cursor position in the current buffer */ @@ -115,16 +118,6 @@ public class MessageUnpacker implements Closeable { private CharBuffer decodeBuffer; - /** - * Get a {@link org.msgpack.value.Cursor} for traversing message-packed values - * @return - */ - public Cursor getCursor() { - return new CursorImpl(this); - } - - - /** * Create an MessageUnpacker that reads data from the given MessageBufferInput * @@ -531,57 +524,143 @@ public void skipValue() throws IOException { */ private static MessageTypeException unexpected(String expected, byte b) throws MessageTypeException { - ValueType type = ValueType.valueOf(b); - return new MessageTypeException(String.format("Expected %s, but got %s (%02x)", expected, type.toTypeName(), b)); + MessageFormat format = MessageFormat.valueOf(b); + String typeName; + if (format == MessageFormat.NEVER_USED) { + typeName = "NeverUsed"; + } else { + String name = format.getValueType().name(); + typeName = name.substring(0, 1) + name.substring(1).toLowerCase(); + } + return new MessageTypeException(String.format("Expected %s, but got %s (%02x)", expected, typeName, b)); } - public MessageFormat unpackValue(ValueHolder holder) throws IOException { + public ImmutableValue unpackValue() throws IOException { MessageFormat mf = getNextFormat(); switch(mf.getValueType()) { case NIL: unpackNil(); - holder.setNil(); - break; + return ValueFactory.newNil(); case BOOLEAN: - holder.setBoolean(unpackBoolean()); - break; - case INTEGER: { - unpackInteger(holder.getIntegerHolder()); - holder.setToInteger(); - break; + return ValueFactory.newBoolean(unpackBoolean()); + case INTEGER: + switch (mf) { + case UINT64: + return ValueFactory.newInteger(unpackBigInteger()); + default: + return ValueFactory.newInteger(unpackLong()); + } + case FLOAT: + return ValueFactory.newFloat(unpackDouble()); + case STRING: { + int length = unpackRawStringHeader(); + return ValueFactory.newString(readPayload(length)); + } + case BINARY: { + int length = unpackBinaryHeader(); + return ValueFactory.newBinary(readPayload(length)); + } + case ARRAY: { + int size = unpackArrayHeader(); + Value[] array = new Value[size]; + for (int i=0; i < size; i++) { + array[i] = unpackValue(); + } + return ValueFactory.newArray(array); } - case FLOAT: { - unpackFloat(holder.getFloatHolder()); - holder.setToFloat(); - break; + case MAP: { + int size = unpackMapHeader(); + Value[] kvs = new Value[size * 2]; + for (int i=0; i < size * 2; ) { + kvs[i] = unpackValue(); + i++; + kvs[i] = unpackValue(); + i++; + } + return ValueFactory.newMap(kvs); + } + case EXTENSION: { + ExtensionTypeHeader extHeader = unpackExtensionTypeHeader(); + return ValueFactory.newExtension(extHeader.getType(), readPayload(extHeader.getLength())); + } + default: + throw new MessageFormatException("Unknown value type"); + } + } + + public Variable unpackValue(Variable var) throws IOException { + MessageFormat mf = getNextFormat(); + switch(mf.getValueType()) { + case NIL: + unpackNil(); + var.setNilValue(); + return var; + case BOOLEAN: + var.setBooleanValue(unpackBoolean()); + return var; + case INTEGER: + switch (mf) { + case UINT64: + var.setIntegerValue(unpackBigInteger()); + return var; + default: + var.setIntegerValue(unpackLong()); + return var; + } + case FLOAT: + var.setFloatValue(unpackDouble()); + return var; + case STRING: { + int length = unpackRawStringHeader(); + var.setStringValue(readPayload(length)); + return var; } - case STRING: - int strLen = unpackRawStringHeader(); - holder.setString(readPayloadAsReference(strLen)); - break; case BINARY: { - int binaryLen = unpackBinaryHeader(); - holder.setBinary(readPayloadAsReference(binaryLen)); - break; + int length = unpackBinaryHeader(); + var.setBinaryValue(readPayload(length)); + return var; } - case ARRAY: - holder.prepareArrayCursor(this); - break; - case MAP: - holder.prepareMapCursor(this); - break; - case EXTENDED: - ExtendedTypeHeader extHeader = unpackExtendedTypeHeader(); - holder.setExt(extHeader.getType(), readPayloadAsReference(extHeader.getLength())); - break; + case ARRAY: { + int size = unpackArrayHeader(); + List list = new ArrayList(size); + for (int i=0; i < size; i++) { + //Variable e = new Variable(); + //unpackValue(e); + //list.add(e); + list.add(unpackValue()); + } + var.setArrayValue(list); + return var; + } + case MAP: { + int size = unpackMapHeader(); + Map map = new HashMap(); + for (int i=0; i < size; i++) { + //Variable k = new Variable(); + //unpackValue(k); + //Variable v = new Variable(); + //unpackValue(v); + Value k = unpackValue(); + Value v = unpackValue(); + map.put(k, v); + } + var.setMapValue(map); + return var; + } + case EXTENSION: { + ExtensionTypeHeader extHeader = unpackExtensionTypeHeader(); + var.setExtensionValue(extHeader.getType(), readPayload(extHeader.getLength())); + return var; + } + default: + throw new MessageFormatException("Unknown value type"); } - return mf; } - public Object unpackNil() throws IOException { + public void unpackNil() throws IOException { byte b = consume(); if(b == Code.NIL) { - return null; + return; } throw unexpected("Nil", b); } @@ -832,73 +911,6 @@ public BigInteger unpackBigInteger() throws IOException { throw unexpected("Integer", b); } - - /** - * Unpack an integer, then store the read value to the given holder - * @param holder an integer holder to which the unpacked integer will be set. - * @throws IOException - */ - public void unpackInteger(IntegerHolder holder) throws IOException { - byte b = consume(); - - if(Code.isFixInt(b)) { - holder.setByte(b); - return; - } - - switch(b) { - case Code.INT8: // signed int 8 - holder.setByte(readByte()); - break; - case Code.INT16: - holder.setShort(readShort()); - break; - case Code.INT32: - holder.setInt(readInt()); - break; - case Code.INT64: // signed int 64 - holder.setLong(readLong()); - break; - case Code.UINT8: // unsigned int 8 - byte u8 = readByte(); - if(u8 < 0) { - holder.setShort((short) (u8 & 0xFF)); - } - else { - holder.setByte(u8); - } - break; - case Code.UINT16: // unsigned int 16 - short u16 = readShort(); - if(u16 < 0) { - holder.setInt(u16 & 0xFFFF); - } - else { - holder.setShort(u16); - } - break; - case Code.UINT32: // unsigned int 32 - int u32 = readInt(); - if(u32 < 0) { - holder.setLong((long) (u32 & 0x7fffffff) + 0x80000000L); - } else { - holder.setInt(u32); - } - break; - case Code.UINT64: // unsigned int 64 - long u64 = readLong(); - if(u64 < 0L) { - holder.setBigInteger(BigInteger.valueOf(u64 + Long.MAX_VALUE + 1L).setBit(63)); - } else { - holder.setLong(u64); - } - break; - default: - throw unexpected("Integer", b); - } - } - - public float unpackFloat() throws IOException { byte b = consume(); switch(b) { @@ -925,26 +937,6 @@ public double unpackDouble() throws IOException { throw unexpected("Float", b); } - public void unpackFloat(ValueHolder holder) throws IOException { - unpackFloat(holder.getFloatHolder()); - } - - public void unpackFloat(FloatHolder holder) throws IOException { - byte b = consume(); - switch(b) { - case Code.FLOAT32: // float - float fv = readFloat(); - holder.setFloat(fv); - break; - case Code.FLOAT64: // double - double dv = readDouble(); - holder.setDouble(dv); - break; - default: - throw unexpected("Float", b); - } - } - private final static String EMPTY_STRING = ""; @@ -1049,33 +1041,33 @@ public int unpackMapHeader() throws IOException { throw unexpected("Map", b); } - public ExtendedTypeHeader unpackExtendedTypeHeader() throws IOException { + public ExtensionTypeHeader unpackExtensionTypeHeader() throws IOException { byte b = consume(); switch(b) { case Code.FIXEXT1: - return new ExtendedTypeHeader(1, readByte()); + return new ExtensionTypeHeader(readByte(), 1); case Code.FIXEXT2: - return new ExtendedTypeHeader(2, readByte()); + return new ExtensionTypeHeader(readByte(), 2); case Code.FIXEXT4: - return new ExtendedTypeHeader(4, readByte()); + return new ExtensionTypeHeader(readByte(), 4); case Code.FIXEXT8: - return new ExtendedTypeHeader(8, readByte()); + return new ExtensionTypeHeader(readByte(), 8); case Code.FIXEXT16: - return new ExtendedTypeHeader(16, readByte()); + return new ExtensionTypeHeader(readByte(), 16); case Code.EXT8: { - int len = readNextLength8(); - int t = readByte(); - return new ExtendedTypeHeader(len, t); + int length = readNextLength8(); + byte type = readByte(); + return new ExtensionTypeHeader(type, length); } case Code.EXT16: { - int len = readNextLength16(); - int t = readByte(); - return new ExtendedTypeHeader(len, t); + int length = readNextLength16(); + byte type = readByte(); + return new ExtensionTypeHeader(type, length); } case Code.EXT32: { - int len = readNextLength32(); - int t = readByte(); - return new ExtendedTypeHeader(len, t); + int length = readNextLength32(); + byte type = readByte(); + return new ExtensionTypeHeader(type, length); } } @@ -1161,6 +1153,12 @@ public void readPayload(byte[] dst) throws IOException { readPayload(dst, 0, dst.length); } + public byte[] readPayload(int length) throws IOException { + byte[] newArray = new byte[length]; + readPayload(newArray); + return newArray; + } + /** * Read up to len bytes of data into the destination array * diff --git a/msgpack-core/src/main/java/org/msgpack/core/NonBlockingMessageUnpacker.java b/msgpack-core/src/main/java/org/msgpack/core/NonBlockingMessageUnpacker.java deleted file mode 100644 index 7ec3122be..000000000 --- a/msgpack-core/src/main/java/org/msgpack/core/NonBlockingMessageUnpacker.java +++ /dev/null @@ -1,11 +0,0 @@ -package org.msgpack.core; - -/** - * MessageUnpacker implementation that supports event-driven I/O, which - * is necessary to implement an efficient RPC server that receives MessagePack data. - */ -public class NonBlockingMessageUnpacker { - - // TODO Impl - -} diff --git a/msgpack-core/src/main/java/org/msgpack/core/NumberUtil.java b/msgpack-core/src/main/java/org/msgpack/core/NumberUtil.java deleted file mode 100644 index 578833b43..000000000 --- a/msgpack-core/src/main/java/org/msgpack/core/NumberUtil.java +++ /dev/null @@ -1,52 +0,0 @@ -package org.msgpack.core; - -import java.math.BigInteger; - -/** - * Utilities for numbers - */ -public class NumberUtil { - - private static final BigInteger BI_BYTE_MIN = BigInteger.valueOf(Byte.MIN_VALUE); - private static final BigInteger BI_BYTE_MAX = BigInteger.valueOf(Byte.MAX_VALUE); - private static final BigInteger BI_SHORT_MIN = BigInteger.valueOf(Short.MIN_VALUE); - private static final BigInteger BI_SHORT_MAX = BigInteger.valueOf(Short.MAX_VALUE); - private static final BigInteger BI_INT_MIN = BigInteger.valueOf(Integer.MIN_VALUE); - private static final BigInteger BI_INT_MAX = BigInteger.valueOf(Integer.MAX_VALUE); - private static final BigInteger BI_LONG_MIN = BigInteger.valueOf(Long.MIN_VALUE); - private static final BigInteger BI_LONG_MAX = BigInteger.valueOf(Long.MAX_VALUE); - - public static class LongUtil { - - public static boolean isValidByte(long v) { - return Byte.MIN_VALUE <= v && v <= Byte.MAX_VALUE; - } - - public static boolean isValidByte(BigInteger v) { - return v.compareTo(BI_BYTE_MIN) >= 0 && v.compareTo(BI_BYTE_MAX) <= 0; - } - - public static boolean isValidShort(long v) { - return Short.MIN_VALUE <= v && v <= Short.MAX_VALUE; - } - - public static boolean isValidShort(BigInteger v) { - return v.compareTo(BI_SHORT_MIN) >= 0 && v.compareTo(BI_SHORT_MAX) <= 0; - } - - public static boolean isValidInt(long v) { - return Integer.MIN_VALUE <= v && v <= Integer.MAX_VALUE; - } - public static boolean isValidInt(BigInteger v) { - return v.compareTo(BI_INT_MIN) >= 0 && v.compareTo(BI_INT_MAX) <= 0; - } - - public static boolean isValidLong(BigInteger v) { - return v.compareTo(BI_LONG_MIN) >= 0 && v.compareTo(BI_LONG_MAX) <= 0; - } - } - - - - -} diff --git a/msgpack-core/src/main/java/org/msgpack/value/AbstractValueVisitor.java b/msgpack-core/src/main/java/org/msgpack/value/AbstractValueVisitor.java deleted file mode 100644 index 06697d3c5..000000000 --- a/msgpack-core/src/main/java/org/msgpack/value/AbstractValueVisitor.java +++ /dev/null @@ -1,48 +0,0 @@ -package org.msgpack.value; - -/** - * Empty visitor that does nothing - */ -public class AbstractValueVisitor implements ValueVisitor { - - @Override - public void visitNil() { - - } - @Override - public void visitBoolean(boolean v) { - - } - @Override - public void visitInteger(IntegerValue v) { - - } - @Override - public void visitFloat(FloatValue v) { - - } - @Override - public void visitBinary(BinaryValue v) { - - } - @Override - public void visitString(StringValue v) { - - } - @Override - public void visitArray(ArrayValue v) { - - } - @Override - public void visitMap(MapValue v) { - - } - @Override - public void visitExtended(ExtendedValue v) { - - } - @Override - public void onError(Exception e) { - - } -} diff --git a/msgpack-core/src/main/java/org/msgpack/value/ArrayCursor.java b/msgpack-core/src/main/java/org/msgpack/value/ArrayCursor.java deleted file mode 100644 index d491ba9c8..000000000 --- a/msgpack-core/src/main/java/org/msgpack/value/ArrayCursor.java +++ /dev/null @@ -1,24 +0,0 @@ -package org.msgpack.value; - -import java.util.Iterator; - -/** - * Created on 6/16/14. - */ -public interface ArrayCursor extends ValueRef, Iterable { - public int size(); - - public boolean hasNext(); - public ValueRef next(); - public void skip(); - - /** - * Skips all of the remaining values - */ - public void skipAll(); - - public Iterator iterator(); - - public ArrayValue toValue(); - -} diff --git a/msgpack-core/src/main/java/org/msgpack/value/ArrayValue.java b/msgpack-core/src/main/java/org/msgpack/value/ArrayValue.java index 1c15df7c0..bb0d00e41 100644 --- a/msgpack-core/src/main/java/org/msgpack/value/ArrayValue.java +++ b/msgpack-core/src/main/java/org/msgpack/value/ArrayValue.java @@ -1,20 +1,57 @@ +// +// MessagePack for Java +// +// 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.msgpack.value; +import java.util.List; +import java.util.Iterator; + /** - * Value interface for array type data. + * The interface {@code ArrayValue} represents MessagePack's Array type. * - * Implementation note: We do not implement List interface here, because - * we cannot reuse AbstractList and AbstractValue implementations simultaneously since - * Java does not support mixin of classes. Instead, it provides {@link #iterator} or - * {@link #toValueArray()} methods to traverse the array contents. + * MessagePack's Array type can represent sequence of values. */ -public interface ArrayValue extends Value, ArrayCursor { +public interface ArrayValue extends Value, Iterable { + + /** + * Returns number of elements in this array. + */ + int size(); - public Value[] toValueArray(); + /** + * Returns the element at the specified position in this array. + * + * @throws IndexOutOfBoundsException + * If the index is out of range + * (index < 0 || index >= size()) + */ + Value get(int index); - public Value get(int index); - public Value apply(int index); + /** + * Returns the element at the specified position in this array. + * This method returns an ImmutableNilValue if the index is out of range. + */ + Value getOrNilValue(int index); - public ArrayValue toValue(); + /** + * Returns an iterator over elements. + */ + Iterator iterator(); + /** + * Returns the value as {@code List}. + */ + List list(); } diff --git a/msgpack-core/src/main/java/org/msgpack/value/BinaryValue.java b/msgpack-core/src/main/java/org/msgpack/value/BinaryValue.java index 808de6f9b..43ddcb966 100644 --- a/msgpack-core/src/main/java/org/msgpack/value/BinaryValue.java +++ b/msgpack-core/src/main/java/org/msgpack/value/BinaryValue.java @@ -1,8 +1,26 @@ +// +// MessagePack for Java +// +// 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.msgpack.value; /** -* Created on 5/30/14. -*/ + * The interface {@code BinaryValue} represents MessagePack's Binary type. + * + * MessagePack's Binary type can represent a byte array at most 264-1 bytes. + * + * @see org.msgpack.value.RawValue + */ public interface BinaryValue extends RawValue { - BinaryValue toValue(); } diff --git a/msgpack-core/src/main/java/org/msgpack/value/BooleanValue.java b/msgpack-core/src/main/java/org/msgpack/value/BooleanValue.java index 2d517469e..5b33d3567 100644 --- a/msgpack-core/src/main/java/org/msgpack/value/BooleanValue.java +++ b/msgpack-core/src/main/java/org/msgpack/value/BooleanValue.java @@ -1,9 +1,28 @@ +// +// MessagePack for Java +// +// 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.msgpack.value; /** -* Created on 5/30/14. -*/ + * The interface {@code BooleanValue} represents MessagePack's Boolean type. + * + * MessagePack's Boolean type can represent {@code true} or {@code false}. + */ public interface BooleanValue extends Value { - public boolean toBoolean(); - public BooleanValue toValue(); + /** + * Returns the value as a {@code boolean}. + */ + boolean getBoolean(); } diff --git a/msgpack-core/src/main/java/org/msgpack/value/Cursor.java b/msgpack-core/src/main/java/org/msgpack/value/Cursor.java deleted file mode 100644 index 09fa50e5f..000000000 --- a/msgpack-core/src/main/java/org/msgpack/value/Cursor.java +++ /dev/null @@ -1,66 +0,0 @@ -package org.msgpack.value; - - -import java.io.Closeable; -import java.util.Iterator; - -/** - * Cursor for traversing a stream of message-packed values - */ -public interface Cursor extends Iterator, Closeable { - - /** - * Tests whether there is a next element. - * @return true if there is a next element, or false if there is no more element. - */ - public boolean hasNext(); - - /** - * Returns a reference to the value, then proceeds the cursor. - * The returned reference is valid until {@link #hasNext()} is called. - * @return - */ - public ValueRef nextRef(); - - /** - * Returns the materialized value of the referenced value, then proceeds the cursor. - * @return - */ - public Value next(); - - /** - * Skip reading the current value. - */ - public void skip(); - - /** - * Returns the number of the read bytes - * @return the number of the read bytes - */ - public long getReadBytes(); - - public static interface Function { - public Out apply(Value input) throws Exception; - } - - /** - * Applies a function f to the referenced value, then returns the result of the function. - * @param f a function that receives the referenced value. - * @param the result type of the function - * @return the result of the function - */ - public Out apply(Function f); - - public boolean isNilValue(); - public boolean isBooleanValue(); - public boolean isNumberValue(); - public boolean isIntegerValue(); - public boolean isFloatValue(); - public boolean isBinaryValue(); - public boolean isStringValue(); - public boolean isRawValue(); - public boolean isArrayValue(); - public boolean isMapValue(); - public boolean isExtendedValue(); - -} diff --git a/msgpack-core/src/main/java/org/msgpack/value/ExtendedValue.java b/msgpack-core/src/main/java/org/msgpack/value/ExtendedValue.java deleted file mode 100644 index 9d4b47a16..000000000 --- a/msgpack-core/src/main/java/org/msgpack/value/ExtendedValue.java +++ /dev/null @@ -1,9 +0,0 @@ -package org.msgpack.value; - -/** -* Created on 5/30/14. -*/ -public interface ExtendedValue extends RawValue { - public int getExtType(); - public ExtendedValue toValue(); -} diff --git a/msgpack-core/src/main/java/org/msgpack/value/ValueVisitor.java b/msgpack-core/src/main/java/org/msgpack/value/ExtensionValue.java similarity index 55% rename from msgpack-core/src/main/java/org/msgpack/value/ValueVisitor.java rename to msgpack-core/src/main/java/org/msgpack/value/ExtensionValue.java index 22436d30a..12db63f29 100644 --- a/msgpack-core/src/main/java/org/msgpack/value/ValueVisitor.java +++ b/msgpack-core/src/main/java/org/msgpack/value/ExtensionValue.java @@ -16,19 +16,15 @@ package org.msgpack.value; /** - * Interface for implementing the visitor pattern on message-packed values + * The interface {@code ExtensionValue} represents MessagePack's Extension type. + * + * MessagePack's Extension type can represent represents a tuple of type information and a byte array where type information is an + * integer whose meaning is defined by applications. + * + * As the type information, applications can use 0 to 127 as the application-specific types. -1 to -128 is reserved for MessagePack's future extension. */ -public interface ValueVisitor { +public interface ExtensionValue extends Value { + byte getType(); - public void visitNil(); - public void visitBoolean(boolean v); - public void visitInteger(IntegerValue v); - public void visitFloat(FloatValue v); - public void visitBinary(BinaryValue v); - public void visitString(StringValue v); - public void visitArray(ArrayValue v); - public void visitMap(MapValue v); - public void visitExtended(ExtendedValue v); - - public void onError(Exception e); + byte[] getData(); } diff --git a/msgpack-core/src/main/java/org/msgpack/value/FloatValue.java b/msgpack-core/src/main/java/org/msgpack/value/FloatValue.java index 3e5dda745..78f6da0e5 100644 --- a/msgpack-core/src/main/java/org/msgpack/value/FloatValue.java +++ b/msgpack-core/src/main/java/org/msgpack/value/FloatValue.java @@ -1,8 +1,26 @@ +// +// MessagePack for Java +// +// 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.msgpack.value; /** -* Created on 5/30/14. -*/ + * The interface {@code FloatValue} represents MessagePack's Float type. + * + * MessagePack's Float type can represent IEEE 754 double precision floating point numbers including NaN and infinity. This is same with Java's {@code double} type. + * + * @see org.msgpack.value.NumberValue + */ public interface FloatValue extends NumberValue { - FloatValue toValue(); } diff --git a/msgpack-core/src/main/java/org/msgpack/value/ImmutableArrayValue.java b/msgpack-core/src/main/java/org/msgpack/value/ImmutableArrayValue.java new file mode 100644 index 000000000..1c0ea24bb --- /dev/null +++ b/msgpack-core/src/main/java/org/msgpack/value/ImmutableArrayValue.java @@ -0,0 +1,34 @@ +// +// MessagePack for Java +// +// 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.msgpack.value; + +import java.util.List; +import java.util.Iterator; + + +public interface ImmutableArrayValue extends ArrayValue, ImmutableValue { + /** + * Returns an iterator over elements. + * Returned Iterator does not support {@code remove()} method since the value is immutable. + */ + Iterator iterator(); + + /** + * Returns the value as {@code List}. + * Returned List is immutable. It does not support {@code put()}, {@code clear()}, or other methods that modify the value. + */ + List list(); +} diff --git a/msgpack-core/src/main/java/org/msgpack/value/ImmutableBinaryValue.java b/msgpack-core/src/main/java/org/msgpack/value/ImmutableBinaryValue.java new file mode 100644 index 000000000..ce52bfc33 --- /dev/null +++ b/msgpack-core/src/main/java/org/msgpack/value/ImmutableBinaryValue.java @@ -0,0 +1,19 @@ +// +// MessagePack for Java +// +// 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.msgpack.value; + +public interface ImmutableBinaryValue extends BinaryValue, ImmutableRawValue { +} diff --git a/msgpack-core/src/main/java/org/msgpack/value/ImmutableBooleanValue.java b/msgpack-core/src/main/java/org/msgpack/value/ImmutableBooleanValue.java new file mode 100644 index 000000000..23b7dbc0b --- /dev/null +++ b/msgpack-core/src/main/java/org/msgpack/value/ImmutableBooleanValue.java @@ -0,0 +1,19 @@ +// +// MessagePack for Java +// +// 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.msgpack.value; + +public interface ImmutableBooleanValue extends BooleanValue, ImmutableValue { +} diff --git a/msgpack-core/src/main/java/org/msgpack/value/ImmutableExtensionValue.java b/msgpack-core/src/main/java/org/msgpack/value/ImmutableExtensionValue.java new file mode 100644 index 000000000..ff1f0e9ea --- /dev/null +++ b/msgpack-core/src/main/java/org/msgpack/value/ImmutableExtensionValue.java @@ -0,0 +1,19 @@ +// +// MessagePack for Java +// +// 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.msgpack.value; + +public interface ImmutableExtensionValue extends ExtensionValue, ImmutableValue { +} diff --git a/msgpack-core/src/main/java/org/msgpack/value/ImmutableFloatValue.java b/msgpack-core/src/main/java/org/msgpack/value/ImmutableFloatValue.java new file mode 100644 index 000000000..bfa6cf114 --- /dev/null +++ b/msgpack-core/src/main/java/org/msgpack/value/ImmutableFloatValue.java @@ -0,0 +1,19 @@ +// +// MessagePack for Java +// +// 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.msgpack.value; + +public interface ImmutableFloatValue extends FloatValue, ImmutableNumberValue { +} diff --git a/msgpack-core/src/main/java/org/msgpack/value/ImmutableIntegerValue.java b/msgpack-core/src/main/java/org/msgpack/value/ImmutableIntegerValue.java new file mode 100644 index 000000000..b2ab29938 --- /dev/null +++ b/msgpack-core/src/main/java/org/msgpack/value/ImmutableIntegerValue.java @@ -0,0 +1,19 @@ +// +// MessagePack for Java +// +// 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.msgpack.value; + +public interface ImmutableIntegerValue extends IntegerValue, ImmutableNumberValue { +} diff --git a/msgpack-core/src/main/java/org/msgpack/value/ImmutableMapValue.java b/msgpack-core/src/main/java/org/msgpack/value/ImmutableMapValue.java new file mode 100644 index 000000000..f612f5758 --- /dev/null +++ b/msgpack-core/src/main/java/org/msgpack/value/ImmutableMapValue.java @@ -0,0 +1,19 @@ +// +// MessagePack for Java +// +// 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.msgpack.value; + +public interface ImmutableMapValue extends MapValue, ImmutableValue { +} diff --git a/msgpack-core/src/main/java/org/msgpack/value/ImmutableNilValue.java b/msgpack-core/src/main/java/org/msgpack/value/ImmutableNilValue.java new file mode 100644 index 000000000..e4fbf48d4 --- /dev/null +++ b/msgpack-core/src/main/java/org/msgpack/value/ImmutableNilValue.java @@ -0,0 +1,19 @@ +// +// MessagePack for Java +// +// 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.msgpack.value; + +public interface ImmutableNilValue extends NilValue, ImmutableValue { +} diff --git a/msgpack-core/src/main/java/org/msgpack/value/ImmutableNumberValue.java b/msgpack-core/src/main/java/org/msgpack/value/ImmutableNumberValue.java new file mode 100644 index 000000000..f264d58da --- /dev/null +++ b/msgpack-core/src/main/java/org/msgpack/value/ImmutableNumberValue.java @@ -0,0 +1,19 @@ +// +// MessagePack for Java +// +// 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.msgpack.value; + +public interface ImmutableNumberValue extends NumberValue, ImmutableValue { +} diff --git a/msgpack-core/src/main/java/org/msgpack/value/ImmutableRawValue.java b/msgpack-core/src/main/java/org/msgpack/value/ImmutableRawValue.java new file mode 100644 index 000000000..8fa691fb6 --- /dev/null +++ b/msgpack-core/src/main/java/org/msgpack/value/ImmutableRawValue.java @@ -0,0 +1,19 @@ +// +// MessagePack for Java +// +// 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.msgpack.value; + +public interface ImmutableRawValue extends RawValue, ImmutableValue { +} diff --git a/msgpack-core/src/main/java/org/msgpack/value/ImmutableStringValue.java b/msgpack-core/src/main/java/org/msgpack/value/ImmutableStringValue.java new file mode 100644 index 000000000..10a3ee217 --- /dev/null +++ b/msgpack-core/src/main/java/org/msgpack/value/ImmutableStringValue.java @@ -0,0 +1,19 @@ +// +// MessagePack for Java +// +// 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.msgpack.value; + +public interface ImmutableStringValue extends StringValue, ImmutableRawValue { +} diff --git a/msgpack-core/src/main/java/org/msgpack/value/ImmutableValue.java b/msgpack-core/src/main/java/org/msgpack/value/ImmutableValue.java new file mode 100644 index 000000000..88d3bf260 --- /dev/null +++ b/msgpack-core/src/main/java/org/msgpack/value/ImmutableValue.java @@ -0,0 +1,47 @@ +// +// MessagePack for Java +// +// 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.msgpack.value; + +import java.io.Serializable; + +public interface ImmutableValue extends Value { + @Override + public ImmutableNilValue asNilValue(); + + @Override + public ImmutableBooleanValue asBooleanValue(); + + @Override + public ImmutableIntegerValue asIntegerValue(); + + @Override + public ImmutableFloatValue asFloatValue(); + + @Override + public ImmutableArrayValue asArrayValue(); + + @Override + public ImmutableMapValue asMapValue(); + + @Override + public ImmutableRawValue asRawValue(); + + @Override + public ImmutableBinaryValue asBinaryValue(); + + @Override + public ImmutableStringValue asStringValue(); +} diff --git a/msgpack-core/src/main/java/org/msgpack/value/IntegerValue.java b/msgpack-core/src/main/java/org/msgpack/value/IntegerValue.java index 4299b42ad..c6cfec721 100644 --- a/msgpack-core/src/main/java/org/msgpack/value/IntegerValue.java +++ b/msgpack-core/src/main/java/org/msgpack/value/IntegerValue.java @@ -1,8 +1,83 @@ +// +// MessagePack for Java +// +// 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.msgpack.value; +import java.math.BigInteger; +import org.msgpack.core.MessageIntegerOverflowException; + /** -* Created on 5/30/14. -*/ + * The interface {@code IntegerValue} represents MessagePack's Integer type. + * + * MessagePack's Integer type can represent from -263 to 264-1. + */ public interface IntegerValue extends NumberValue { - IntegerValue toValue(); + /** + * Returns true if the value is in the range of [-27 to 27-1]. + */ + boolean isInByteRange(); + + /** + * Returns true if the value is in the range of [-215 to 215-1] + */ + boolean isInShortRange(); + + /** + * Returns true if the value is in the range of [-231 to 231-1] + */ + boolean isInIntRange(); + + /** + * Returns true if the value is in the range of [-263 to 263-1] + */ + boolean isInLongRange(); + + /** + * Returns the value as a {@code byte}, otherwise throws an exception. + * + * @throws MessageIntegerOverflowException + * If the value does not fit in the range of {@code byte} type. + */ + byte getByte(); + + /** + * Returns the value as a {@code short}, otherwise throws an exception. + * + * @throws MessageIntegerOverflowException + * If the value does not fit in the range of {@code short} type. + */ + short getShort(); + + /** + * Returns the value as an {@code int}, otherwise throws an exception. + * + * @throws MessageIntegerOverflowException + * If the value does not fit in the range of {@code int} type. + */ + int getInt(); + + /** + * Returns the value as a {@code long}, otherwise throws an exception. + * + * @throws MessageIntegerOverflowException + * If the value does not fit in the range of {@code long} type. + */ + long getLong(); + + /** + * Returns the value as a {@code BigInteger}. + */ + BigInteger getBigInteger(); } diff --git a/msgpack-core/src/main/java/org/msgpack/value/MapCursor.java b/msgpack-core/src/main/java/org/msgpack/value/MapCursor.java deleted file mode 100644 index 17ac2fec2..000000000 --- a/msgpack-core/src/main/java/org/msgpack/value/MapCursor.java +++ /dev/null @@ -1,32 +0,0 @@ -package org.msgpack.value; - -/** - * Cursor for traversing map value entries. This cursor reports a sequence of key and value pairs. - */ -public interface MapCursor extends ValueRef { - public int size(); - - /** - * Test whether this cursor can point to a next key or value. - * @return - */ - public boolean hasNext(); - - /** - * Retrieves a reference to the next key or value. - * @return - */ - public ValueRef nextKeyOrValue(); - - /** - * Skips a next key or value - */ - public void skipKeyOrValue(); - - /** - * Skips all of the remaining keys and values. - */ - public void skipAll(); - - MapValue toValue(); -} diff --git a/msgpack-core/src/main/java/org/msgpack/value/MapValue.java b/msgpack-core/src/main/java/org/msgpack/value/MapValue.java index ea67fdad6..b29617c5d 100644 --- a/msgpack-core/src/main/java/org/msgpack/value/MapValue.java +++ b/msgpack-core/src/main/java/org/msgpack/value/MapValue.java @@ -1,13 +1,52 @@ +// +// MessagePack for Java +// +// 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.msgpack.value; import java.util.Map; +import java.util.Set; +import java.util.Collection; /** -* Created on 5/30/14. -*/ -public interface MapValue extends Value, MapCursor { - public Value[] toKeyValueSeq(); - public Map toMap(); + * The interface {@code ArrayValue} represents MessagePack's Map type. + * + * MessagePack's Map type can represent sequence of key-value pairs. + */ +public interface MapValue extends Value { + /** + * Returns number of key-value pairs in this array. + */ + int size(); - public MapValue toValue(); + Set keySet(); + + Set> entrySet(); + + Collection values(); + + /** + * Returns the value as {@code Map}. + */ + Map map(); + + /** + * Returns the key-value pairs as an array of {@code Value}. + * + * Odd elements are keys. Next element of an odd element is a value corresponding to the key. + * + * For example, if this value represents {"k1": "v1", "k2": "v2"}, this method returns ["k1", "v1", "k2", "v2"]. + */ + Value[] getKeyValueArray(); } diff --git a/msgpack-core/src/main/java/org/msgpack/value/NilValue.java b/msgpack-core/src/main/java/org/msgpack/value/NilValue.java index 4c8c39beb..56c23a9f9 100644 --- a/msgpack-core/src/main/java/org/msgpack/value/NilValue.java +++ b/msgpack-core/src/main/java/org/msgpack/value/NilValue.java @@ -1,8 +1,22 @@ +// +// MessagePack for Java +// +// 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.msgpack.value; /** - * References to values + * The interface {@code NilValue} represents MessagePack's Nil type. */ public interface NilValue extends Value { - NilValue toValue(); } diff --git a/msgpack-core/src/main/java/org/msgpack/value/NumberValue.java b/msgpack-core/src/main/java/org/msgpack/value/NumberValue.java index 38952fcc5..785d12581 100644 --- a/msgpack-core/src/main/java/org/msgpack/value/NumberValue.java +++ b/msgpack-core/src/main/java/org/msgpack/value/NumberValue.java @@ -1,106 +1,64 @@ +// +// MessagePack for Java +// +// 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.msgpack.value; -import org.msgpack.core.MessageOverflowException; - import java.math.BigInteger; /** -* Created on 5/30/14. -*/ + * The base interface {@code NumberValue} of {@code IntegerValue} and {@code FloatValue}. + * + * @see org.msgpack.value.IntegerValue + * @see org.msgpack.value.FloatValue + */ public interface NumberValue extends Value { /** - * Check whether this value is a valid byte value. - * @return true if this value has no fractional part, and is within the range of {@link Byte#MIN_VALUE} and {@link Byte#MAX_VALUE}; otherwise returns false - */ - public boolean isValidByte(); - - /** - * Check whether this value is a valid short value. - * @return true if this value has no fractional part, and is within the range of {@link Short#MIN_VALUE} and {@link Short#MAX_VALUE}; otherwise returns false - */ - public boolean isValidShort(); - - /** - * Check whether this value is a valid integer value. - * @return true if this value has no fractional part, and is within the range of {@link Integer#MIN_VALUE} and {@link Integer#MAX_VALUE}; otherwise returns false - */ - public boolean isValidInt(); - - /** - * Check whether this value is a valid long value. - * @return true if this value has no fractional part, and is within the range of {@link Long#MIN_VALUE} and {@link Long#MAX_VALUE}; otherwise returns false - */ - public boolean isValidLong(); - - /** - * Returns true if this number has no decimal component - * @return true if this number has no decimal component, otherwise false (float, double values); + * Represent this value as a byte value, which may involve rounding or truncation of the original value. + * the value. */ - public boolean isWhole(); + byte castAsByte(); /** - * Convert this value into a byte value. If this value is not within the range of Byte value, it will truncate or round the value. + * Represent this value as a short value, which may involve rounding or truncation of the original value. */ - public byte toByte(); - /** - * Convert this value into a short value. If this value is not within the range of Short value, it will truncate or round the value. - */ - public short toShort(); - /** - * Convert this value into an int value. If this value is not within the range of Int value, it will truncate or round the value. - */ - public int toInt(); - /** - * Convert this value into a long value. If this value is not within the range of Long value, it will truncate or round the value. - */ - public long toLong(); - /** - * Convert this value into a BigInteger - */ - public BigInteger toBigInteger(); - /** - * Convert this value into a float value - */ - public float toFloat(); - /** - * Convert this value into a double value - */ - public double toDouble(); + short castAsShort(); /** - * Convert this value into a byte value. If this value is not within the range of Byte value, it throws an exception. - * @return - * @throws org.msgpack.core.MessageOverflowException when the value is not within the range of {@link Byte#MIN_VALUE} and {@link Byte#MAX_VALUE}; + * Represent this value as an int value, which may involve rounding or truncation of the original value. + * value. */ - public byte asByte() throws MessageOverflowException; + int castAsInt(); /** - * Convert this value into a short value. If this value is not within the range of Short value, it throws an exception. - * @return - * @throws org.msgpack.core.MessageOverflowException when the value is not within the range of {@link Short#MIN_VALUE} and {@link Short#MAX_VALUE} + * Represent this value as a long value, which may involve rounding or truncation of the original value. */ - public short asShort() throws MessageOverflowException; + long castAsLong(); /** - * Convert this value into an int value. If this value is not within the range of Integer value, it throws an exception. - * @return - * @throws org.msgpack.core.MessageOverflowException when the value is not within the range of {@link Integer#MIN_VALUE} and {@link Integer#MAX_VALUE} + * Represent this value as a BigInteger, which may involve rounding or truncation of the original value. */ - public int asInt() throws MessageOverflowException; + BigInteger castAsBigInteger(); /** - * Convert this value into a long value. If this value is not within the range of Long value, it throws an exception. - * @return - * @throws org.msgpack.core.MessageOverflowException when the value is not within the range of {@link Long#MIN_VALUE} and {@link Long#MAX_VALUE} + * Represent this value as a 32-bit float value, which may involve rounding or truncation of the original value. */ - public long asLong() throws MessageOverflowException; + float castAsFloat(); /** - * Convert this value into a BigInteger value. - * @return - * @throws org.msgpack.core.MessageOverflowException + * Represent this value as a 64-bit double value, which may involve rounding or truncation of the original value. */ - public BigInteger asBigInteger() throws MessageOverflowException; - + double castAsDouble(); } diff --git a/msgpack-core/src/main/java/org/msgpack/value/RawValue.java b/msgpack-core/src/main/java/org/msgpack/value/RawValue.java index 8db9e34b1..748be0845 100644 --- a/msgpack-core/src/main/java/org/msgpack/value/RawValue.java +++ b/msgpack-core/src/main/java/org/msgpack/value/RawValue.java @@ -1,19 +1,61 @@ +// +// MessagePack for Java +// +// 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.msgpack.value; -import org.msgpack.core.buffer.MessageBuffer; - import java.nio.ByteBuffer; +import org.msgpack.core.MessageStringCodingException; /** - * Base type of StringValue, BinaryValue and ExtendedValue + * The interface {@code RawValue} represents MessagePack's Raw type, which means Binary or String type. + * + * MessagePack's Raw type can represent a byte array at most 264-1 bytes. + * + * @see org.msgpack.value.StringValue + * @see org.msgpack.value.BinaryValue */ public interface RawValue extends Value { - public byte[] toByteArray(); - public ByteBuffer toByteBuffer(); - public MessageBuffer toMessageBuffer(); + /** + * Returns the value as {@code byte[]}. + * + * This method copies the byte array. + */ + byte[] getByteArray(); + + /** + * Returns the value as {@code ByteBuffer}. + * + * Returned ByteBuffer is read-only. See {@code#asReadOnlyBuffer()}. + * This method doesn't copy the byte array as much as possible. + */ + ByteBuffer getByteBuffer(); - @Override - public String toString(); + /** + * Returns the value as {@code String}. + * + * This method throws an exception if the value includes invalid UTF-8 byte sequence. + * + * @throws MessageStringCodingException + * If this value includes invalid UTF-8 byte sequence. + */ + String getString(); - public RawValue toValue(); + /** + * Returns the value as {@code String}. + * + * This method replaces an invalid UTF-8 byte sequence with U+FFFD replacement character. + */ + String stringValue(); } diff --git a/msgpack-core/src/main/java/org/msgpack/value/StringValue.java b/msgpack-core/src/main/java/org/msgpack/value/StringValue.java index 35315f14d..0709a22b8 100644 --- a/msgpack-core/src/main/java/org/msgpack/value/StringValue.java +++ b/msgpack-core/src/main/java/org/msgpack/value/StringValue.java @@ -1,8 +1,28 @@ +// +// MessagePack for Java +// +// 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.msgpack.value; /** - * Created on 5/30/14. + * The interface {@code StringValue} represents MessagePack's String type. + * + * MessagePack's String type can represent a UTF-8 string at most 264-1 bytes. + * + * Note that the value could include invalid byte sequences. {@code getString()} method throws {@code MessageTypeStringCodingException} if the value includes invalid byte sequence. {@code stringValue()} method replaces an invalid byte sequence with U+FFFD replacement character. + * + * @see org.msgpack.value.RawValue */ public interface StringValue extends RawValue { - public StringValue toValue(); } diff --git a/msgpack-core/src/main/java/org/msgpack/value/Value.java b/msgpack-core/src/main/java/org/msgpack/value/Value.java index 0cf02453c..1cc2f964e 100644 --- a/msgpack-core/src/main/java/org/msgpack/value/Value.java +++ b/msgpack-core/src/main/java/org/msgpack/value/Value.java @@ -15,15 +15,231 @@ // package org.msgpack.value; +import org.msgpack.core.MessagePacker; +import org.msgpack.core.MessageTypeCastException; + +import java.io.IOException; -import org.msgpack.core.*; /** - * Value is a holder of a message-packed value. + * Value is an implementation of MessagePack type system. */ -public interface Value extends ValueRef { +public interface Value { + /** + * Returns type of this value. + *

+ * Note that you can't use instanceof to check type of a value because type of a mutable value is variable. + */ + ValueType getValueType(); + + /** + * Returns immutable copy of this value. + *

+ * This method simply returns this without copying the value if this value is already immutable. + */ + ImmutableValue immutableValue(); + + /** + * Returns true if type of this value is Nil. + *

+ * If this method returns true, {@code asNilValue} never throws exceptions. + * Note that you can't use instanceof or cast ((NilValue) thisValue) to check type of a value because type of a mutable value is variable. + */ + boolean isNilValue(); + + /** + * Returns true if type of this value is Boolean. + *

+ * If this method returns true, {@code asBooleanValue} never throws exceptions. + * Note that you can't use instanceof or cast ((BooleanValue) thisValue) to check type of a value because type of a mutable value is variable. + */ + boolean isBooleanValue(); + + /** + * Returns true if type of this value is Integer or Float. + *

+ * If this method returns true, {@code asNumberValue} never throws exceptions. + * Note that you can't use instanceof or cast ((NumberValue) thisValue) to check type of a value because type of a mutable value is variable. + */ + boolean isNumberValue(); + + /** + * Returns true if type of this value is Integer. + *

+ * If this method returns true, {@code asIntegerValue} never throws exceptions. + * Note that you can't use instanceof or cast ((IntegerValue) thisValue) to check type of a value because type of a mutable value is variable. + */ + boolean isIntegerValue(); + + /** + * Returns true if type of this value is Float. + *

+ * If this method returns true, {@code asFloatValue} never throws exceptions. + * Note that you can't use instanceof or cast ((FloatValue) thisValue) to check type of a value because type of a mutable value is variable. + */ + boolean isFloatValue(); + + /** + * Returns true if type of this value is String or Binary. + *

+ * If this method returns true, {@code asRawValue} never throws exceptions. + * Note that you can't use instanceof or cast ((RawValue) thisValue) to check type of a value because type of a mutable value is variable. + */ + boolean isRawValue(); + + /** + * Returns true if type of this value is Binary. + *

+ * If this method returns true, {@code asBinaryValue} never throws exceptions. + * Note that you can't use instanceof or cast ((BinaryValue) thisValue) to check type of a value because type of a mutable value is variable. + */ + boolean isBinaryValue(); + + /** + * Returns true if type of this value is String. + *

+ * If this method returns true, {@code asStringValue} never throws exceptions. + * Note that you can't use instanceof or cast ((StringValue) thisValue) to check type of a value because type of a mutable value is variable. + */ + boolean isStringValue(); + + /** + * Returns true if type of this value is Array. + *

+ * If this method returns true, {@code asArrayValue} never throws exceptions. + * Note that you can't use instanceof or cast ((ArrayValue) thisValue) to check type of a value because type of a mutable value is variable. + */ + boolean isArrayValue(); + + /** + * Returns true if type of this value is Map. + *

+ * If this method returns true, {@code asMapValue} never throws exceptions. + * Note that you can't use instanceof or cast ((MapValue) thisValue) to check type of a value because type of a mutable value is variable. + */ + boolean isMapValue(); + + /** + * Returns true if type of this an Extension. + *

+ * If this method returns true, {@code asExtensionValue} never throws exceptions. + * Note that you can't use instanceof or cast ((ExtensionValue) thisValue) to check type of a value because + * type of a mutable value is variable. + */ + boolean isExtensionValue(); + + /** + * Returns the value as {@code NilValue}. Otherwise throws {@code MessageTypeCastException}. + *

+ * Note that you can't use instanceof or cast ((NilValue) thisValue) to check type of a value because type of a mutable value is variable. + * + * @throws MessageTypeCastException If type of this value is not Nil. + */ + NilValue asNilValue(); + + /** + * Returns the value as {@code BooleanValue}. Otherwise throws {@code MessageTypeCastException}. + *

+ * Note that you can't use instanceof or cast ((BooleanValue) thisValue) to check type of a value because type of a mutable value is variable. + * + * @throws MessageTypeCastException If type of this value is not Boolean. + */ + BooleanValue asBooleanValue(); + + /** + * Returns the value as {@code NumberValue}. Otherwise throws {@code MessageTypeCastException}. + *

+ * Note that you can't use instanceof or cast ((NumberValue) thisValue) to check type of a value because type of a mutable value is variable. + * + * @throws MessageTypeCastException If type of this value is not Integer or Float. + */ + NumberValue asNumberValue(); + + /** + * Returns the value as {@code IntegerValue}. Otherwise throws {@code MessageTypeCastException}. + *

+ * Note that you can't use instanceof or cast ((IntegerValue) thisValue) to check type of a value because type of a mutable value is variable. + * + * @throws MessageTypeCastException If type of this value is not Integer. + */ + IntegerValue asIntegerValue(); + + /** + * Returns the value as {@code FloatValue}. Otherwise throws {@code MessageTypeCastException}. + *

+ * Note that you can't use instanceof or cast ((FloatValue) thisValue) to check type of a value because type of a mutable value is variable. + * + * @throws MessageTypeCastException If type of this value is not Float. + */ + FloatValue asFloatValue(); + + /** + * Returns the value as {@code RawValue}. Otherwise throws {@code MessageTypeCastException}. + *

+ * Note that you can't use instanceof or cast ((RawValue) thisValue) to check type of a value because type of a mutable value is variable. + * + * @throws MessageTypeCastException If type of this value is not Binary or String. + */ + RawValue asRawValue(); + + /** + * Returns the value as {@code BinaryValue}. Otherwise throws {@code MessageTypeCastException}. + *

+ * Note that you can't use instanceof or cast ((BinaryValue) thisValue) to check type of a value because type of a mutable value is variable. + * + * @throws MessageTypeCastException If type of this value is not Binary. + */ + BinaryValue asBinaryValue(); + + /** + * Returns the value as {@code StringValue}. Otherwise throws {@code MessageTypeCastException}. + *

+ * Note that you can't use instanceof or cast ((StringValue) thisValue) to check type of a value because type of a mutable value is variable. + * + * @throws MessageTypeCastException If type of this value is not String. + */ + StringValue asStringValue(); + + /** + * Returns the value as {@code ArrayValue}. Otherwise throws {@code MessageTypeCastException}. + *

+ * Note that you can't use instanceof or cast ((ArrayValue) thisValue) to check type of a value because type of a mutable value is variable. + * + * @throws MessageTypeCastException If type of this value is not Array. + */ + ArrayValue asArrayValue(); + + /** + * Returns the value as {@code MapValue}. Otherwise throws {@code MessageTypeCastException}. + *

+ * Note that you can't use instanceof or cast ((MapValue) thisValue) to check type of a value because type of a mutable value is variable. + * + * @throws MessageTypeCastException If type of this value is not Map. + */ + MapValue asMapValue(); + + /** + * Returns the value as {@code ExtensionValue}. Otherwise throws {@code MessageTypeCastException}. + *

+ * Note that you can't use instanceof or cast ((ExtensionValue) thisValue) to check type of a value + * because type of a mutable value is variable. + * + * @throws MessageTypeCastException If type of this value is not an Extension. + */ + ExtensionValue asExtensionValue(); - public ArrayValue asArrayValue() throws MessageTypeException; - public MapValue asMapValue() throws MessageTypeException; + /** + * Serializes the value using the specified {@code MessagePacker} + * + * @see MessagePacker + */ + void writeTo(MessagePacker pk) throws IOException; + /** + * Compares this value to the specified object. + *

+ * This method returns {@code true} if type and value are equivalent. + * If this value is {@code MapValue} or {@code ArrayValue}, this method check equivalence of elements recursively. + */ + boolean equals(Object obj); } diff --git a/msgpack-core/src/main/java/org/msgpack/value/ValueFactory.java b/msgpack-core/src/main/java/org/msgpack/value/ValueFactory.java index 084d325da..8842b6cf4 100644 --- a/msgpack-core/src/main/java/org/msgpack/value/ValueFactory.java +++ b/msgpack-core/src/main/java/org/msgpack/value/ValueFactory.java @@ -15,135 +15,171 @@ // package org.msgpack.value; -import org.msgpack.value.impl.*; - -import java.util.Iterator; -import java.util.List; -import java.util.Map; +import org.msgpack.value.impl.ImmutableNilValueImpl; +import org.msgpack.value.impl.ImmutableBooleanValueImpl; +import org.msgpack.value.impl.ImmutableLongValueImpl; +import org.msgpack.value.impl.ImmutableBigIntegerValueImpl; +import org.msgpack.value.impl.ImmutableBinaryValueImpl; +import org.msgpack.value.impl.ImmutableDoubleValueImpl; +import org.msgpack.value.impl.ImmutableStringValueImpl; +import org.msgpack.value.impl.ImmutableArrayValueImpl; +import org.msgpack.value.impl.ImmutableMapValueImpl; +import org.msgpack.value.impl.ImmutableExtensionValueImpl; + +import java.util.*; import java.math.BigInteger; -import java.nio.ByteBuffer; -/** - * Factory for creting Value instances - */ -public class ValueFactory { - public static NilValue nilValue() { - return NilValueImpl.getInstance(); - } +public final class ValueFactory { + private ValueFactory() { } - public static BooleanValue newBoolean(boolean v) { - return v ? BooleanValueImpl.TRUE : BooleanValueImpl.FALSE; + public static ImmutableNilValue newNil() { + return ImmutableNilValueImpl.get(); } - public static IntegerValue newByte(byte v) { - return new IntegerValueImpl((int) v); + public static ImmutableBooleanValue newBoolean(boolean v) { + return v ? ImmutableBooleanValueImpl.TRUE : ImmutableBooleanValueImpl.FALSE; } - public static IntegerValue newShort(short v) { - return new IntegerValueImpl((int) v); + public static ImmutableIntegerValue newInteger(byte v) { + return new ImmutableLongValueImpl(v); } - public static IntegerValue newInt(int v) { - return new IntegerValueImpl(v); + public static ImmutableIntegerValue newInteger(short v) { + return new ImmutableLongValueImpl(v); } - public static IntegerValue newLong(long v) { - return new LongValueImpl(v); + public static ImmutableIntegerValue newInteger(int v) { + return new ImmutableLongValueImpl(v); } - public static IntegerValue newBigInteger(BigInteger v) { - return new BigIntegerValueImpl(v); + public static ImmutableIntegerValue newInteger(long v) { + return new ImmutableLongValueImpl(v); } - public static FloatValue newFloat(float v) { - return new FloatValueImpl(v); + public static ImmutableIntegerValue newInteger(BigInteger v) { + return new ImmutableBigIntegerValueImpl(v); } - public static FloatValue newDouble(double v) { - return new DoubleValueImpl(v); + public static ImmutableFloatValue newFloat(float v) { + return new ImmutableDoubleValueImpl(v); } - public static BinaryValue newBinary(byte[] b) { - return new BinaryValueImpl(ByteBuffer.wrap(b)); + public static ImmutableFloatValue newFloat(double v) { + return new ImmutableDoubleValueImpl(v); } - public static BinaryValue newBinary(byte[] b, int off, int len) { - return new BinaryValueImpl(ByteBuffer.wrap(b, off, len)); + public static ImmutableBinaryValue newBinary(byte[] b) { + return new ImmutableBinaryValueImpl(b); } - public static BinaryValue newBinary(ByteBuffer bb) { - return new BinaryValueImpl(bb.duplicate()); + public static ImmutableBinaryValue newBinary(byte[] b, int off, int len) { + return new ImmutableBinaryValueImpl(Arrays.copyOfRange(b, off, len)); } - public static StringValue newString(String s) { - return new StringValueImpl(s); + public static ImmutableStringValue newString(String s) { + return new ImmutableStringValueImpl(s); } - public static StringValue newRawString(byte[] b) { - return new RawStringValueImpl(ByteBuffer.wrap(b)); + public static ImmutableStringValue newString(byte[] b) { + return new ImmutableStringValueImpl(b); } - public static StringValue newRawString(byte[] b, int off, int len) { - return new RawStringValueImpl(ByteBuffer.wrap(b, off, len)); + public static ImmutableStringValue newString(byte[] b, int off, int len) { + return new ImmutableStringValueImpl(Arrays.copyOfRange(b, off, len)); } - public static StringValue newRawString(ByteBuffer bb) { - return new RawStringValueImpl(bb.duplicate()); - } - - public static ArrayValue newArrayFrom(List list) { + public static ImmutableArrayValue newArray(List list) { if (list.isEmpty()) { - return ArrayValueImpl.empty(); + return ImmutableArrayValueImpl.empty(); } Value[] array = list.toArray(new Value[list.size()]); - return new ArrayValueImpl(array); + return new ImmutableArrayValueImpl(array); } - public static ArrayValue newArray(Value... array) { + public static ImmutableArrayValue newArray(Value... array) { if (array.length == 0) { - return ArrayValueImpl.empty(); + return ImmutableArrayValueImpl.empty(); } - return new ArrayValueImpl(array); + return new ImmutableArrayValueImpl(Arrays.copyOf(array, array.length)); } - public static ArrayValue emptyArray() { - return ArrayValueImpl.empty(); + public static ImmutableArrayValue emptyArray() { + return ImmutableArrayValueImpl.empty(); } - public static MapValue newMap(Map map) { - Value[] keyValueSequence = new Value[map.size() * 2]; + public static + ImmutableMapValue newMap(Map map) { + Value[] kvs = new Value[map.size() * 2]; Iterator> ite = map.entrySet().iterator(); int index = 0; while (ite.hasNext()) { Map.Entry pair = ite.next(); - keyValueSequence[index++] = pair.getKey(); - keyValueSequence[index++] = pair.getValue(); + kvs[index] = pair.getKey(); + index++; + kvs[index] = pair.getValue(); + index++; + } + return newMap(kvs); + } + + public static ImmutableMapValue newMap(Value[] kvs) { + if (kvs.length == 0) { + return ImmutableMapValueImpl.empty(); } - return newMap(keyValueSequence); + return new ImmutableMapValueImpl(Arrays.copyOf(kvs, kvs.length)); } - public static MapValue newMap(Value[] keyValueSequence) { - if (keyValueSequence.length == 0) { - return MapValueImpl.empty(); + public static ImmutableMapValue emptyMap() { + return ImmutableMapValueImpl.empty(); + } + + public static MapValue newMap(Map.Entry... pairs) { + MapBuilder b = new MapBuilder(); + for(Map.Entry p : pairs) { + b.put(p); } - return new MapValueImpl(keyValueSequence); + return b.build(); } - public static MapValue emptyMap() { - return MapValueImpl.empty(); + public static MapBuilder newMapBuilder() { + return new MapBuilder(); } - public static ExtendedValue newExtendedValue(int extType, byte[] extData) { - return newExtendedValue(extType, ByteBuffer.wrap(extData)); + public static Map.Entry newMapEntry(Value key, Value value) { + return new AbstractMap.SimpleEntry(key, value); } - public static ExtendedValue newExtendedValue(int extType, ByteBuffer extData) { - return new ExtendedValueImpl(extType, extData); + public static class MapBuilder { + private final Map map = new HashMap(); + + public MapBuilder() {} + + public MapValue build() { + return newMap(map); + } + + public void put(Map.Entry pair) { + put(pair.getKey(), pair.getValue()); + } + + public void put(Value key, Value value) { + map.put(key, value); + } + + public void putAll(Iterable> entries){ + for(Map.Entry entry : entries) { + put(entry.getKey(), entry.getValue()); + } + } + + public void putAll(Map map) { + for(Map.Entry entry : map.entrySet()) { + put(entry); + } + } } - /** - * Hide the default constructor to forbid instantiation of this class - */ - protected ValueFactory() { + public static ImmutableExtensionValue newExtension(byte type, byte[] data) { + return new ImmutableExtensionValueImpl(type, data); } } diff --git a/msgpack-core/src/main/java/org/msgpack/value/ValueRef.java b/msgpack-core/src/main/java/org/msgpack/value/ValueRef.java deleted file mode 100644 index 0043e4392..000000000 --- a/msgpack-core/src/main/java/org/msgpack/value/ValueRef.java +++ /dev/null @@ -1,54 +0,0 @@ -package org.msgpack.value; - -import org.msgpack.core.MessagePacker; -import org.msgpack.core.MessageTypeException; - -import java.io.IOException; - -/** - * Reference to the value - */ -public interface ValueRef { - public ValueType getValueType(); - - public NilValue asNil() throws MessageTypeException; - public BooleanValue asBoolean() throws MessageTypeException; - public NumberValue asNumber() throws MessageTypeException; - public IntegerValue asInteger() throws MessageTypeException; - public FloatValue asFloat() throws MessageTypeException; - public BinaryValue asBinary() throws MessageTypeException; - public StringValue asString() throws MessageTypeException; - public RawValue asRaw() throws MessageTypeException; - public ExtendedValue asExtended() throws MessageTypeException; - - public ArrayCursor getArrayCursor() throws MessageTypeException; - public MapCursor getMapCursor() throws MessageTypeException; - - public boolean isNil(); - public boolean isBoolean(); - public boolean isNumber(); - public boolean isInteger(); - public boolean isFloat(); - public boolean isBinary(); - public boolean isString(); - public boolean isRaw(); - public boolean isArray(); - public boolean isMap(); - public boolean isExtended(); - - public void writeTo(MessagePacker packer) throws IOException; - - public void accept(ValueVisitor visitor); - - /** - * Create an immutable value from this reference - * @return - */ - public Value toValue(); - - /** - * Test whether this value is a reference of not. - * @return true if this value is reference, otherwise false. - */ - public boolean isRef(); -} diff --git a/msgpack-core/src/main/java/org/msgpack/value/ValueType.java b/msgpack-core/src/main/java/org/msgpack/value/ValueType.java index 5e1b27b99..c04916635 100644 --- a/msgpack-core/src/main/java/org/msgpack/value/ValueType.java +++ b/msgpack-core/src/main/java/org/msgpack/value/ValueType.java @@ -30,25 +30,14 @@ public enum ValueType { BINARY(false, true), ARRAY(false, false), MAP(false, false), - EXTENDED(false, true); - + EXTENSION(false, true); private final boolean numberType; private final boolean rawType; - private final int bitMask; private ValueType(boolean numberType, boolean rawType) { this.numberType = numberType; this.rawType = rawType; - this.bitMask = 1 << this.ordinal(); - } - - public int getBitMask() { - return bitMask; - } - - public boolean isTypeOf(int bitMask) { - return (this.bitMask & bitMask) != 0; } public boolean isNilType() { @@ -91,16 +80,7 @@ public boolean isMapType() { return this == MAP; } - public boolean isExtendedType() { - return this == EXTENDED; + public boolean isExtensionType() { + return this == EXTENSION; } - - public static ValueType valueOf(byte b) { - return MessageFormat.valueOf(b).getValueType(); - } - - public String toTypeName() { - return this.name().substring(0, 1) + this.name().substring(1).toLowerCase(); - } - } diff --git a/msgpack-core/src/main/java/org/msgpack/value/Variable.java b/msgpack-core/src/main/java/org/msgpack/value/Variable.java new file mode 100644 index 000000000..227626ea8 --- /dev/null +++ b/msgpack-core/src/main/java/org/msgpack/value/Variable.java @@ -0,0 +1,1032 @@ +// +// MessagePack for Java +// +// 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.msgpack.value; + +import org.msgpack.core.MessagePack; +import org.msgpack.core.MessagePacker; +import org.msgpack.core.MessageTypeCastException; +import org.msgpack.core.MessageStringCodingException; +import org.msgpack.core.MessageIntegerOverflowException; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.List; +import java.util.Set; +import java.util.Map; +import java.util.Collection; +import java.util.Iterator; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.charset.CharsetDecoder; +import java.nio.charset.CodingErrorAction; +import java.nio.charset.CharacterCodingException; + + +public class Variable implements Value { + private abstract class AbstractValueAccessor implements Value { + @Override + public boolean isNilValue() { + return getValueType().isNilType(); + } + + @Override + public boolean isBooleanValue() { + return getValueType().isBooleanType(); + } + + @Override + public boolean isNumberValue() { + return getValueType().isNumberType(); + } + + @Override + public boolean isIntegerValue() { + return getValueType().isIntegerType(); + } + + @Override + public boolean isFloatValue() { + return getValueType().isFloatType(); + } + + @Override + public boolean isRawValue() { + return getValueType().isRawType(); + } + + @Override + public boolean isBinaryValue() { + return getValueType().isBinaryType(); + } + + @Override + public boolean isStringValue() { + return getValueType().isStringType(); + } + + @Override + public boolean isArrayValue() { + return getValueType().isArrayType(); + } + + @Override + public boolean isMapValue() { + return getValueType().isMapType(); + } + + @Override + public boolean isExtensionValue() { + return getValueType().isExtensionType(); + } + + @Override + public NilValue asNilValue() { + throw new MessageTypeCastException(); + } + + @Override + public BooleanValue asBooleanValue() { + throw new MessageTypeCastException(); + } + + @Override + public NumberValue asNumberValue() { + throw new MessageTypeCastException(); + } + + @Override + public IntegerValue asIntegerValue() { + throw new MessageTypeCastException(); + } + + @Override + public FloatValue asFloatValue() { + throw new MessageTypeCastException(); + } + + @Override + public RawValue asRawValue() { + throw new MessageTypeCastException(); + } + + @Override + public BinaryValue asBinaryValue() { + throw new MessageTypeCastException(); + } + + @Override + public StringValue asStringValue() { + throw new MessageTypeCastException(); + } + + @Override + public ArrayValue asArrayValue() { + throw new MessageTypeCastException(); + } + + @Override + public MapValue asMapValue() { + throw new MessageTypeCastException(); + } + + @Override + public ExtensionValue asExtensionValue() { + throw new MessageTypeCastException(); + } + + @Override + public boolean equals(Object obj) { + return Variable.this.equals(obj); + } + + @Override + public int hashCode() { + return Variable.this.hashCode(); + } + + @Override + public String toString() { + return Variable.this.toString(); + } + } + + public static enum Type { + NULL(ValueType.NIL), + BOOLEAN(ValueType.BOOLEAN), + LONG(ValueType.INTEGER), + BIG_INTEGER(ValueType.INTEGER), + DOUBLE(ValueType.FLOAT), + BYTE_ARRAY(ValueType.BINARY), + RAW_STRING(ValueType.STRING), + LIST(ValueType.ARRAY), + MAP(ValueType.MAP), + EXTENSION(ValueType.EXTENSION); + + private final ValueType valueType; + + private Type(ValueType valueType) { + this.valueType = valueType; + } + + public ValueType getValueType() { + return valueType; + } + } + + private final NilValueAccessor nilAccessor = new NilValueAccessor(); + private final BooleanValueAccessor booleanAccessor = new BooleanValueAccessor(); + private final IntegerValueAccessor integerAccessor = new IntegerValueAccessor(); + private final FloatValueAccessor floatAccessor = new FloatValueAccessor(); + private final BinaryValueAccessor binaryAccessor = new BinaryValueAccessor(); + private final StringValueAccessor stringAccessor = new StringValueAccessor(); + private final ArrayValueAccessor arrayAccessor = new ArrayValueAccessor(); + private final MapValueAccessor mapAccessor = new MapValueAccessor(); + private final ExtensionValueAccessor extensionAccessor = new ExtensionValueAccessor(); + + private Type type; + + private long longValue; + private double doubleValue; + private Object objectValue; + + private AbstractValueAccessor accessor; + + public Variable() { + setNilValue(); + } + + + //// + // NilValue + // + + public Variable setNilValue() { + this.type = Type.NULL; + this.accessor = nilAccessor; + return this; + } + + private class NilValueAccessor extends AbstractValueAccessor implements NilValue { + @Override + public ValueType getValueType() { + return ValueType.NIL; + } + + @Override + public NilValue asNilValue() { + return this; + } + + @Override + public ImmutableNilValue immutableValue() { + return ValueFactory.newNil(); + } + + @Override + public void writeTo(MessagePacker pk) throws IOException { + pk.packNil(); + } + } + + + //// + // BooleanValue + // + + public Variable setBooleanValue(boolean v) { + this.type = Type.BOOLEAN; + this.accessor = booleanAccessor; + this.longValue = (v ? 1L : 0L); + return this; + } + + private class BooleanValueAccessor extends AbstractValueAccessor implements BooleanValue { + @Override + public ValueType getValueType() { + return ValueType.BOOLEAN; + } + + @Override + public BooleanValue asBooleanValue() { + return this; + } + + @Override + public ImmutableBooleanValue immutableValue() { + return ValueFactory.newBoolean(getBoolean()); + } + + @Override + public boolean getBoolean() { + return longValue == 1L; + } + + @Override + public void writeTo(MessagePacker pk) throws IOException { + pk.packBoolean(longValue == 1L); + } + } + + + //// + // NumberValue + // IntegerValue + // FloatValue + // + + private static final BigInteger LONG_MIN = BigInteger.valueOf((long) Long.MIN_VALUE); + private static final BigInteger LONG_MAX = BigInteger.valueOf((long) Long.MAX_VALUE); + private static final long BYTE_MIN = (long) Byte.MIN_VALUE; + private static final long BYTE_MAX = (long) Byte.MAX_VALUE; + private static final long SHORT_MIN = (long) Short.MIN_VALUE; + private static final long SHORT_MAX = (long) Short.MAX_VALUE; + private static final long INT_MIN = (long) Integer.MIN_VALUE; + private static final long INT_MAX = (long) Integer.MAX_VALUE; + + private abstract class AbstractNumberValueAccessor extends AbstractValueAccessor implements NumberValue { + @Override + public NumberValue asNumberValue() { + return this; + } + + @Override + public byte castAsByte() { + if (type == Type.BIG_INTEGER) { + return ((BigInteger) objectValue).byteValue(); + } + return (byte) longValue; + } + + @Override + public short castAsShort() { + if (type == Type.BIG_INTEGER) { + return ((BigInteger) objectValue).shortValue(); + } + return (short) longValue; + } + + @Override + public int castAsInt() { + if (type == Type.BIG_INTEGER) { + return ((BigInteger) objectValue).intValue(); + } + return (int) longValue; + } + + @Override + public long castAsLong() { + if (type == Type.BIG_INTEGER) { + return ((BigInteger) objectValue).longValue(); + } + return (long) longValue; + } + + @Override + public BigInteger castAsBigInteger() { + if (type == Type.BIG_INTEGER) { + return (BigInteger) objectValue; + } + else if (type == Type.DOUBLE) { + return new BigDecimal(doubleValue).toBigInteger(); + } + return BigInteger.valueOf(longValue); + } + + @Override + public float castAsFloat() { + if (type == Type.BIG_INTEGER) { + return ((BigInteger) objectValue).floatValue(); + } + else if (type == Type.DOUBLE) { + return (float) doubleValue; + } + return (float) longValue; + } + + @Override + public double castAsDouble() { + if (type == Type.BIG_INTEGER) { + return ((BigInteger) objectValue).doubleValue(); + } + else if (type == Type.DOUBLE) { + return doubleValue; + } + return (double) longValue; + } + } + + + //// + // IntegerValue + // + + public Variable setIntegerValue(long v) { + this.type = Type.LONG; + this.accessor = integerAccessor; + this.longValue = v; + return this; + } + + public Variable setIntegerValue(BigInteger v) { + if (0 <= v.compareTo(LONG_MIN) && v.compareTo(LONG_MAX) <= 0) { + this.type = Type.LONG; + this.accessor = integerAccessor; + this.longValue = v.longValue(); + } else { + this.type = Type.BIG_INTEGER; + this.accessor = integerAccessor; + this.objectValue = v; + } + return this; + } + + private class IntegerValueAccessor extends AbstractNumberValueAccessor implements IntegerValue { + @Override + public ValueType getValueType() { + return ValueType.INTEGER; + } + + @Override + public IntegerValue asIntegerValue() { + return this; + } + + @Override + public ImmutableIntegerValue immutableValue() { + if (type == Type.BIG_INTEGER) { + return ValueFactory.newInteger((BigInteger) objectValue); + } + return ValueFactory.newInteger(longValue); + } + + @Override + public boolean isInByteRange() { + if (type == Type.BIG_INTEGER) { + return false; + } + return BYTE_MIN <= longValue && longValue <= BYTE_MAX; + } + + @Override + public boolean isInShortRange() { + if (type == Type.BIG_INTEGER) { + return false; + } + return SHORT_MIN <= longValue && longValue <= SHORT_MAX; + } + + @Override + public boolean isInIntRange() { + if (type == Type.BIG_INTEGER) { + return false; + } + return INT_MIN <= longValue && longValue <= INT_MAX; + } + + @Override + public boolean isInLongRange() { + if (type == Type.BIG_INTEGER) { + return false; + } + return true; + } + + @Override + public byte getByte() { + if (!isInByteRange()) { + throw new MessageIntegerOverflowException(longValue); + } + return (byte) longValue; + } + + @Override + public short getShort() { + if (!isInByteRange()) { + throw new MessageIntegerOverflowException(longValue); + } + return (short) longValue; + } + + @Override + public int getInt() { + if (!isInIntRange()) { + throw new MessageIntegerOverflowException(longValue); + } + return (int) longValue; + } + + @Override + public long getLong() { + if (!isInLongRange()) { + throw new MessageIntegerOverflowException(longValue); + } + return longValue; + } + + @Override + public BigInteger getBigInteger() { + if (type == Type.BIG_INTEGER) { + return (BigInteger) objectValue; + } else { + return BigInteger.valueOf(longValue); + } + } + + @Override + public void writeTo(MessagePacker pk) throws IOException { + if (type == Type.BIG_INTEGER) { + pk.packBigInteger((BigInteger) objectValue); + } else { + pk.packLong(longValue); + } + } + } + + + //// + // FloatValue + // + + public Variable setFloatValue(double v) { + this.type = Type.DOUBLE; + this.accessor = floatAccessor; + this.doubleValue = v; + this.longValue = (long) v; // AbstractNumberValueAccessor uses castAsLong + return this; + } + + public Variable setFloatValue(float v) { + this.type = Type.DOUBLE; + this.accessor = floatAccessor; + this.longValue = (long) v; // AbstractNumberValueAccessor uses castAsLong + return this; + } + + private class FloatValueAccessor extends AbstractNumberValueAccessor implements FloatValue { + @Override + public FloatValue asFloatValue() { + return this; + } + + @Override + public ImmutableFloatValue immutableValue() { + return ValueFactory.newFloat(doubleValue); + } + + @Override + public ValueType getValueType() { + return ValueType.FLOAT; + } + + @Override + public void writeTo(MessagePacker pk) throws IOException { + pk.packDouble(doubleValue); + } + } + + + //// + // RawValue + // BinaryValue + // StringValue + // + + private abstract class AbstractRawValueAccessor extends AbstractValueAccessor implements RawValue { + @Override + public RawValue asRawValue() { + return this; + } + + @Override + public byte[] getByteArray() { + return (byte[]) objectValue; + } + + @Override + public ByteBuffer getByteBuffer() { + return ByteBuffer.wrap(getByteArray()); + } + + @Override + public String getString() { + byte[] raw = (byte[]) objectValue; + try { + CharsetDecoder reportDecoder = MessagePack.UTF8.newDecoder() + .onMalformedInput(CodingErrorAction.REPORT) + .onUnmappableCharacter(CodingErrorAction.REPORT); + return reportDecoder.decode(ByteBuffer.wrap(raw)).toString(); + } catch (CharacterCodingException ex) { + throw new MessageStringCodingException(ex); + } + } + + @Override + public String stringValue() { + byte[] raw = (byte[]) objectValue; + try { + CharsetDecoder reportDecoder = MessagePack.UTF8.newDecoder() + .onMalformedInput(CodingErrorAction.REPLACE) + .onUnmappableCharacter(CodingErrorAction.REPLACE); + return reportDecoder.decode(ByteBuffer.wrap(raw)).toString(); + } catch (CharacterCodingException ex) { + throw new MessageStringCodingException(ex); + } + } + } + + //// + // BinaryValue + // + + public Variable setBinaryValue(byte[] v) { + this.type = Type.BYTE_ARRAY; + this.accessor = binaryAccessor; + this.objectValue = v; + return this; + } + + private class BinaryValueAccessor extends AbstractRawValueAccessor implements BinaryValue { + @Override + public ValueType getValueType() { + return ValueType.BINARY; + } + + @Override + public BinaryValue asBinaryValue() { + return this; + } + + @Override + public ImmutableBinaryValue immutableValue() { + return ValueFactory.newBinary(getByteArray()); + } + + @Override + public void writeTo(MessagePacker pk) throws IOException { + byte[] data = (byte[]) objectValue; + pk.packBinaryHeader(data.length); + pk.writePayload(data); + } + } + + + //// + // StringValue + // + + public Variable setStringValue(String v) { + return setStringValue(v.getBytes(MessagePack.UTF8)); + } + + public Variable setStringValue(byte[] v) { + this.type = Type.RAW_STRING; + this.accessor = stringAccessor; + this.objectValue = v; + return this; + } + + private class StringValueAccessor extends AbstractRawValueAccessor implements StringValue { + @Override + public ValueType getValueType() { + return ValueType.STRING; + } + + @Override + public StringValue asStringValue() { + return this; + } + + @Override + public ImmutableStringValue immutableValue() { + return ValueFactory.newString((byte[]) objectValue); + } + + @Override + public void writeTo(MessagePacker pk) throws IOException { + byte[] data = (byte[]) objectValue; + pk.packRawStringHeader(data.length); + pk.writePayload(data); + } + } + + + //// + // ArrayValue + // + + public Variable setArrayValue(List v) { + this.type = Type.LIST; + this.accessor = arrayAccessor; + this.objectValue = v; + return this; + } + + private class ArrayValueAccessor extends AbstractValueAccessor implements ArrayValue { + @Override + public ValueType getValueType() { + return ValueType.ARRAY; + } + + @Override + public ArrayValue asArrayValue() { + return this; + } + + @Override + public ImmutableArrayValue immutableValue() { + return ValueFactory.newArray(list()); + } + + @Override + public int size() { + return list().size(); + } + + @Override + public Value get(int index) { + return list().get(index); + } + + @Override + public Value getOrNilValue(int index) { + List l = list(); + if (l.size() < index && index >= 0) { + return ValueFactory.newNil(); + } + return l.get(index); + } + + @Override + public Iterator iterator() { + return list().iterator(); + } + + @Override + @SuppressWarnings("unchecked") + public List list() { + return (List) objectValue; + } + + @Override + public void writeTo(MessagePacker pk) throws IOException { + List l = list(); + pk.packArrayHeader(l.size()); + for (Value e : l) { + e.writeTo(pk); + } + } + } + + //// + // MapValue + // + + public Variable setMapValue(Map v) { + this.type = Type.MAP; + this.accessor = mapAccessor; + this.objectValue = v; + return this; + } + + private class MapValueAccessor extends AbstractValueAccessor implements MapValue { + @Override + public ValueType getValueType() { + return ValueType.MAP; + } + + @Override + public MapValue asMapValue() { + return this; + } + + @Override + public ImmutableMapValue immutableValue() { + return ValueFactory.newMap(map()); + } + + @Override + public int size() { + return map().size(); + } + + @Override + public Set keySet() { + return map().keySet(); + } + + @Override + public Set> entrySet() { + return map().entrySet(); + } + + @Override + public Collection values() { + return map().values(); + } + + @Override + public Value[] getKeyValueArray() { + Map v = map(); + Value[] kvs = new Value[v.size() * 2]; + Iterator> ite = v.entrySet().iterator(); + int i = 0; + while (ite.hasNext()) { + Map.Entry pair = ite.next(); + kvs[i] = pair.getKey(); + i++; + kvs[i] = pair.getValue(); + i++; + } + return kvs; + } + + @SuppressWarnings("unchecked") + public Map map() { + return (Map) objectValue; + } + + @Override + public void writeTo(MessagePacker pk) throws IOException { + Map m = map(); + pk.packArrayHeader(m.size()); + for (Map.Entry pair : m.entrySet()) { + pair.getKey().writeTo(pk); + pair.getValue().writeTo(pk); + } + } + } + + + //// + // ExtensionValue + // + public Variable setExtensionValue(byte type, byte[] data) { + this.type = Type.EXTENSION; + this.accessor = extensionAccessor; + this.objectValue = ValueFactory.newExtension(type, data); + return this; + } + + private class ExtensionValueAccessor extends AbstractValueAccessor implements ExtensionValue { + @Override + public ValueType getValueType() { + return ValueType.EXTENSION; + } + + @Override + public ExtensionValue asExtensionValue() { + return this; + } + + @Override + public ImmutableExtensionValue immutableValue() { + return (ImmutableExtensionValue) objectValue; + } + + @Override + public byte getType() { + return ((ImmutableExtensionValue) objectValue).getType(); + } + + @Override + public byte[] getData() { + return ((ImmutableExtensionValue) objectValue).getData(); + } + + @Override + public void writeTo(MessagePacker pk) throws IOException { + ((ImmutableExtensionValue) objectValue).writeTo(pk); + } + } + + + //// + // Value + // + + @Override + public ImmutableValue immutableValue() { + return accessor.immutableValue(); + } + + @Override + public void writeTo(MessagePacker pk) throws IOException { + accessor.writeTo(pk); + } + + @Override + public int hashCode() { + return immutableValue().hashCode(); // TODO optimize + } + + @Override + public boolean equals(Object o) { + return immutableValue().equals(o); // TODO optimize + } + + @Override + public String toString() { + return immutableValue().toString(); // TODO optimize + } + + @Override + public ValueType getValueType() { + return type.getValueType(); + } + + @Override + public boolean isNilValue() { + return getValueType().isNilType(); + } + + @Override + public boolean isBooleanValue() { + return getValueType().isBooleanType(); + } + + @Override + public boolean isNumberValue() { + return getValueType().isNumberType(); + } + + @Override + public boolean isIntegerValue() { + return getValueType().isIntegerType(); + } + + @Override + public boolean isFloatValue() { + return getValueType().isFloatType(); + } + + @Override + public boolean isRawValue() { + return getValueType().isRawType(); + } + + @Override + public boolean isBinaryValue() { + return getValueType().isBinaryType(); + } + + @Override + public boolean isStringValue() { + return getValueType().isStringType(); + } + + @Override + public boolean isArrayValue() { + return getValueType().isArrayType(); + } + + @Override + public boolean isMapValue() { + return getValueType().isMapType(); + } + + @Override + public boolean isExtensionValue() { + return getValueType().isExtensionType(); + } + + @Override + public NilValue asNilValue() { + if (!isNilValue()) { + throw new MessageTypeCastException(); + } + return (NilValue) accessor; + } + + @Override + public BooleanValue asBooleanValue() { + if (!isBooleanValue()) { + throw new MessageTypeCastException(); + } + return (BooleanValue) accessor; + } + + @Override + public NumberValue asNumberValue() { + if (!isNumberValue()) { + throw new MessageTypeCastException(); + } + return (NumberValue) accessor; + } + + @Override + public IntegerValue asIntegerValue() { + if (!isIntegerValue()) { + throw new MessageTypeCastException(); + } + return (IntegerValue) accessor; + } + + @Override + public FloatValue asFloatValue() { + if (!isFloatValue()) { + throw new MessageTypeCastException(); + } + return (FloatValue) accessor; + } + + @Override + public RawValue asRawValue() { + if (!isRawValue()) { + throw new MessageTypeCastException(); + } + return (RawValue) accessor; + } + + @Override + public BinaryValue asBinaryValue() { + if (!isBinaryValue()) { + throw new MessageTypeCastException(); + } + return (BinaryValue) accessor; + } + + @Override + public StringValue asStringValue() { + if (!isStringValue()) { + throw new MessageTypeCastException(); + } + return (StringValue) accessor; + } + + @Override + public ArrayValue asArrayValue() { + if (!isArrayValue()) { + throw new MessageTypeCastException(); + } + return (ArrayValue) accessor; + } + + @Override + public MapValue asMapValue() { + if (!isMapValue()) { + throw new MessageTypeCastException(); + } + return (MapValue) accessor; + } + + @Override + public ExtensionValue asExtensionValue() { + if (!isExtensionValue()) { + throw new MessageTypeCastException(); + } + return (ExtensionValue) accessor; + } +} diff --git a/msgpack-core/src/main/java/org/msgpack/value/holder/ExtHolder.java b/msgpack-core/src/main/java/org/msgpack/value/holder/ExtHolder.java deleted file mode 100644 index 104e74210..000000000 --- a/msgpack-core/src/main/java/org/msgpack/value/holder/ExtHolder.java +++ /dev/null @@ -1,69 +0,0 @@ -package org.msgpack.value.holder; - -import org.msgpack.core.MessagePack; -import org.msgpack.core.MessagePacker; -import org.msgpack.core.MessageStringCodingException; -import org.msgpack.core.buffer.MessageBuffer; -import org.msgpack.value.*; -import org.msgpack.value.impl.AbstractValueRef; - -import java.io.IOException; -import java.nio.ByteBuffer; - -/** - * Created on 6/13/14. - */ -public class ExtHolder extends AbstractValueRef implements ExtendedValue { - - private int extType; - private MessageBuffer buffer; - - - public void setExtType(int extType, MessageBuffer buffer) { - this.extType = extType; - this.buffer = buffer; - } - - @Override - public int getExtType() { - return extType; - } - - @Override - public ValueType getValueType() { - return ValueType.EXTENDED; - } - - @Override - public void writeTo(MessagePacker packer) throws IOException { - packer.packExtendedTypeHeader(extType, buffer.size()).writePayload(buffer.toByteBuffer()); - } - - @Override - public void accept(ValueVisitor visitor) { - visitor.visitExtended(this); - } - @Override - public ExtendedValue toValue() { - // clone the buffer contents - return ValueFactory.newExtendedValue(extType, buffer.toByteArray()); - } - - @Override - public byte[] toByteArray() { - return buffer.toByteArray(); - } - @Override - public ByteBuffer toByteBuffer() { - return buffer.toByteBuffer(); - } - @Override - public MessageBuffer toMessageBuffer() { - return buffer; - } - - @Override - public String toString() throws MessageStringCodingException { - return new String(buffer.toByteArray(), MessagePack.UTF8); - } -} diff --git a/msgpack-core/src/main/java/org/msgpack/value/holder/FloatHolder.java b/msgpack-core/src/main/java/org/msgpack/value/holder/FloatHolder.java deleted file mode 100644 index fb369afdb..000000000 --- a/msgpack-core/src/main/java/org/msgpack/value/holder/FloatHolder.java +++ /dev/null @@ -1,178 +0,0 @@ -package org.msgpack.value.holder; - -import org.msgpack.core.MessageFloatOverflowException; -import org.msgpack.core.MessageOverflowException; -import org.msgpack.core.MessagePacker; -import org.msgpack.value.*; -import org.msgpack.value.impl.AbstractValueRef; - -import java.io.IOException; -import java.math.BigDecimal; -import java.math.BigInteger; - -/** - * Created on 6/3/14. - */ -public class FloatHolder extends AbstractValueRef implements FloatValue { - - public static enum Type { - FLOAT, - DOUBLE - } - - private Type tpe; - private double value; - - @Override - public boolean isValidByte() { - return ((double) ((byte) value)) == value; - } - @Override - public boolean isValidShort() { - return ((double) ((short) value)) == value; - } - @Override - public boolean isValidInt() { - return ((double) ((int) value)) == value; - } - @Override - public boolean isValidLong() { - long l = (long) value; - return ((double) l) == value && l != Long.MAX_VALUE; - } - @Override - public boolean isWhole() { - long l = (long) value; - return ((double) l == value) || l == Long.MAX_VALUE && value < Double.POSITIVE_INFINITY || l == Long.MIN_VALUE && value > Double.NEGATIVE_INFINITY; - } - @Override - public byte toByte() { - return (byte) value; - } - - @Override - public short toShort() { - return (short) value; - } - - @Override - public int toInt() { - return (int) value; - } - - @Override - public long toLong() { - return (long) value; - } - - @Override - public BigInteger toBigInteger() { - return new BigDecimal(value).toBigInteger(); - } - - @Override - public float toFloat() { - return (float) value; - } - - @Override - public double toDouble() { - return value; - } - @Override - public byte asByte() throws MessageOverflowException { - if(!isValidByte()) - throw new MessageFloatOverflowException(value); - return (byte) value; - } - @Override - public short asShort() throws MessageOverflowException { - if(!isValidShort()) - throw new MessageFloatOverflowException(value); - return (short) value; - } - @Override - public int asInt() throws MessageOverflowException { - if(!isValidInt()) - throw new MessageFloatOverflowException(value); - return (int) value; - } - @Override - public long asLong() throws MessageOverflowException { - if(!isValidLong()) - throw new MessageFloatOverflowException(value); - return (long) value; - } - @Override - public BigInteger asBigInteger() throws MessageOverflowException { - if(!isWhole()) - throw new MessageFloatOverflowException(value); - return new BigDecimal(value).toBigInteger(); - } - - @Override - public ValueType getValueType() { - return ValueType.FLOAT; - } - @Override - public void writeTo(MessagePacker pk) throws IOException { - switch(tpe) { - case FLOAT: - pk.packFloat(toFloat()); - break; - case DOUBLE: - pk.packDouble(value); - break; - } - } - - @Override - public void accept(ValueVisitor visitor) { - visitor.visitFloat(this); - } - @Override - public FloatValue toValue() { - switch(tpe) { - case FLOAT: - return ValueFactory.newFloat(toFloat()); - case DOUBLE: - return ValueFactory.newDouble(toDouble()); - default: - throw new IllegalStateException("cannot reach here"); - } - } - - public Type getType() { - return tpe; - } - - public void setFloat(float v) { - tpe = Type.FLOAT; - value = v; - } - - public void setDouble(double v) { - tpe = Type.DOUBLE; - value = v; - } - - @Override - public int hashCode() { - long v = Double.doubleToLongBits(value); - return (int) (v ^ (v >>> 32)); - } - - @Override - public String toString() { - switch(tpe) { - case FLOAT: - return Float.toString((float) value); - case DOUBLE: - return Double.toString(value); - default: - throw new IllegalStateException("cannot reach here"); - } - } - - -} diff --git a/msgpack-core/src/main/java/org/msgpack/value/holder/IntegerHolder.java b/msgpack-core/src/main/java/org/msgpack/value/holder/IntegerHolder.java deleted file mode 100644 index f7aab07fc..000000000 --- a/msgpack-core/src/main/java/org/msgpack/value/holder/IntegerHolder.java +++ /dev/null @@ -1,268 +0,0 @@ -package org.msgpack.value.holder; - -import org.msgpack.core.MessageIntegerOverflowException; -import org.msgpack.core.MessagePacker; -import org.msgpack.core.MessageTypeException; -import org.msgpack.value.*; -import org.msgpack.value.impl.AbstractValueRef; - -import java.io.IOException; -import java.math.BigInteger; -import static org.msgpack.core.NumberUtil.*; - -/** - * Union of integer values - */ -public class IntegerHolder extends AbstractValueRef implements IntegerValue { - - @Override - public ValueType getValueType() { - return ValueType.INTEGER; - } - @Override - public void writeTo(MessagePacker packer) throws IOException { - switch(tpe) { - case BIG_INTEGER: - packer.packBigInteger(biValue); - break; - default: - packer.packLong(longValue); - break; - } - } - - @Override - public IntegerValue asInteger() throws MessageTypeException { - return this; - } - - @Override - public void accept(ValueVisitor visitor) { - visitor.visitInteger(this); - } - - @Override - public IntegerValue toValue() { - switch(tpe){ - case BYTE: - return ValueFactory.newByte(toByte()); - case SHORT: - return ValueFactory.newShort(toShort()); - case INT: - return ValueFactory.newInt(toInt()); - case LONG: - return ValueFactory.newLong(toLong()); - case BIG_INTEGER: - return ValueFactory.newBigInteger(toBigInteger()); - default: - throw new IllegalStateException("cannot reach here"); - } - } - - public static enum Type { - BYTE, - SHORT, - INT, - LONG, - BIG_INTEGER - } - - private Type tpe; - private long longValue; - private BigInteger biValue; - - public Type getType() { - return tpe; - } - - public void setByte(byte v){ - tpe = Type.BYTE; - longValue = v; - } - public void setShort(short v) { - tpe = Type.SHORT; - longValue = v; - } - public void setInt(int v) { - tpe = Type.INT; - longValue = v; - } - public void setLong(long v) { - tpe = Type.LONG; - longValue = v; - } - public void setBigInteger(BigInteger v) { - tpe = Type.BIG_INTEGER; - biValue = v; - } - - private RuntimeException failure() { - return new IllegalStateException(); - } - - public boolean isBigInteger() { - return tpe == Type.BIG_INTEGER; - } - - @Override - public boolean isValidByte() { - return tpe == Type.BYTE; - } - @Override - public boolean isValidShort() { - return tpe.ordinal() <= Type.SHORT.ordinal(); - } - @Override - public boolean isValidInt() { - return tpe.ordinal() <= Type.INT.ordinal(); - } - @Override - public boolean isValidLong() { - return tpe.ordinal() <= Type.LONG.ordinal(); - } - - @Override - public boolean isWhole() { - return true; - } - - public byte toByte() { - return isBigInteger() ? biValue.byteValue() : (byte) longValue; - } - - public short toShort() { - return isBigInteger() ? biValue.shortValue() : (short) longValue; - } - - public int toInt() { - return isBigInteger() ? biValue.intValue() : (int) longValue; - } - - public long toLong(){ - return isBigInteger() ? biValue.longValue() : longValue; - } - - public BigInteger toBigInteger() { - return isBigInteger() ? biValue : BigInteger.valueOf(longValue); - } - @Override - public float toFloat() { - return isBigInteger() ? biValue.floatValue() : (float) longValue; - } - @Override - public double toDouble() { - return isBigInteger() ? biValue.doubleValue() : (double) longValue; - } - - - @Override - public byte asByte() throws MessageIntegerOverflowException { - switch(tpe) { - case BYTE: - return (byte) longValue; - case SHORT: - case INT: - case LONG: - if(LongUtil.isValidByte(longValue)) { - return (byte) longValue; - } - else { - throw new MessageIntegerOverflowException(longValue); - } - case BIG_INTEGER: - if(LongUtil.isValidByte(biValue)) { - return biValue.byteValue(); - } - else { - throw new MessageIntegerOverflowException(biValue); - } - default: - throw failure(); - } - } - - - @Override - public short asShort() throws MessageIntegerOverflowException { - switch(tpe) { - case BYTE: - case SHORT: - return (short) longValue; - case INT: - case LONG: - if(LongUtil.isValidShort(longValue)) { - return (short) longValue; - } - else { - throw new MessageIntegerOverflowException(longValue); - } - case BIG_INTEGER: - if(LongUtil.isValidShort(biValue)) { - return biValue.shortValue(); - } - else { - throw new MessageIntegerOverflowException(biValue); - } - default: - throw failure(); - } - } - - - @Override - public int asInt() throws MessageIntegerOverflowException { - switch(tpe) { - case BYTE: - case SHORT: - case INT: - return (int) longValue; - case LONG: - if(LongUtil.isValidInt(longValue)) { - return (int) longValue; - } - else { - throw new MessageIntegerOverflowException(longValue); - } - case BIG_INTEGER: - if(LongUtil.isValidInt(biValue)) { - return biValue.intValue(); - } - else { - throw new MessageIntegerOverflowException(biValue); - } - default: - throw failure(); - } - } - - @Override - public long asLong() throws MessageIntegerOverflowException { - if(isBigInteger()){ - if(LongUtil.isValidLong(biValue)) { - return biValue.longValue(); - } else { - throw new MessageIntegerOverflowException(biValue); - } - } - return longValue; - } - - @Override - public BigInteger asBigInteger() { - return toBigInteger(); - } - - - @Override - public int hashCode() { - return isBigInteger() ? biValue.hashCode() : (int) longValue; - } - - @Override - public String toString() { - return isBigInteger() ? biValue.toString() : Long.toString(longValue); - } - - - -} diff --git a/msgpack-core/src/main/java/org/msgpack/value/holder/RawHolder.java b/msgpack-core/src/main/java/org/msgpack/value/holder/RawHolder.java deleted file mode 100644 index 371589957..000000000 --- a/msgpack-core/src/main/java/org/msgpack/value/holder/RawHolder.java +++ /dev/null @@ -1,270 +0,0 @@ -package org.msgpack.value.holder; - -import org.msgpack.core.MessagePack; -import org.msgpack.core.MessagePacker; -import org.msgpack.core.MessageStringCodingException; -import org.msgpack.core.buffer.MessageBuffer; -import org.msgpack.value.*; -import org.msgpack.value.impl.AbstractValueRef; - -import java.io.IOException; -import java.nio.ByteBuffer; - -import static org.msgpack.core.MessagePackException.UNREACHABLE; - - -class RawHolderImpl extends AbstractValueRef implements RawValue { - - public static enum Type { - STRING, - BINARY - } - - protected Type tpe; - protected MessageBuffer buf; - - public void setString(MessageBuffer buf) { - this.tpe = Type.STRING; - this.buf = buf; - } - - public void setBinary(MessageBuffer buf) { - this.tpe = Type.BINARY; - this.buf = buf; - } - - public MessageBuffer getBuffer() { return buf; } - - @Override - public byte[] toByteArray() { - switch(tpe) { - case STRING: - case BINARY: - return buf.toByteArray(); - default: - throw UNREACHABLE; - } - } - - @Override - public ByteBuffer toByteBuffer() { - switch(tpe) { - case STRING: - return buf.toByteBuffer(); - default: - throw UNREACHABLE; - } - } - - @Override - public MessageBuffer toMessageBuffer() { - return buf; - } - - @Override - public String toString() throws MessageStringCodingException { - switch(tpe) { - case STRING: - return new String(buf.toByteArray(), MessagePack.UTF8); - case BINARY: - return buf.toHexString(0, buf.size()); - default: - throw UNREACHABLE; - } - } - - - @Override - public ValueType getValueType() { - switch(tpe) { - case STRING: - return ValueType.STRING; - case BINARY: - return ValueType.BINARY; - default: - throw UNREACHABLE; - } - } - - @Override - public void writeTo(MessagePacker packer) throws IOException { - switch(tpe) { - case STRING: - packer.packRawStringHeader(buf.size()).writePayload(buf.toByteBuffer()); - break; - case BINARY: - packer.packBinaryHeader(buf.size()).writePayload(buf.toByteBuffer()); - break; - default: - throw UNREACHABLE; - } - } - - @Override - public void accept(ValueVisitor visitor) { - switch(tpe) { - case STRING: - visitor.visitString(this.asString()); - break; - case BINARY: - visitor.visitBinary(this.asBinary()); - break; - default: - throw UNREACHABLE; - } - } - - @Override - public RawValue toValue() { - switch(tpe) { - case STRING: - return ValueFactory.newRawString(buf.toByteArray()); - case BINARY: - return ValueFactory.newBinary(buf.toByteArray()); - default: - throw UNREACHABLE; - } - } - -} - - -/** - * Holder of the raw values - */ -public class RawHolder extends RawHolderImpl { - - private static class StringValueWrap extends RawHolderImpl implements StringValue { - public StringValue toValue() { - return ValueFactory.newRawString(buf.toByteArray()); - } - } - - private static class BinaryValueWrap extends RawHolderImpl implements BinaryValue { - public BinaryValue toValue() { - return ValueFactory.newBinary(buf.toByteArray()); - } - } - - private StringValueWrap stringWrap = new StringValueWrap(); - private BinaryValueWrap binaryWrap = new BinaryValueWrap(); - - @Override - public void setString(MessageBuffer buf) { - this.tpe = Type.STRING; - this.buf = buf; - stringWrap.setString(buf); - } - - @Override - public void setBinary(MessageBuffer buf) { - this.tpe = Type.BINARY; - this.buf = buf; - binaryWrap.setBinary(buf); - } - - public MessageBuffer getBuffer() { return buf; } - - @Override - public byte[] toByteArray() { - switch(tpe) { - case STRING: - case BINARY: - return buf.toByteArray(); - default: - throw UNREACHABLE; - } - } - - @Override - public ByteBuffer toByteBuffer() { - switch(tpe) { - case STRING: - return buf.toByteBuffer(); - default: - throw UNREACHABLE; - } - } - - @Override - public MessageBuffer toMessageBuffer() { - return buf; - } - - @Override - public String toString() throws MessageStringCodingException { - switch(tpe) { - case STRING: - return new String(buf.toByteArray(), MessagePack.UTF8); - case BINARY: - return buf.toHexString(0, buf.size()); - default: - throw UNREACHABLE; - } - } - - - @Override - public ValueType getValueType() { - switch(tpe) { - case STRING: - return ValueType.STRING; - case BINARY: - return ValueType.BINARY; - default: - throw UNREACHABLE; - } - } - - @Override - public void writeTo(MessagePacker packer) throws IOException { - switch(tpe) { - case STRING: - packer.packRawStringHeader(buf.size()).writePayload(buf.toByteBuffer()); - break; - case BINARY: - packer.packBinaryHeader(buf.size()).writePayload(buf.toByteBuffer()); - break; - default: - throw UNREACHABLE; - } - } - - @Override - public void accept(ValueVisitor visitor) { - switch(tpe) { - case STRING: - visitor.visitString(this.asString()); - break; - case BINARY: - visitor.visitBinary(this.asBinary()); - break; - default: - throw UNREACHABLE; - } - } - - @Override - public RawValue toValue() { - switch(tpe) { - case STRING: - return ValueFactory.newRawString(buf.toByteArray()); - case BINARY: - return ValueFactory.newBinary(buf.toByteArray()); - default: - throw UNREACHABLE; - } - } - - - @Override - public StringValue asString() { - return stringWrap; - } - - @Override - public BinaryValue asBinary() { - return binaryWrap; - } - -} diff --git a/msgpack-core/src/main/java/org/msgpack/value/holder/ValueHolder.java b/msgpack-core/src/main/java/org/msgpack/value/holder/ValueHolder.java deleted file mode 100644 index fc0a99272..000000000 --- a/msgpack-core/src/main/java/org/msgpack/value/holder/ValueHolder.java +++ /dev/null @@ -1,127 +0,0 @@ -package org.msgpack.value.holder; - -import org.msgpack.core.MessageUnpacker; -import org.msgpack.core.buffer.MessageBuffer; -import org.msgpack.value.ValueRef; -import org.msgpack.value.impl.ArrayCursorImpl; -import org.msgpack.value.Value; -import org.msgpack.value.ValueFactory; -import org.msgpack.value.ValueType; -import org.msgpack.value.impl.MapCursorImpl; - -import java.io.IOException; -import java.nio.ByteBuffer; - -import static org.msgpack.core.MessagePackException.UNREACHABLE; - -/** - * This class can hold any message packed value. - */ -public class ValueHolder { - - private ValueType vt; - private IntegerHolder integerHolder = new IntegerHolder(); - private FloatHolder floatHolder = new FloatHolder(); - private RawHolder rawHolder = new RawHolder(); - private ExtHolder extHolder = new ExtHolder(); - private ArrayCursorImpl arrayCursor; - private MapCursorImpl mapCursor; - private ValueRef currentRef; - - public ValueRef getRef() { - if(currentRef == null) { - throw new IllegalStateException("no value is set to this holder"); - } - - return currentRef; - } - - public Value get() { - switch(vt) { - case NIL: - case BOOLEAN: - case INTEGER: - case FLOAT: - case ARRAY: - case MAP: - case EXTENDED: - return getRef().toValue(); - case STRING: - return ValueFactory.newRawString(cloneBuffer(rawHolder.getBuffer())); - case BINARY: - return ValueFactory.newBinary(cloneBuffer(rawHolder.getBuffer())); - default: - throw UNREACHABLE; - } - } - - - private static ByteBuffer cloneBuffer(MessageBuffer buffer) { - return ByteBuffer.wrap(buffer.toByteArray()); - } - - public IntegerHolder getIntegerHolder() { - return integerHolder; - } - - public FloatHolder getFloatHolder() { - return floatHolder; - } - - public void setBoolean(boolean v) { - vt = ValueType.BOOLEAN; - currentRef = ValueFactory.newBoolean(v); - } - - public void setNil() { - vt = ValueType.NIL; - currentRef = ValueFactory.nilValue(); - } - - public void setString(MessageBuffer rawString) { - vt = ValueType.STRING; - rawHolder.setString(rawString); - currentRef = rawHolder.asString(); - } - - public void setBinary(MessageBuffer b) { - vt = ValueType.BINARY; - rawHolder.setBinary(b); - currentRef = rawHolder.asBinary(); - } - - public void setToInteger() { - vt = ValueType.INTEGER; - currentRef = integerHolder; - } - - public void setToFloat() { - vt = ValueType.FLOAT; - currentRef = floatHolder; - } - - public void setExt(int extType, MessageBuffer b) { - vt = ValueType.EXTENDED; - extHolder.setExtType(extType, b); - currentRef = extHolder; - } - - public void prepareArrayCursor(MessageUnpacker unpacker) throws IOException { - vt = ValueType.ARRAY; - - // TODO reusing cursor instances - arrayCursor = new ArrayCursorImpl(new ValueHolder()); - arrayCursor.reset(unpacker); - currentRef = arrayCursor; - } - - public void prepareMapCursor(MessageUnpacker unpacker) throws IOException { - vt = ValueType.MAP; - - // TODO reusing cursor instances - mapCursor = new MapCursorImpl(new ValueHolder()); - mapCursor.reset(unpacker); - currentRef = mapCursor; - } - -} diff --git a/msgpack-core/src/main/java/org/msgpack/value/impl/AbstractImmutableRawValue.java b/msgpack-core/src/main/java/org/msgpack/value/impl/AbstractImmutableRawValue.java new file mode 100644 index 000000000..b72461943 --- /dev/null +++ b/msgpack-core/src/main/java/org/msgpack/value/impl/AbstractImmutableRawValue.java @@ -0,0 +1,171 @@ +// +// MessagePack for Java +// +// 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.msgpack.value.impl; + +import org.msgpack.core.MessagePack; +import org.msgpack.core.MessagePacker; +import org.msgpack.core.MessageStringCodingException; +import org.msgpack.value.Value; +import org.msgpack.value.ImmutableRawValue; + +import java.util.Arrays; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.charset.CharsetDecoder; +import java.nio.charset.CharsetEncoder; +import java.nio.charset.CodingErrorAction; +import java.nio.charset.CharacterCodingException; + + +public abstract class AbstractImmutableRawValue extends AbstractImmutableValue implements ImmutableRawValue { + protected final byte[] data; + private volatile String decodedStringCache; + private volatile CharacterCodingException codingException; + + public AbstractImmutableRawValue(byte[] data) { + this.data = data; + } + + public AbstractImmutableRawValue(String string) { + this.decodedStringCache = string; + this.data = string.getBytes(MessagePack.UTF8); // TODO + } + + @Override + public ImmutableRawValue asRawValue() { + return this; + } + + @Override + public byte[] getByteArray() { + return Arrays.copyOf(data, data.length); + } + + @Override + public ByteBuffer getByteBuffer() { + return ByteBuffer.wrap(data).asReadOnlyBuffer(); + } + + @Override + public String getString() { + if (decodedStringCache == null) { + decodeString(); + } + if (codingException != null) { + throw new MessageStringCodingException(codingException); + } else { + return decodedStringCache; + } + } + + @Override + public String stringValue() { + if (decodedStringCache == null) { + decodeString(); + } + return decodedStringCache; + } + + private void decodeString() { + synchronized (data) { + if (decodedStringCache != null) { + return; + } + try { + CharsetDecoder reportDecoder = MessagePack.UTF8.newDecoder() + .onMalformedInput(CodingErrorAction.REPORT) + .onUnmappableCharacter(CodingErrorAction.REPORT); + this.decodedStringCache = reportDecoder.decode(getByteBuffer()).toString(); + } catch (CharacterCodingException ex) { + try { + CharsetDecoder replaceDecoder = MessagePack.UTF8.newDecoder() + .onMalformedInput(CodingErrorAction.REPLACE) + .onUnmappableCharacter(CodingErrorAction.REPLACE); + this.decodedStringCache = replaceDecoder.decode(getByteBuffer()).toString(); + } catch (CharacterCodingException neverThrown) { + throw new MessageStringCodingException(neverThrown); + } + this.codingException = ex; + } + } + } + + @Override + public String toString() { + return toString(new StringBuilder()).toString(); + } + + private StringBuilder toString(StringBuilder sb) { + String s = stringValue(); + sb.append("\""); + for (int i = 0; i < s.length(); i++) { + char ch = s.charAt(i); + if (ch < 0x20) { + switch (ch) { + case '\n': + sb.append("\\n"); + break; + case '\r': + sb.append("\\r"); + break; + case '\t': + sb.append("\\t"); + break; + case '\f': + sb.append("\\f"); + break; + case '\b': + sb.append("\\b"); + break; + default: + // control chars + escapeChar(sb, ch); + break; + } + } else if (ch <= 0x7f) { + switch (ch) { + case '\\': + sb.append("\\\\"); + break; + case '"': + sb.append("\\\""); + break; + default: + sb.append(ch); + break; + } + } else if (ch >= 0xd800 && ch <= 0xdfff) { + // surrogates + escapeChar(sb, ch); + } else { + sb.append(ch); + } + } + sb.append("\""); + + return sb; + } + + private final static char[] HEX_TABLE = "0123456789ABCDEF".toCharArray(); + + private void escapeChar(StringBuilder sb, int ch) { + sb.append("\\u"); + sb.append(HEX_TABLE[(ch >> 12) & 0x0f]); + sb.append(HEX_TABLE[(ch >> 8) & 0x0f]); + sb.append(HEX_TABLE[(ch >> 4) & 0x0f]); + sb.append(HEX_TABLE[ch & 0x0f]); + } +} diff --git a/msgpack-core/src/main/java/org/msgpack/value/impl/AbstractImmutableValue.java b/msgpack-core/src/main/java/org/msgpack/value/impl/AbstractImmutableValue.java new file mode 100644 index 000000000..1f337e127 --- /dev/null +++ b/msgpack-core/src/main/java/org/msgpack/value/impl/AbstractImmutableValue.java @@ -0,0 +1,132 @@ +// +// MessagePack for Java +// +// 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.msgpack.value.impl; + +import org.msgpack.core.MessageTypeCastException; +import org.msgpack.value.*; + + +abstract class AbstractImmutableValue implements ImmutableValue { + @Override + public boolean isNilValue() { + return getValueType().isNilType(); + } + + @Override + public boolean isBooleanValue() { + return getValueType().isBooleanType(); + } + + @Override + public boolean isNumberValue() { + return getValueType().isNumberType(); + } + + @Override + public boolean isIntegerValue() { + return getValueType().isIntegerType(); + } + + @Override + public boolean isFloatValue() { + return getValueType().isFloatType(); + } + + @Override + public boolean isRawValue() { + return getValueType().isRawType(); + } + + @Override + public boolean isBinaryValue() { + return getValueType().isBinaryType(); + } + + @Override + public boolean isStringValue() { + return getValueType().isStringType(); + } + + @Override + public boolean isArrayValue() { + return getValueType().isArrayType(); + } + + @Override + public boolean isMapValue() { + return getValueType().isMapType(); + } + + @Override + public boolean isExtensionValue() { + return getValueType().isExtensionType(); + } + + @Override + public ImmutableNilValue asNilValue() { + throw new MessageTypeCastException(); + } + + @Override + public ImmutableBooleanValue asBooleanValue() { + throw new MessageTypeCastException(); + } + + @Override + public ImmutableNumberValue asNumberValue() { + throw new MessageTypeCastException(); + } + + @Override + public ImmutableIntegerValue asIntegerValue() { + throw new MessageTypeCastException(); + } + + @Override + public ImmutableFloatValue asFloatValue() { + throw new MessageTypeCastException(); + } + + @Override + public ImmutableRawValue asRawValue() { + throw new MessageTypeCastException(); + } + + @Override + public ImmutableBinaryValue asBinaryValue() { + throw new MessageTypeCastException(); + } + + @Override + public ImmutableStringValue asStringValue() { + throw new MessageTypeCastException(); + } + + @Override + public ImmutableArrayValue asArrayValue() { + throw new MessageTypeCastException(); + } + + @Override + public ImmutableMapValue asMapValue() { + throw new MessageTypeCastException(); + } + + @Override + public ImmutableExtensionValue asExtensionValue() { + throw new MessageTypeCastException(); + } +} diff --git a/msgpack-core/src/main/java/org/msgpack/value/impl/AbstractValue.java b/msgpack-core/src/main/java/org/msgpack/value/impl/AbstractValue.java deleted file mode 100644 index 6408ed67a..000000000 --- a/msgpack-core/src/main/java/org/msgpack/value/impl/AbstractValue.java +++ /dev/null @@ -1,13 +0,0 @@ -package org.msgpack.value.impl; - -import org.msgpack.value.*; - -/** -* Base implementation of MessagePackValue -*/ -public abstract class AbstractValue extends AbstractValueRef implements Value { - - @Override - public boolean isRef() { return false; } - -} diff --git a/msgpack-core/src/main/java/org/msgpack/value/impl/AbstractValueRef.java b/msgpack-core/src/main/java/org/msgpack/value/impl/AbstractValueRef.java deleted file mode 100644 index 1e67a6b3c..000000000 --- a/msgpack-core/src/main/java/org/msgpack/value/impl/AbstractValueRef.java +++ /dev/null @@ -1,62 +0,0 @@ -package org.msgpack.value.impl; - -import org.msgpack.core.MessageTypeException; -import org.msgpack.value.*; - -/** - * Base implementation of message pack values - */ -public abstract class AbstractValueRef implements ValueRef { - - public boolean isRef() { return true; } - - protected static int NUMBER_TYPE_MASK = (1 << ValueType.INTEGER.ordinal()) - | (1 << ValueType.FLOAT.ordinal()); - protected static int RAW_TYPE_MASK = (1 << ValueType.STRING.ordinal()) - | (1 << ValueType.BINARY.ordinal()); - - protected E as(Class valueClass, ValueType vt) { - return as(valueClass, 1 << vt.ordinal()); - } - protected E as(Class valueClass, int bitMask) { - if(this.getValueType() == null) - throw new MessageTypeException("This value points to nothing"); - if(!this.getValueType().isTypeOf(bitMask)) - throw new MessageTypeException(String.format("Expected %s, but %s", valueClass.getSimpleName(), this.getValueType())); - return valueClass.cast(this); - } - - public NilValue asNil() throws MessageTypeException { return as(NilValue.class, ValueType.NIL); } - public BooleanValue asBoolean() throws MessageTypeException{ return as(BooleanValue.class, ValueType.BOOLEAN); } - public NumberValue asNumber() throws MessageTypeException { return as(NumberValue.class, NUMBER_TYPE_MASK); } - public IntegerValue asInteger() throws MessageTypeException { return as(IntegerValue.class, ValueType.INTEGER); } - public FloatValue asFloat() throws MessageTypeException { return as(FloatValue.class, ValueType.FLOAT); } - public BinaryValue asBinary() throws MessageTypeException { return as(BinaryValue.class, ValueType.BINARY); } - public StringValue asString() throws MessageTypeException { return as(StringValue.class, ValueType.STRING); } - public RawValue asRaw() throws MessageTypeException { return as(RawValue.class, RAW_TYPE_MASK); } - public ArrayValue asArrayValue() throws MessageTypeException { return as(ArrayValue.class, ValueType.ARRAY); } - public MapValue asMapValue() throws MessageTypeException { return as(MapValue.class, ValueType.MAP); } - public ExtendedValue asExtended() throws MessageTypeException { return as(ExtendedValue.class, ValueType.EXTENDED); } - - @Override - public ArrayCursor getArrayCursor() throws MessageTypeException { - throw new MessageTypeException("This value is not an array type"); - } - @Override - public MapCursor getMapCursor() throws MessageTypeException { - throw new MessageTypeException("This value is not a map type"); - } - - public boolean isNil() { return getValueType().isNilType(); } - public boolean isBoolean() { return getValueType().isBooleanType(); } - public boolean isNumber() { return getValueType().isNumberType(); } - public boolean isInteger() { return getValueType().isIntegerType(); } - public boolean isFloat() { return getValueType().isFloatType(); } - public boolean isBinary() { return getValueType().isBinaryType(); } - public boolean isString() { return getValueType().isStringType(); } - public boolean isRaw() { return getValueType().isRawType(); } - public boolean isArray() { return getValueType().isArrayType(); } - public boolean isMap() { return getValueType().isMapType(); } - public boolean isExtended() { return getValueType().isExtendedType(); } - -} diff --git a/msgpack-core/src/main/java/org/msgpack/value/impl/ArrayCursorImpl.java b/msgpack-core/src/main/java/org/msgpack/value/impl/ArrayCursorImpl.java deleted file mode 100644 index 5a5a1676e..000000000 --- a/msgpack-core/src/main/java/org/msgpack/value/impl/ArrayCursorImpl.java +++ /dev/null @@ -1,126 +0,0 @@ -package org.msgpack.value.impl; - -import org.msgpack.core.*; -import org.msgpack.value.*; -import org.msgpack.value.holder.ValueHolder; -import static org.msgpack.core.MessagePackException.UNSUPPORTED; - -import java.io.IOException; -import java.util.Iterator; - -/** - * Created on 6/16/14. - */ -public class ArrayCursorImpl extends AbstractValueRef implements ArrayCursor { - - private final ValueHolder valueHolder; - private MessageUnpacker unpacker; - private int cursor = 0; - private int arraySize; - - public ArrayCursorImpl(ValueHolder valueHolder) { - this.valueHolder = valueHolder; - } - - public void reset(MessageUnpacker unpacker) throws IOException { - this.unpacker = unpacker; - this.arraySize = unpacker.unpackArrayHeader(); - this.cursor = 0; - } - - @Override - public int size() { - return arraySize; - } - - @Override - public Iterator iterator() { - return new Iterator() { - @Override - public boolean hasNext() { - return ArrayCursorImpl.this.hasNext(); - } - @Override - public ValueRef next() { - return ArrayCursorImpl.this.next(); - } - @Override - public void remove() { - throw UNSUPPORTED("remove"); - } - }; - } - - public boolean hasNext() { - return cursor < arraySize; - } - - public ValueRef next() { - try { - unpacker.unpackValue(valueHolder); - cursor++; - return valueHolder.getRef(); - } - catch(IOException e) { - throw new MessageFormatException(e); - } - } - - @Override - public void skip() { - try { - unpacker.skipValue(); - cursor++; - } - catch(IOException e) { - throw new MessageFormatException(e); - } - } - - @Override - public void skipAll() { - while(hasNext()) { - skip(); - } - } - - - private void ensureNotTraversed() { - if(cursor != 0) - throw UNSUPPORTED("ArrayCursor is already traversed"); - } - - @Override - public ValueType getValueType() { - return ValueType.ARRAY; - } - - @Override - public ArrayCursor getArrayCursor() throws MessageTypeException { - return this; - } - - @Override - public void writeTo(MessagePacker packer) throws IOException { - ensureNotTraversed(); - packer.packArrayHeader(arraySize); - for(ValueRef v : this) { - packer.packValue(v.toValue()); - } - } - - @Override - public void accept(ValueVisitor visitor) { - visitor.visitArray(toValue()); - } - - @Override - public ArrayValue toValue() { - Value[] arr = new Value[arraySize]; - int i = 0; - for(ValueRef v : this) { - arr[i++] = v.toValue(); - } - return ValueFactory.newArray(arr); - } -} diff --git a/msgpack-core/src/main/java/org/msgpack/value/impl/ArrayValueImpl.java b/msgpack-core/src/main/java/org/msgpack/value/impl/ArrayValueImpl.java deleted file mode 100644 index c54df5992..000000000 --- a/msgpack-core/src/main/java/org/msgpack/value/impl/ArrayValueImpl.java +++ /dev/null @@ -1,162 +0,0 @@ -package org.msgpack.value.impl; - -import org.msgpack.core.MessagePacker; -import org.msgpack.core.MessageTypeException; -import org.msgpack.value.*; - -import java.io.IOException; -import java.util.Arrays; -import java.util.Iterator; - -/** -* Created on 5/30/14. -*/ -public class ArrayValueImpl extends AbstractValue implements ArrayValue { - private static ArrayValueImpl EMPTY = new ArrayValueImpl(new Value[0]); - - public static ArrayValue empty() { - return EMPTY; - } - - private int cursor = 0; - private final Value[] array; - - public ArrayValueImpl(Value[] array) { - this.array = array; - } - - public Value get(int index) { - return array[index]; - } - - public Value apply(int index) { - return array[index]; - } - - @Override - public ValueType getValueType() { - return ValueType.ARRAY; - } - - - @Override - public ArrayCursor getArrayCursor() throws MessageTypeException { - return this; - } - - @Override - public void writeTo(MessagePacker pk) throws IOException { - pk.packArrayHeader(array.length); - for(int i = 0; i < array.length; i++) { - array[i].writeTo(pk); - } - } - @Override - public void accept(ValueVisitor visitor) { - visitor.visitArray(this); - } - @Override - public ArrayValue toValue() { - return this; - } - - @Override - public boolean equals(Object o) { - if(o == this) { - return true; - } - if(!(o instanceof Value)) { - return false; - } - Value v = (Value) o; - if(!v.isArray()) { - return false; - } - Value[] other = v.asArrayValue().toValueArray(); - if(array.length != other.length) - return false; - - for(int i = 0; i < array.length; i++) { - if(!array[i].equals(other[i])) { - return false; - } - } - return true; - } - - @Override - public int hashCode() { - int h = 1; - for(int i = 0; i < array.length; i++) { - Value obj = array[i]; - h = 31 * h + obj.hashCode(); - } - return h; - } - - @Override - public String toString() { - return toString(new StringBuilder()).toString(); - } - - private StringBuilder toString(StringBuilder sb) { - if(array.length == 0) { - return sb.append("[]"); - } - sb.append("["); - sb.append(array[0]); - for(int i = 1; i < array.length; i++) { - sb.append(","); - sb.append(array[i].toString()); - } - sb.append("]"); - return sb; - } - - @Override - public int size() { - return array.length; - } - - @Override - public boolean hasNext() { - return cursor < array.length; - } - @Override - public ValueRef next() { - return array[cursor++]; - } - @Override - public void skip() { - cursor++; - } - @Override - public void skipAll() { - while(hasNext()) { - skip(); - } - } - - public Value[] toValueArray() { - return Arrays.copyOf(array, array.length); - } - - @Override - public Iterator iterator() { - return new Iterator() { - int cursor = 0; - @Override - public boolean hasNext() { - return cursor < array.length; - } - @Override - public ValueRef next() { - return array[cursor++]; - } - @Override - public void remove() { - throw new UnsupportedOperationException("remove"); - } - }; - } -} diff --git a/msgpack-core/src/main/java/org/msgpack/value/impl/BinaryValueImpl.java b/msgpack-core/src/main/java/org/msgpack/value/impl/BinaryValueImpl.java deleted file mode 100644 index 8b992f023..000000000 --- a/msgpack-core/src/main/java/org/msgpack/value/impl/BinaryValueImpl.java +++ /dev/null @@ -1,33 +0,0 @@ -package org.msgpack.value.impl; - -import org.msgpack.value.ValueType; -import org.msgpack.value.BinaryValue; -import org.msgpack.value.ValueVisitor; - -import java.nio.ByteBuffer; - -/** -* Created on 5/30/14. -*/ -public class BinaryValueImpl extends RawValueImpl implements BinaryValue { - public BinaryValueImpl(ByteBuffer byteBuffer) { - super(byteBuffer); - } - - @Override - public ValueType getValueType() { - return ValueType.BINARY; - } - @Override - public void accept(ValueVisitor visitor) { - visitor.visitBinary(this); - } - - @Override - public BinaryValue toValue() { - return this; - } - - - -} diff --git a/msgpack-core/src/main/java/org/msgpack/value/impl/BooleanValueImpl.java b/msgpack-core/src/main/java/org/msgpack/value/impl/BooleanValueImpl.java deleted file mode 100644 index 4d1cbc311..000000000 --- a/msgpack-core/src/main/java/org/msgpack/value/impl/BooleanValueImpl.java +++ /dev/null @@ -1,63 +0,0 @@ -package org.msgpack.value.impl; - -import org.msgpack.core.MessagePacker; -import org.msgpack.value.ValueType; -import org.msgpack.value.BooleanValue; -import org.msgpack.value.ValueVisitor; - -import java.io.IOException; - -/** -* Created on 5/30/14. -*/ -public class BooleanValueImpl extends AbstractValue implements BooleanValue { - - public static BooleanValue TRUE = new BooleanValueImpl(true); - public static BooleanValue FALSE = new BooleanValueImpl(false); - - private final boolean value; - - public BooleanValueImpl(boolean value) { - this.value = value; - } - - @Override - public ValueType getValueType() { - return ValueType.BOOLEAN; - } - @Override - public boolean equals(Object o) { - if (!(o instanceof BooleanValue)) - return false; - return value == ((BooleanValue) o).toBoolean(); - } - - @Override - public int hashCode() { - return 0; - } - - public String toString() { - return Boolean.toString(value); - } - - @Override - public boolean toBoolean() { - return value; - } - - @Override - public void writeTo(MessagePacker packer) throws IOException { - packer.packBoolean(value); - } - @Override - public void accept(ValueVisitor visitor) { - visitor.visitBoolean(value); - } - @Override - public BooleanValue toValue() { - return this; - } - - -} diff --git a/msgpack-core/src/main/java/org/msgpack/value/impl/CursorImpl.java b/msgpack-core/src/main/java/org/msgpack/value/impl/CursorImpl.java deleted file mode 100644 index 488ecae78..000000000 --- a/msgpack-core/src/main/java/org/msgpack/value/impl/CursorImpl.java +++ /dev/null @@ -1,134 +0,0 @@ -package org.msgpack.value.impl; - -import org.msgpack.core.*; -import org.msgpack.value.*; -import org.msgpack.value.holder.ValueHolder; -import java.io.IOException; - -/** - * Cursor implementation - */ -public class CursorImpl implements Cursor { - - private final MessageUnpacker unpacker; - private MessageFormat currentFormat; - private ValueHolder valueHolder; - - public CursorImpl(MessageUnpacker unpacker) { - this.unpacker = unpacker; - this.currentFormat = MessageFormat.NIL; - this.valueHolder = new ValueHolder(); - } - - @Override - public void remove() { - throw new UnsupportedOperationException("remove"); - } - - - @Override - public boolean hasNext() { - try { - return unpacker.hasNext(); - } - catch(IOException e) { - throw new MessageFormatException(e); - } - } - - @Override - public void skip() { - try { - unpacker.skipValue(); - } - catch(IOException e){ - throw new MessageFormatException(e); - } - } - @Override - public long getReadBytes() { - return unpacker.getTotalReadBytes(); - } - - - private final void readNext() { - try { - currentFormat = unpacker.unpackValue(valueHolder); - } - catch(IOException e) { - throw new MessageFormatException(e); - } - } - - @Override - public Value next() { - readNext(); - return valueHolder.get(); - } - - @Override - public ValueRef nextRef() { - readNext(); - return valueHolder.getRef(); - } - - private ValueType getValueType() { - return currentFormat.getValueType(); - } - - - @Override - public Out apply(Function f) { - return null; - } - - @Override - public boolean isNilValue() { - return getValueType().isNilType(); - } - @Override - public boolean isBooleanValue() { - return getValueType().isBooleanType(); - } - @Override - public boolean isNumberValue() { - return getValueType().isNumberType(); - } - @Override - public boolean isIntegerValue() { - return getValueType().isIntegerType(); - } - @Override - public boolean isFloatValue() { - return getValueType().isFloatType(); - } - @Override - public boolean isBinaryValue() { - return getValueType().isBinaryType(); - } - @Override - public boolean isStringValue() { - return getValueType().isStringType(); - } - @Override - public boolean isRawValue() { - return getValueType().isRawType(); - } - @Override - public boolean isArrayValue() { - return getValueType().isArrayType(); - } - @Override - public boolean isMapValue() { - return getValueType().isMapType(); - } - @Override - public boolean isExtendedValue() { - return getValueType().isExtendedType(); - } - - @Override - public void close() throws IOException { - unpacker.close(); - } -} diff --git a/msgpack-core/src/main/java/org/msgpack/value/impl/DoubleValueImpl.java b/msgpack-core/src/main/java/org/msgpack/value/impl/DoubleValueImpl.java deleted file mode 100644 index e8382a344..000000000 --- a/msgpack-core/src/main/java/org/msgpack/value/impl/DoubleValueImpl.java +++ /dev/null @@ -1,152 +0,0 @@ -package org.msgpack.value.impl; - -import org.msgpack.core.MessageFloatOverflowException; -import org.msgpack.core.MessageOverflowException; -import org.msgpack.core.MessagePacker; -import org.msgpack.value.*; - -import java.io.IOException; -import java.math.BigDecimal; -import java.math.BigInteger; - -/** -* Created on 5/30/14. -*/ -public class DoubleValueImpl extends AbstractValue implements FloatValue { - private final double value; - - public DoubleValueImpl(double value) { - this.value = value; - } - - @Override - public ValueType getValueType() { - return ValueType.FLOAT; - } - - @Override - public boolean isValidByte() { - return ((double) ((byte) value)) == value; - } - @Override - public boolean isValidShort() { - return ((double) ((short) value)) == value; - } - @Override - public boolean isValidInt() { - return ((double) ((int) value)) == value; - } - @Override - public boolean isValidLong() { - long l = (long) value; - return ((double) l) == value && l != Long.MAX_VALUE; - } - @Override - public boolean isWhole() { - long l = (long) value; - return ((double) l == value) || l == Long.MAX_VALUE && value < Double.POSITIVE_INFINITY || l == Long.MIN_VALUE && value > Double.NEGATIVE_INFINITY; - } - @Override - public byte toByte() { - return (byte) value; - } - - @Override - public short toShort() { - return (short) value; - } - - @Override - public int toInt() { - return (int) value; - } - - @Override - public long toLong() { - return (long) value; - } - - @Override - public BigInteger toBigInteger() { - return new BigDecimal(value).toBigInteger(); - } - - @Override - public float toFloat() { - return (float) value; - } - - @Override - public double toDouble() { - return value; - } - @Override - public byte asByte() throws MessageOverflowException { - if(!isValidByte()) - throw new MessageFloatOverflowException(value); - return (byte) value; - } - @Override - public short asShort() throws MessageOverflowException { - if(!isValidShort()) - throw new MessageFloatOverflowException(value); - return (short) value; - } - @Override - public int asInt() throws MessageOverflowException { - if(!isValidInt()) - throw new MessageFloatOverflowException(value); - return (int) value; - } - @Override - public long asLong() throws MessageOverflowException { - if(!isValidLong()) - throw new MessageFloatOverflowException(value); - return (long) value; - } - @Override - public BigInteger asBigInteger() throws MessageOverflowException { - if(!isWhole()) - throw new MessageFloatOverflowException(value); - return new BigDecimal(value).toBigInteger(); - } - - @Override - public boolean equals(Object o) { - if (o == this) { - return true; - } - if (!(o instanceof Value)) { - return false; - } - Value v = (Value) o; - if (!v.isFloat()) { - return false; - } - return value == v.asFloat().toDouble(); - } - - @Override - public FloatValue toValue() { - return ValueFactory.newDouble(value); - } - @Override - public void writeTo(MessagePacker pk) throws IOException { - pk.packDouble(value); - } - @Override - public void accept(ValueVisitor visitor) { - visitor.visitFloat(this); - } - - @Override - public int hashCode() { - long v = Double.doubleToLongBits(value); - return (int) (v ^ (v >>> 32)); - } - - @Override - public String toString() { - return Double.toString(value); - } -} diff --git a/msgpack-core/src/main/java/org/msgpack/value/impl/ExtendedValueImpl.java b/msgpack-core/src/main/java/org/msgpack/value/impl/ExtendedValueImpl.java deleted file mode 100644 index 1591b6308..000000000 --- a/msgpack-core/src/main/java/org/msgpack/value/impl/ExtendedValueImpl.java +++ /dev/null @@ -1,50 +0,0 @@ -package org.msgpack.value.impl; - -import org.msgpack.core.MessagePacker; -import org.msgpack.value.ValueType; -import org.msgpack.value.ExtendedValue; -import org.msgpack.value.ValueVisitor; - -import java.io.IOException; -import java.nio.ByteBuffer; - -/** - * Extended value implementation - */ -public class ExtendedValueImpl extends RawValueImpl implements ExtendedValue { - - private final int type; - - - public ExtendedValueImpl(int type, ByteBuffer data) { - super(data); - this.type = type; - } - - @Override - public ValueType getValueType() { - return ValueType.EXTENDED; - } - @Override - public void writeTo(MessagePacker packer) throws IOException { - packer.packExtendedTypeHeader(type, byteBuffer.remaining()); - packer.writePayload(byteBuffer); - } - - @Override - public void accept(ValueVisitor visitor) { - visitor.visitExtended(this); - } - - @Override - public ExtendedValue toValue() { - return this; - } - - @Override - public int getExtType() { - return type; - } - - -} diff --git a/msgpack-core/src/main/java/org/msgpack/value/impl/FloatValueImpl.java b/msgpack-core/src/main/java/org/msgpack/value/impl/FloatValueImpl.java deleted file mode 100644 index 644b81aaa..000000000 --- a/msgpack-core/src/main/java/org/msgpack/value/impl/FloatValueImpl.java +++ /dev/null @@ -1,159 +0,0 @@ -package org.msgpack.value.impl; - -import org.msgpack.core.MessageFloatOverflowException; -import org.msgpack.core.MessageOverflowException; -import org.msgpack.core.MessagePacker; -import org.msgpack.value.*; - -import java.io.IOException; -import java.math.BigDecimal; -import java.math.BigInteger; - -/** -* Created on 5/30/14. -*/ -public class FloatValueImpl extends AbstractValue implements FloatValue { - private final float value; - - public FloatValueImpl(float value) { - this.value = value; - } - - @Override - public ValueType getValueType() { - return ValueType.FLOAT; - } - - @Override - public boolean isValidByte() { - return (float) ((byte) value) == value; - } - @Override - public boolean isValidShort() { - return (float) ((short) value) == value; - } - @Override - public boolean isValidInt() { - int i = (int) value; - return ((float) i) == value && i != Integer.MAX_VALUE; - } - @Override - public boolean isValidLong() { - long l = (long) value; - return ((float) l) == value && l != Long.MAX_VALUE; - } - - @Override - public boolean isWhole() { - long l = (long) value; - return ((float) l) == value || l == Long.MAX_VALUE || value < Float.POSITIVE_INFINITY || l == Long.MIN_VALUE && value > Float.NEGATIVE_INFINITY; - } - - @Override - public byte toByte() { - return (byte) value; - } - - @Override - public short toShort() { - return (short) value; - } - - @Override - public int toInt() { - return (int) value; - } - - @Override - public long toLong() { - return (long) value; - } - - @Override - public BigInteger toBigInteger() { - return new BigDecimal((double) value).toBigInteger(); - } - - @Override - public float toFloat() { - return value; - } - - @Override - public double toDouble() { - return (double) value; - } - @Override - public byte asByte() throws MessageOverflowException { - if (!isValidByte()) { - throw new MessageFloatOverflowException(value); - } - return (byte) value; - } - @Override - public short asShort() throws MessageOverflowException { - if(!isValidShort()) - throw new MessageFloatOverflowException(value); - return (short) value; - } - @Override - public int asInt() throws MessageOverflowException { - if(!isValidInt()) - throw new MessageFloatOverflowException(value); - return (int) value; - } - - @Override - public long asLong() throws MessageOverflowException { - if(!isValidLong()) - throw new MessageFloatOverflowException(value); - return (long) value; - } - - @Override - public BigInteger asBigInteger() throws MessageOverflowException { - if(!isWhole()) - throw new MessageFloatOverflowException(value); - - return BigDecimal.valueOf(value).toBigInteger(); - } - - @Override - public boolean equals(Object o) { - if (o == this) { - return true; - } - if (!(o instanceof Value)) { - return false; - } - Value v = (Value) o; - if (!v.isFloat()) { - return false; - } - return (double) value == v.asFloat().toDouble(); - } - - @Override - public void writeTo(MessagePacker pk) throws IOException { - pk.packFloat(value); - } - @Override - public void accept(ValueVisitor visitor) { - visitor.visitFloat(this); - } - @Override - public FloatValue toValue() { - return this; - } - - @Override - public int hashCode() { - long v = Double.doubleToLongBits((double) value); - return (int) (v ^ (v >>> 32)); - } - - @Override - public String toString() { - return Float.toString(value); - } -} diff --git a/msgpack-core/src/main/java/org/msgpack/value/impl/ImmutableArrayValueImpl.java b/msgpack-core/src/main/java/org/msgpack/value/impl/ImmutableArrayValueImpl.java new file mode 100644 index 000000000..39564711d --- /dev/null +++ b/msgpack-core/src/main/java/org/msgpack/value/impl/ImmutableArrayValueImpl.java @@ -0,0 +1,207 @@ +// +// MessagePack for Java +// +// 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.msgpack.value.impl; + +import org.msgpack.core.MessagePacker; +import org.msgpack.value.*; + +import java.util.List; +import java.util.AbstractList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.NoSuchElementException; +import java.io.IOException; + + +/** + * {@code ImmutableArrayValueImpl} Implements {@code ImmutableArrayValue} using a {@code Value[]} field. + * + * @see org.msgpack.value.IntegerValue + */ +public class ImmutableArrayValueImpl extends AbstractImmutableValue implements ImmutableArrayValue { + private static ImmutableArrayValueImpl EMPTY = new ImmutableArrayValueImpl(new Value[0]); + + public static ImmutableArrayValue empty() { + return EMPTY; + } + + private final Value[] array; + + public ImmutableArrayValueImpl(Value[] array) { + this.array = array; + } + + @Override + public ValueType getValueType() { + return ValueType.ARRAY; + } + + @Override + public ImmutableArrayValue immutableValue() { + return this; + } + + @Override + public ImmutableArrayValue asArrayValue() { + return this; + } + + @Override + public int size() { + return array.length; + } + + @Override + public Value get(int index) { + return array[index]; + } + + @Override + public Value getOrNilValue(int index) { + if (index < array.length && index >= 0) { + return array[index]; + } + return ImmutableNilValueImpl.get(); + } + + @Override + public Iterator iterator() { + return new Ite(array); + } + + @Override + public List list() { + return new ImmutableArrayValueList(array); + } + + @Override + public void writeTo(MessagePacker pk) throws IOException { + pk.packArrayHeader(array.length); + for(int i = 0; i < array.length; i++) { + array[i].writeTo(pk); + } + } + + @Override + public boolean equals(Object o) { + if(o == this) { + return true; + } + if(!(o instanceof Value)) { + return false; + } + Value v = (Value) o; + + if (v instanceof ImmutableArrayValueImpl) { + ImmutableArrayValueImpl oa = (ImmutableArrayValueImpl) v; + return Arrays.equals(array, oa.array); + } else { + if(!v.isArrayValue()) { + return false; + } + ArrayValue av = v.asArrayValue(); + if (size() != av.size()) { + return false; + } + Iterator oi = av.iterator(); + int i = 0; + while (i < array.length) { + if (!oi.hasNext() || !array[i].equals(oi.next())) { + return false; + } + i++; + } + return true; + } + } + + @Override + public int hashCode() { + int h = 1; + for(int i = 0; i < array.length; i++) { + Value obj = array[i]; + h = 31 * h + obj.hashCode(); + } + return h; + } + + @Override + public String toString() { + return toString(new StringBuilder()).toString(); + } + + private StringBuilder toString(StringBuilder sb) { + if(array.length == 0) { + return sb.append("[]"); + } + sb.append("["); + sb.append(array[0]); + for(int i = 1; i < array.length; i++) { + sb.append(","); + sb.append(array[i].toString()); + } + sb.append("]"); + return sb; + } + + private static class ImmutableArrayValueList extends AbstractList { + private final Value[] array; + + public ImmutableArrayValueList(Value[] array) { + this.array = array; + } + + @Override + public Value get(int index) { + return array[index]; + } + + @Override + public int size() { + return array.length; + } + } + + private static class Ite implements Iterator { + private final Value[] array; + private int index; + + public Ite(Value[] array) { + this.array = array; + this.index = 0; + } + + @Override + public boolean hasNext() { + return index != array.length; + } + + @Override + public Value next() { + int i = index; + if (i >= array.length) { + throw new NoSuchElementException(); + } + index = i + 1; + return array[i]; + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + } +} diff --git a/msgpack-core/src/main/java/org/msgpack/value/impl/BigIntegerValueImpl.java b/msgpack-core/src/main/java/org/msgpack/value/impl/ImmutableBigIntegerValueImpl.java similarity index 62% rename from msgpack-core/src/main/java/org/msgpack/value/impl/BigIntegerValueImpl.java rename to msgpack-core/src/main/java/org/msgpack/value/impl/ImmutableBigIntegerValueImpl.java index 85af4a176..1e5ac8759 100644 --- a/msgpack-core/src/main/java/org/msgpack/value/impl/BigIntegerValueImpl.java +++ b/msgpack-core/src/main/java/org/msgpack/value/impl/ImmutableBigIntegerValueImpl.java @@ -1,26 +1,38 @@ +// +// MessagePack for Java +// +// 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.msgpack.value.impl; -import org.msgpack.core.MessageIntegerOverflowException; import org.msgpack.core.MessagePacker; -import org.msgpack.value.ValueType; -import org.msgpack.value.IntegerValue; -import org.msgpack.value.Value; -import org.msgpack.value.ValueVisitor; +import org.msgpack.core.MessageIntegerOverflowException; +import org.msgpack.value.*; import java.io.IOException; import java.math.BigInteger; -import static org.msgpack.core.Preconditions.checkNotNull; /** -* Created on 5/30/14. -*/ -public class BigIntegerValueImpl extends AbstractValue implements IntegerValue { - + * {@code ImmutableBigIntegerValueImpl} Implements {@code ImmutableBigIntegerValue} using a {@code BigInteger} field. + * + * @see org.msgpack.value.IntegerValue + */ +public class ImmutableBigIntegerValueImpl extends AbstractImmutableValue implements ImmutableIntegerValue { private final BigInteger value; - public BigIntegerValueImpl(BigInteger value) { - this.value = checkNotNull(value, "BigInteger value is null"); + public ImmutableBigIntegerValueImpl(BigInteger value) { + this.value = value; } private static final BigInteger BYTE_MIN = BigInteger.valueOf((long) Byte.MIN_VALUE); @@ -38,113 +50,116 @@ public ValueType getValueType() { } @Override - public byte toByte() { + public ImmutableIntegerValue immutableValue() { + return this; + } + + @Override + public ImmutableNumberValue asNumberValue() { + return this; + } + + @Override + public ImmutableIntegerValue asIntegerValue() { + return this; + } + + @Override + public byte castAsByte() { return value.byteValue(); } @Override - public short toShort() { + public short castAsShort() { return value.shortValue(); } @Override - public int toInt() { + public int castAsInt() { return value.intValue(); } @Override - public long toLong() { + public long castAsLong() { return value.longValue(); } @Override - public BigInteger toBigInteger() { + public BigInteger castAsBigInteger() { return value; } @Override - public float toFloat() { + public float castAsFloat() { return value.floatValue(); } @Override - public double toDouble() { + public double castAsDouble() { return value.doubleValue(); } @Override - public byte asByte() throws MessageIntegerOverflowException { - if (!isValidByte()) { + public boolean isInByteRange() { + return 0 <= value.compareTo(BYTE_MIN) && value.compareTo(BYTE_MAX) <= 0; + } + + @Override + public boolean isInShortRange() { + return 0 <= value.compareTo(SHORT_MIN) && value.compareTo(SHORT_MAX) <= 0; + } + + @Override + public boolean isInIntRange() { + return 0 <= value.compareTo(INT_MIN) && value.compareTo(INT_MAX) <= 0; + } + + @Override + public boolean isInLongRange() { + return 0 <= value.compareTo(LONG_MIN) && value.compareTo(LONG_MAX) <= 0; + } + + @Override + public byte getByte() { + if (!isInByteRange()) { throw new MessageIntegerOverflowException(value); } return value.byteValue(); } @Override - public short asShort() throws MessageIntegerOverflowException { - if (!isValidShort()) { + public short getShort() { + if (!isInShortRange()) { throw new MessageIntegerOverflowException(value); } return value.shortValue(); } @Override - public int asInt() throws MessageIntegerOverflowException { - if (!isValidInt()) { + public int getInt() { + if (!isInIntRange()) { throw new MessageIntegerOverflowException(value); } return value.intValue(); } @Override - public long asLong() throws MessageIntegerOverflowException { - if (!isValidLong()) { + public long getLong() { + if (!isInLongRange()) { throw new MessageIntegerOverflowException(value); } return value.longValue(); } @Override - public BigInteger asBigInteger() throws MessageIntegerOverflowException { + public BigInteger getBigInteger() { return value; } - @Override - public boolean isValidByte() { - return 0 <= value.compareTo(BYTE_MIN) && value.compareTo(BYTE_MAX) <= 0; - } - - @Override - public boolean isValidShort() { - return 0 <= value.compareTo(SHORT_MIN) && value.compareTo(SHORT_MAX) <= 0; - } - - @Override - public boolean isValidInt() { - return 0 <= value.compareTo(INT_MIN) && value.compareTo(INT_MAX) <= 0; - } - - @Override - public boolean isValidLong() { - return 0 <= value.compareTo(LONG_MIN) && value.compareTo(LONG_MAX) <= 0; - } - @Override - public boolean isWhole() { - return true; - } - @Override public void writeTo(MessagePacker pk) throws IOException { pk.packBigInteger(value); } - @Override - public void accept(ValueVisitor visitor) { - visitor.visitInteger(this); - } - @Override - public IntegerValue toValue() { - return this; - } @Override public boolean equals(Object o) { @@ -155,11 +170,12 @@ public boolean equals(Object o) { return false; } Value v = (Value) o; - if (!v.isInteger()) { + + if (!v.isIntegerValue()) { return false; } - IntegerValue iv = v.asInteger(); - return value.equals(iv.toBigInteger()); + IntegerValue iv = v.asIntegerValue(); + return value.equals(iv.castAsBigInteger()); } @Override diff --git a/msgpack-core/src/main/java/org/msgpack/value/impl/ImmutableBinaryValueImpl.java b/msgpack-core/src/main/java/org/msgpack/value/impl/ImmutableBinaryValueImpl.java new file mode 100644 index 000000000..da794e001 --- /dev/null +++ b/msgpack-core/src/main/java/org/msgpack/value/impl/ImmutableBinaryValueImpl.java @@ -0,0 +1,85 @@ +// +// MessagePack for Java +// +// 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.msgpack.value.impl; + +import org.msgpack.core.MessagePacker; +import org.msgpack.value.ImmutableBinaryValue; +import org.msgpack.value.Value; +import org.msgpack.value.ValueType; + +import java.io.IOException; +import java.util.Arrays; + + +/** + * {@code ImmutableBinaryValueImpl} Implements {@code ImmutableBinaryValue} using a {@code byte[]} field. + * This implementation caches result of {@code stringValue()} and {@code getString()} using a private {@code String} field. + * + * @see org.msgpack.value.StringValue + */ +public class ImmutableBinaryValueImpl extends AbstractImmutableRawValue implements ImmutableBinaryValue { + public ImmutableBinaryValueImpl(byte[] data) { + super(data); + } + + @Override + public ValueType getValueType() { + return ValueType.BINARY; + } + + @Override + public ImmutableBinaryValue immutableValue() { + return this; + } + + @Override + public ImmutableBinaryValue asBinaryValue() { + return this; + } + + @Override + public void writeTo(MessagePacker pk) throws IOException { + pk.packBinaryHeader(data.length); + pk.writePayload(data); + } + + @Override + public boolean equals(Object o) { + if(this == o) { + return true; + } + if(!(o instanceof Value)) { + return false; + } + Value v = (Value) o; + if(!v.isBinaryValue()) { + return false; + } + + if(v instanceof ImmutableBinaryValueImpl) { + ImmutableBinaryValueImpl bv = (ImmutableBinaryValueImpl) v; + return Arrays.equals(data, bv.data); + } + else { + return Arrays.equals(data, v.asBinaryValue().getByteArray()); + } + } + + @Override + public int hashCode() { + return Arrays.hashCode(data); + } +} diff --git a/msgpack-core/src/main/java/org/msgpack/value/impl/ImmutableBooleanValueImpl.java b/msgpack-core/src/main/java/org/msgpack/value/impl/ImmutableBooleanValueImpl.java new file mode 100644 index 000000000..aee366788 --- /dev/null +++ b/msgpack-core/src/main/java/org/msgpack/value/impl/ImmutableBooleanValueImpl.java @@ -0,0 +1,93 @@ +// +// MessagePack for Java +// +// 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.msgpack.value.impl; + +import org.msgpack.core.MessagePacker; +import org.msgpack.value.ImmutableBooleanValue; +import org.msgpack.value.Value; +import org.msgpack.value.ValueType; + +import java.io.IOException; + + +/** + * {@code ImmutableBooleanValueImpl} Implements {@code ImmutableBooleanValue} using a {@code boolean} field. + *

+ * This class is a singleton. {@code ImmutableBooleanValueImpl.trueInstance()} and {@code ImmutableBooleanValueImpl.falseInstance()} are the only instances of this class. + * + * @see org.msgpack.value.BooleanValue + */ +public class ImmutableBooleanValueImpl extends AbstractImmutableValue implements ImmutableBooleanValue { + public static ImmutableBooleanValue TRUE = new ImmutableBooleanValueImpl(true); + public static ImmutableBooleanValue FALSE = new ImmutableBooleanValueImpl(false); + + private final boolean value; + + private ImmutableBooleanValueImpl(boolean value) { + this.value = value; + } + + @Override + public ValueType getValueType() { + return ValueType.BOOLEAN; + } + + @Override + public ImmutableBooleanValue immutableValue() { + return this; + } + + @Override + public boolean getBoolean() { + return value; + } + + @Override + public void writeTo(MessagePacker packer) throws IOException { + packer.packBoolean(value); + } + + @Override + public boolean equals(Object o) { + if(o == this) { + return true; + } + if(!(o instanceof Value)) { + return false; + } + Value v = (Value) o; + + if(!v.isBooleanValue()) { + return false; + } + return value == v.asBooleanValue().getBoolean(); + } + + @Override + public int hashCode() { + if(value) { + return 1231; + } + else { + return 1237; + } + } + + @Override + public String toString() { + return Boolean.toString(value); + } +} diff --git a/msgpack-core/src/main/java/org/msgpack/value/impl/ImmutableDoubleValueImpl.java b/msgpack-core/src/main/java/org/msgpack/value/impl/ImmutableDoubleValueImpl.java new file mode 100644 index 000000000..db7a262b4 --- /dev/null +++ b/msgpack-core/src/main/java/org/msgpack/value/impl/ImmutableDoubleValueImpl.java @@ -0,0 +1,116 @@ +// +// MessagePack for Java +// +// 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.msgpack.value.impl; + +import org.msgpack.core.MessagePacker; +import org.msgpack.value.ImmutableFloatValue; +import org.msgpack.value.Value; +import org.msgpack.value.ValueType; + +import java.io.IOException; +import java.math.BigDecimal; +import java.math.BigInteger; + + +/** + * {@code ImmutableDoubleValueImpl} Implements {@code ImmutableFloatValue} using a {@code double} field. + * + * @see org.msgpack.value.FloatValue + */ +public class ImmutableDoubleValueImpl extends AbstractImmutableValue implements ImmutableFloatValue { + private final double value; + + public ImmutableDoubleValueImpl(double value) { + this.value = value; + } + + @Override + public ValueType getValueType() { + return ValueType.FLOAT; + } + + @Override + public ImmutableDoubleValueImpl immutableValue() { + return this; + } + + @Override + public byte castAsByte() { + return (byte) value; + } + + @Override + public short castAsShort() { + return (short) value; + } + + @Override + public int castAsInt() { + return (int) value; + } + + @Override + public long castAsLong() { + return (long) value; + } + + @Override + public BigInteger castAsBigInteger() { + return new BigDecimal(value).toBigInteger(); + } + + @Override + public float castAsFloat() { + return (float) value; + } + + @Override + public double castAsDouble() { + return value; + } + + @Override + public void writeTo(MessagePacker pk) throws IOException { + pk.packDouble(value); + } + + @Override + public boolean equals(Object o) { + if(o == this) { + return true; + } + if(!(o instanceof Value)) { + return false; + } + Value v = (Value) o; + + if(!v.isFloatValue()) { + return false; + } + return value == v.asFloatValue().castAsDouble(); + } + + @Override + public int hashCode() { + long v = Double.doubleToLongBits(value); + return (int) (v ^ (v >>> 32)); + } + + @Override + public String toString() { + return Double.toString(value); + } +} diff --git a/msgpack-core/src/main/java/org/msgpack/value/impl/ImmutableExtensionValueImpl.java b/msgpack-core/src/main/java/org/msgpack/value/impl/ImmutableExtensionValueImpl.java new file mode 100644 index 000000000..fdd22b7f0 --- /dev/null +++ b/msgpack-core/src/main/java/org/msgpack/value/impl/ImmutableExtensionValueImpl.java @@ -0,0 +1,108 @@ +// +// MessagePack for Java +// +// 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.msgpack.value.impl; + +import org.msgpack.core.MessagePacker; +import org.msgpack.value.*; + +import java.util.Arrays; +import java.io.IOException; + + +/** + * {@code ImmutableExtensionValueImpl} Implements {@code ImmutableExtensionValue} using a {@code byte} and a {@code byte[]} fields. + * + * @see ExtensionValue + */ +public class ImmutableExtensionValueImpl extends AbstractImmutableValue implements ImmutableExtensionValue { + private final byte type; + private final byte[] data; + + public ImmutableExtensionValueImpl(byte type, byte[] data) { + this.type = type; + this.data = data; + } + + @Override + public ValueType getValueType() { + return ValueType.EXTENSION; + } + + @Override + public ImmutableExtensionValue immutableValue() { + return this; + } + + @Override + public ImmutableExtensionValue asExtensionValue() { + return this; + } + + @Override + public byte getType() { + return type; + } + + @Override + public byte[] getData() { + return data; + } + + @Override + public void writeTo(MessagePacker packer) throws IOException { + packer.packExtensionTypeHeader(type, data.length); + packer.writePayload(data); + } + + @Override + public boolean equals(Object o) { + if (o == this) { + return true; + } + if (!(o instanceof Value)) { + return false; + } + Value v = (Value) o; + + if (!v.isExtensionValue()) { + return false; + } + ExtensionValue ev = v.asExtensionValue(); + return type == ev.getType() && Arrays.equals(data, ev.getData()); + } + + @Override + public int hashCode() { + int hash = 31 + type; + for (byte e : data) { + hash = 31 * hash + e; + } + return hash; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append('('); + sb.append(Byte.toString(type)); + sb.append(",0x"); + for (byte e : data) { + sb.append(Integer.toString((int) e, 16)); + } + sb.append(")"); + return sb.toString(); + } +} diff --git a/msgpack-core/src/main/java/org/msgpack/value/impl/LongValueImpl.java b/msgpack-core/src/main/java/org/msgpack/value/impl/ImmutableLongValueImpl.java similarity index 57% rename from msgpack-core/src/main/java/org/msgpack/value/impl/LongValueImpl.java rename to msgpack-core/src/main/java/org/msgpack/value/impl/ImmutableLongValueImpl.java index 57346fe11..adad02764 100644 --- a/msgpack-core/src/main/java/org/msgpack/value/impl/LongValueImpl.java +++ b/msgpack-core/src/main/java/org/msgpack/value/impl/ImmutableLongValueImpl.java @@ -1,23 +1,37 @@ +// +// MessagePack for Java +// +// 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.msgpack.value.impl; -import org.msgpack.core.MessageIntegerOverflowException; import org.msgpack.core.MessagePacker; -import org.msgpack.value.ValueType; -import org.msgpack.value.IntegerValue; -import org.msgpack.value.Value; -import org.msgpack.value.ValueVisitor; +import org.msgpack.core.MessageIntegerOverflowException; +import org.msgpack.value.*; import java.io.IOException; import java.math.BigInteger; -/** -* Created on 5/30/14. -*/ -public class LongValueImpl extends AbstractValue implements IntegerValue { +/** + * {@code ImmutableLongValueImpl} Implements {@code ImmutableIntegerValue} using a {@code long} field. + * + * @see org.msgpack.value.IntegerValue + */ +public class ImmutableLongValueImpl extends AbstractImmutableValue implements ImmutableIntegerValue { private final long value; - public LongValueImpl(long value) { + public ImmutableLongValueImpl(long value) { this.value = value; } @@ -34,115 +48,113 @@ public ValueType getValueType() { } @Override - public IntegerValue asInteger() { + public ImmutableIntegerValue immutableValue() { return this; } @Override - public byte toByte() { + public ImmutableNumberValue asNumberValue() { + return this; + } + + @Override + public ImmutableIntegerValue asIntegerValue() { + return this; + } + + @Override + public byte castAsByte() { return (byte) value; } @Override - public short toShort() { + public short castAsShort() { return (short) value; } @Override - public int toInt() { + public int castAsInt() { return (int) value; } @Override - public long toLong() { + public long castAsLong() { return value; } @Override - public BigInteger toBigInteger() { + public BigInteger castAsBigInteger() { return BigInteger.valueOf(value); } @Override - public float toFloat() { + public float castAsFloat() { return (float) value; } @Override - public double toDouble() { + public double castAsDouble() { return (double) value; } @Override - public byte asByte() throws MessageIntegerOverflowException { - if (!isValidByte()) { - throw new MessageIntegerOverflowException(value); - } - return (byte) value; + public boolean isInByteRange() { + return BYTE_MIN <= value && value <= BYTE_MAX; } @Override - public short asShort() throws MessageIntegerOverflowException { - if (!isValidShort()) { - throw new MessageIntegerOverflowException(value); - } - return (short) value; + public boolean isInShortRange() { + return SHORT_MIN <= value && value <= SHORT_MAX; } @Override - public int asInt() throws MessageIntegerOverflowException { - if (!isValidInt()) { - throw new MessageIntegerOverflowException(value); - } - return (int) value; + public boolean isInIntRange() { + return INT_MIN <= value && value <= INT_MAX; } @Override - public long asLong() throws MessageIntegerOverflowException { - return value; + public boolean isInLongRange() { + return true; } @Override - public BigInteger asBigInteger() throws MessageIntegerOverflowException { - return BigInteger.valueOf(value); + public byte getByte() { + if (!isInByteRange()) { + throw new MessageIntegerOverflowException(value); + } + return (byte) value; } @Override - public boolean isValidByte() { - return BYTE_MIN <= value && value <= BYTE_MAX; + public short getShort() { + if (!isInByteRange()) { + throw new MessageIntegerOverflowException(value); + } + return (short) value; } @Override - public boolean isValidShort() { - return SHORT_MIN <= value && value <= SHORT_MAX; + public int getInt() { + if (!isInIntRange()) { + throw new MessageIntegerOverflowException(value); + } + return (int) value; } @Override - public boolean isValidInt() { - return INT_MIN <= value && value <= INT_MAX; + public long getLong() { + return value; } @Override - public boolean isValidLong() { - return true; - } - @Override - public boolean isWhole() { - return true; + public BigInteger getBigInteger() { + return BigInteger.valueOf((long) value); } @Override public void writeTo(MessagePacker pk) throws IOException { pk.packLong(value); } - @Override - public void accept(ValueVisitor visitor) { - visitor.visitInteger(this); - } - @Override - public IntegerValue toValue() { - return this; - } @Override public boolean equals(Object o) { @@ -153,14 +165,15 @@ public boolean equals(Object o) { return false; } Value v = (Value) o; - if (!v.isInteger()) { + if (!v.isIntegerValue()) { return false; } - IntegerValue iv = v.asInteger(); - if (!iv.isValidLong()) { + + IntegerValue iv = v.asIntegerValue(); + if (!iv.isInLongRange()) { return false; } - return value == iv.toLong(); + return value == iv.castAsLong(); } @Override diff --git a/msgpack-core/src/main/java/org/msgpack/value/impl/ImmutableMapValueImpl.java b/msgpack-core/src/main/java/org/msgpack/value/impl/ImmutableMapValueImpl.java new file mode 100644 index 000000000..bb477919e --- /dev/null +++ b/msgpack-core/src/main/java/org/msgpack/value/impl/ImmutableMapValueImpl.java @@ -0,0 +1,283 @@ +// +// MessagePack for Java +// +// 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.msgpack.value.impl; + +import org.msgpack.core.MessagePacker; +import org.msgpack.value.*; + +import java.io.IOException; +import java.util.Map; +import java.util.Set; +import java.util.Collection; +import java.util.AbstractMap; +import java.util.AbstractSet; +import java.util.AbstractCollection; +import java.util.Iterator; +import java.util.Arrays; +import java.util.NoSuchElementException; + + +/** + * {@code ImmutableMapValueImpl} Implements {@code ImmutableMapValue} using a {@code Value[]} field. + * + * @see org.msgpack.value.MapValue + */ +public class ImmutableMapValueImpl extends AbstractImmutableValue implements ImmutableMapValue { + private static ImmutableMapValueImpl EMPTY = new ImmutableMapValueImpl(new Value[0]); + + public static ImmutableMapValue empty() { + return EMPTY; + } + + private final Value[] kvs; + + public ImmutableMapValueImpl(Value[] kvs) { + this.kvs = kvs; + } + + @Override + public ValueType getValueType() { + return ValueType.MAP; + } + + @Override + public ImmutableMapValue immutableValue() { + return this; + } + + @Override + public ImmutableMapValue asMapValue() { + return this; + } + + @Override + public Value[] getKeyValueArray() { + return Arrays.copyOf(kvs, kvs.length); + } + + @Override + public int size() { + return kvs.length / 2; + } + + @Override + public Set keySet() { + return new KeySet(kvs); + } + + @Override + public Set> entrySet() { + return new EntrySet(kvs); + } + + @Override + public Collection values() { + return new ValueCollection(kvs); + } + + @Override + public Map map() { + return new ImmutableMapValueMap(kvs); + } + + @Override + public void writeTo(MessagePacker pk) throws IOException { + pk.packMapHeader(kvs.length / 2); + for (int i = 0; i < kvs.length; i++) { + kvs[i].writeTo(pk); + } + } + + @Override + public boolean equals(Object o) { + if (o == this) { + return true; + } + if (!(o instanceof Value)) { + return false; + } + Value v = (Value) o; + + if (!v.isMapValue()) { + return false; + } + MapValue mv = v.asMapValue(); + return map().equals(mv.map()); + } + + @Override + public int hashCode() { + int h = 0; + for (int i = 0; i < kvs.length; i += 2) { + h += kvs[i].hashCode() ^ kvs[i + 1].hashCode(); + } + return h; + } + + @Override + public String toString() { + return toString(new StringBuilder()).toString(); + } + + private StringBuilder toString(StringBuilder sb) { + if (kvs.length == 0) { + return sb.append("{}"); + } + sb.append("{"); + sb.append(kvs[0]); + sb.append(":"); + sb.append(kvs[1]); + for (int i = 2; i < kvs.length; i += 2) { + sb.append(","); + sb.append(kvs[i].toString()); + sb.append(":"); + sb.append(kvs[i + 1].toString()); + } + sb.append("}"); + return sb; + } + + private static class ImmutableMapValueMap extends AbstractMap { + private final Value[] kvs; + + public ImmutableMapValueMap(Value[] kvs) { + this.kvs = kvs; + } + + @Override + public Set> entrySet() { + return new EntrySet(kvs); + } + } + + private static class EntrySet extends AbstractSet> { + private final Value[] kvs; + + EntrySet(Value[] kvs) { + this.kvs = kvs; + } + + @Override + public int size() { + return kvs.length / 2; + } + + @Override + public Iterator> iterator() { + return new EntrySetIterator(kvs); + } + } + + private static class EntrySetIterator implements Iterator> { + private final Value[] kvs; + private int index; + + EntrySetIterator(Value[] kvs) { + this.kvs = kvs; + this.index = 0; + } + + @Override + public boolean hasNext() { + return index < kvs.length; + } + + @Override + public Map.Entry next() { + if (index >= kvs.length) { + throw new NoSuchElementException(); // TODO message + } + + Value key = kvs[index]; + Value value = kvs[index + 1]; + Map.Entry pair = new AbstractMap.SimpleImmutableEntry(key, value); + + index += 2; + return pair; + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); // TODO message + } + } + + private static class KeySet extends AbstractSet { + private Value[] kvs; + + KeySet(Value[] kvs) { + this.kvs = kvs; + } + + @Override + public int size() { + return kvs.length / 2; + } + + @Override + public Iterator iterator() { + return new EntryIterator(kvs, 0); + } + } + + private static class ValueCollection extends AbstractCollection { + private Value[] kvs; + + ValueCollection(Value[] kvs) { + this.kvs = kvs; + } + + @Override + public int size() { + return kvs.length / 2; + } + + @Override + public Iterator iterator() { + return new EntryIterator(kvs, 1); + } + } + + private static class EntryIterator implements Iterator { + private Value[] kvs; + private int index; + + public EntryIterator(Value[] kvs, int offset) { + this.kvs = kvs; + this.index = offset; + } + + @Override + public boolean hasNext() { + return index < kvs.length; + } + + @Override + public Value next() { + int i = index; + if (i >= kvs.length) { + throw new NoSuchElementException(); + } + index = i + 2; + return kvs[i]; + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + } +} diff --git a/msgpack-core/src/main/java/org/msgpack/value/impl/ImmutableNilValueImpl.java b/msgpack-core/src/main/java/org/msgpack/value/impl/ImmutableNilValueImpl.java new file mode 100644 index 000000000..c8f9c3bcc --- /dev/null +++ b/msgpack-core/src/main/java/org/msgpack/value/impl/ImmutableNilValueImpl.java @@ -0,0 +1,82 @@ +// +// MessagePack for Java +// +// 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.msgpack.value.impl; + +import org.msgpack.core.MessagePacker; +import org.msgpack.value.Value; +import org.msgpack.value.ValueType; +import org.msgpack.value.ImmutableNilValue; + +import java.io.IOException; + + +/** + * {@code ImmutableNilValueImpl} Implements {@code ImmutableNilValue}. + * + * This class is a singleton. {@code ImmutableNilValueImpl.get()} is the only instances of this class. + * + * @see org.msgpack.value.NilValue + */ +public class ImmutableNilValueImpl extends AbstractImmutableValue implements ImmutableNilValue { + private static ImmutableNilValue instance = new ImmutableNilValueImpl(); + + public static ImmutableNilValue get() { + return instance; + } + + private ImmutableNilValueImpl() { } + + @Override + public ValueType getValueType() { + return ValueType.NIL; + } + + @Override + public ImmutableNilValue immutableValue() { + return this; + } + + @Override + public ImmutableNilValue asNilValue() { + return this; + } + + @Override + public void writeTo(MessagePacker pk) throws IOException { + pk.packNil(); + } + + @Override + public boolean equals(Object o) { + if (o == this) { + return true; + } + if (!(o instanceof Value)) { + return false; + } + return ((Value) o).isNilValue(); + } + + @Override + public int hashCode() { + return 0; + } + + @Override + public String toString() { + return "null"; + } +} diff --git a/msgpack-core/src/main/java/org/msgpack/value/impl/ImmutableStringValueImpl.java b/msgpack-core/src/main/java/org/msgpack/value/impl/ImmutableStringValueImpl.java new file mode 100644 index 000000000..59e2cefb1 --- /dev/null +++ b/msgpack-core/src/main/java/org/msgpack/value/impl/ImmutableStringValueImpl.java @@ -0,0 +1,88 @@ +// +// MessagePack for Java +// +// 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.msgpack.value.impl; + +import org.msgpack.core.MessagePacker; +import org.msgpack.value.Value; +import org.msgpack.value.ValueType; +import org.msgpack.value.ImmutableStringValue; + +import java.util.Arrays; +import java.io.IOException; + + +/** + * {@code ImmutableStringValueImpl} Implements {@code ImmutableStringValue} using a {@code byte[]} field. + * This implementation caches result of {@code stringValue()} and {@code getString()} using a private {@code String} field. + * + * @see org.msgpack.value.StringValue + */ +public class ImmutableStringValueImpl extends AbstractImmutableRawValue implements ImmutableStringValue { + public ImmutableStringValueImpl(byte[] data) { + super(data); + } + + public ImmutableStringValueImpl(String string) { + super(string); + } + + @Override + public ValueType getValueType() { + return ValueType.STRING; + } + + @Override + public ImmutableStringValue immutableValue() { + return this; + } + + @Override + public ImmutableStringValue asStringValue() { + return this; + } + + @Override + public void writeTo(MessagePacker pk) throws IOException { + pk.packRawStringHeader(data.length); + pk.writePayload(data); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof Value)) { + return false; + } + Value v = (Value) o; + if (!v.isStringValue()) { + return false; + } + + if (v instanceof ImmutableStringValueImpl) { + ImmutableStringValueImpl bv = (ImmutableStringValueImpl) v; + return Arrays.equals(data, bv.data); + } else { + return Arrays.equals(data, v.asStringValue().getByteArray()); + } + } + + @Override + public int hashCode() { + return Arrays.hashCode(data); + } +} diff --git a/msgpack-core/src/main/java/org/msgpack/value/impl/IntegerValueImpl.java b/msgpack-core/src/main/java/org/msgpack/value/impl/IntegerValueImpl.java deleted file mode 100644 index 758fde939..000000000 --- a/msgpack-core/src/main/java/org/msgpack/value/impl/IntegerValueImpl.java +++ /dev/null @@ -1,169 +0,0 @@ -package org.msgpack.value.impl; - -import org.msgpack.core.MessageIntegerOverflowException; -import org.msgpack.core.MessageOverflowException; -import org.msgpack.core.MessagePacker; -import org.msgpack.value.*; - -import java.io.IOException; -import java.math.BigInteger; - -/** -* Created on 5/30/14. -*/ -public class IntegerValueImpl extends AbstractValue implements IntegerValue { - - private final int value; - - public IntegerValueImpl(int value) { - this.value = value; - } - - private static int BYTE_MIN = (int) Byte.MIN_VALUE; - private static int BYTE_MAX = (int) Byte.MAX_VALUE; - private static int SHORT_MIN = (int) Short.MIN_VALUE; - private static int SHORT_MAX = (int) Short.MAX_VALUE; - - @Override - public ValueType getValueType() { - return ValueType.INTEGER; - } - - @Override - public IntegerValue asInteger() { - return this; - } - - @Override - public byte toByte() { - return (byte) value; - } - - @Override - public short toShort() { - return (short) value; - } - - @Override - public int toInt() { - return value; - } - - @Override - public long toLong() { - return value; - } - - @Override - public BigInteger toBigInteger() { - return BigInteger.valueOf((long) value); - } - - @Override - public float toFloat() { - return (float) value; - } - - @Override - public double toDouble() { - return (double) value; - } - - @Override - public byte asByte() throws MessageOverflowException { - if (!isValidByte()) { - throw new MessageIntegerOverflowException(value); - } - return (byte) value; - } - - @Override - public short asShort() throws MessageOverflowException { - if (!isValidShort()) { - throw new MessageIntegerOverflowException(value); - } - return (short) value; - } - - @Override - public int asInt() throws MessageOverflowException { - return value; - } - - @Override - public long asLong() throws MessageOverflowException { - return value; - } - - @Override - public BigInteger asBigInteger() throws MessageOverflowException { - return BigInteger.valueOf((long) value); - } - - @Override - public boolean isValidByte() { - return BYTE_MIN <= value && value <= BYTE_MAX; - } - - @Override - public boolean isValidShort() { - return SHORT_MIN <= value && value <= SHORT_MAX; - } - - @Override - public boolean isValidInt() { - return true; - } - - @Override - public boolean isValidLong() { - return true; - } - - @Override - public boolean isWhole() { - return true; - } - - @Override - public void writeTo(MessagePacker pk) throws IOException { - pk.packInt(value); - } - @Override - public void accept(ValueVisitor visitor) { - visitor.visitInteger(this); - } - @Override - public IntegerValue toValue() { - return this; - } - - @Override - public boolean equals(Object o) { - if (o == this) { - return true; - } - if (!(o instanceof Value)) { - return false; - } - Value v = (Value) o; - if (!v.isInteger()) { - return false; - } - IntegerValue iv = v.asInteger(); - if (!iv.isValidInt()) { - return false; - } - return iv.toInt() == value; - } - - @Override - public int hashCode() { - return value; - } - - @Override - public String toString() { - return Integer.toString(value); - } -} diff --git a/msgpack-core/src/main/java/org/msgpack/value/impl/MapCursorImpl.java b/msgpack-core/src/main/java/org/msgpack/value/impl/MapCursorImpl.java deleted file mode 100644 index a6f5268b1..000000000 --- a/msgpack-core/src/main/java/org/msgpack/value/impl/MapCursorImpl.java +++ /dev/null @@ -1,116 +0,0 @@ -package org.msgpack.value.impl; - -import org.msgpack.core.*; -import org.msgpack.value.*; -import org.msgpack.value.holder.ValueHolder; - -import java.io.IOException; - -import static org.msgpack.core.MessagePackException.UNSUPPORTED; - -/** - * Created on 6/16/14. - */ -public class MapCursorImpl extends AbstractValueRef implements MapCursor { - - private final ValueHolder valueHolder; - private MessageUnpacker unpacker; - private int cursor = 0; - private int mapSize; - - public MapCursorImpl(ValueHolder valueHolder) { - this.valueHolder = valueHolder; - } - - public void reset(MessageUnpacker unpacker) throws IOException { - this.unpacker = unpacker; - cursor = 0; - this.mapSize = unpacker.unpackMapHeader(); - } - - @Override - public int size() { - return mapSize; - } - @Override - public boolean hasNext() { - try { - return cursor < (mapSize * 2) && unpacker.hasNext(); - } - catch(IOException e) { - return false; - } - } - - @Override - public ValueRef nextKeyOrValue() { - try { - MessageFormat f = unpacker.unpackValue(valueHolder); - cursor++; - return valueHolder.getRef(); - } - catch(IOException e) { - throw new MessageFormatException(e); - } - } - - @Override - public void skipKeyOrValue() { - try { - unpacker.skipValue(); - } - catch(IOException e) { - throw new MessageFormatException(e); - } - } - - @Override - public void skipAll() { - while(hasNext()) { - skipKeyOrValue(); - } - } - - private void ensureNotTraversed() { - if(cursor != 0) - throw UNSUPPORTED("MapCursor is already traversed"); - } - - - @Override - public MapCursor getMapCursor() throws MessageTypeException { - return this; - } - - @Override - public ValueType getValueType() { - return ValueType.MAP; - } - - @Override - public void writeTo(MessagePacker packer) throws IOException { - ensureNotTraversed(); - packer.packMapHeader(mapSize); - while(hasNext()) { - packer.packValue(nextKeyOrValue().toValue()); - } - } - - @Override - public void accept(ValueVisitor visitor) { - visitor.visitMap(this.toValue()); - } - - @Override - public MapValue toValue() { - ensureNotTraversed(); - Value[] keyValueArray = new Value[mapSize * 2]; - int i = 0; - while(hasNext()) { - keyValueArray[i++] = nextKeyOrValue().toValue(); - } - return ValueFactory.newMap(keyValueArray); - } - - -} diff --git a/msgpack-core/src/main/java/org/msgpack/value/impl/MapValueImpl.java b/msgpack-core/src/main/java/org/msgpack/value/impl/MapValueImpl.java deleted file mode 100644 index 3f010a7e2..000000000 --- a/msgpack-core/src/main/java/org/msgpack/value/impl/MapValueImpl.java +++ /dev/null @@ -1,280 +0,0 @@ -package org.msgpack.value.impl; - -import org.msgpack.core.MessagePacker; -import org.msgpack.value.*; - -import java.io.IOException; -import java.util.*; - -/** -* Created on 5/30/14. -*/ -public class MapValueImpl extends AbstractValue implements MapValue { - private static MapValueImpl EMPTY = new MapValueImpl(new Value[0]); - - public static MapValue empty() { - return EMPTY; - } - - private final Value[] array; - private transient int cursor = 0; - - public MapValueImpl(Value[] array) { - this.array = array; - } - - @Override - public ValueType getValueType() { - return ValueType.MAP; - } - - @Override - public Value[] toKeyValueSeq() { - return Arrays.copyOf(array, array.length); - } - @Override - public int size() { - return array.length / 2; - } - - @Override - public boolean hasNext() { - return cursor < array.length; - } - @Override - public ValueRef nextKeyOrValue() { - return array[cursor++]; - } - - @Override - public void skipKeyOrValue() { - cursor++; - } - @Override - public void skipAll() { - while(hasNext()) { - skipKeyOrValue(); - } - } - - @Override - public MapCursor getMapCursor() { - return this; - } - - private class MapImpl extends AbstractMap { - - private class EntrySet extends AbstractSet> { - - @Override - public int size() { - return array.length / 2; - } - - @Override - public Iterator> iterator() { - return new EntrySetIterator(); - } - } - - private class EntrySetIterator implements - Iterator> { - private int pos = 0; - - @Override - public boolean hasNext() { - return pos < array.length; - } - - @Override - public Entry next() { - if (pos >= array.length) { - throw new NoSuchElementException(); - } - - Value key = array[pos]; - Value value = array[pos + 1]; - Entry pair = new SimpleImmutableEntry(key, value); - - pos += 2; - return pair; - } - - @Override - public void remove() { - throw new UnsupportedOperationException(); - } - } - - private class KeySet extends AbstractSet { - @Override - public int size() { - return array.length / 2; - } - - @Override - public Iterator iterator() { - return new ValueIterator(0); - } - } - - private class ValueCollection extends AbstractCollection { - - @Override - public int size() { - return array.length / 2; - } - - @Override - public Iterator iterator() { - return new ValueIterator(1); - } - } - - private class ValueIterator implements Iterator { - private int pos; - - ValueIterator(int offset) { - this.pos = offset; - } - - @Override - public boolean hasNext() { - return pos < array.length; - } - - @Override - public Value next() { - if (pos >= array.length) { - throw new NoSuchElementException(); - } - Value v = array[pos]; - pos += 2; - return v; - } - - @Override - public void remove() { - throw new UnsupportedOperationException(); - } - } - - @Override - public Set> entrySet() { - return new EntrySet(); - } - - @Override - public Set keySet() { - return new KeySet(); - } - - @Override - public Collection values() { - return new ValueCollection(); - } - - - @Override - public Value get(Object key) { - for (int i = array.length - 2; i >= 0; i -= 2) { - if (array[i].equals(key)) { - return array[i + 1]; - } - } - return null; - } - } - - @Override - public Map toMap() { - return new MapImpl(); - } - - @Override - public void writeTo(MessagePacker pk) throws IOException { - pk.packMapHeader(array.length / 2); - for (int i = 0; i < array.length; i++) { - array[i].writeTo(pk); - } - } - @Override - public void accept(ValueVisitor visitor) { - visitor.visitMap(this); - } - - @Override - public MapValue toValue() { - return ValueFactory.newMap(array); - } - - @Override - public boolean equals(Object o) { - if (o == this) { - return true; - } - if (!(o instanceof Value)) { - return false; - } - Value v = (Value) o; - if (!v.isMap()) { - return false; - } - - Map mv = v.asMapValue().toMap(); - if (mv.size() != array.length / 2) { - return false; - } - - try { - for (int i = 0; i < array.length; i += 2) { - Value key = array[i]; - Value value = array[i + 1]; - if (!value.equals(mv.get(key))) { - return false; - } - } - } catch (ClassCastException ex) { - return false; - } catch (NullPointerException ex) { - return false; - } - - return true; - } - - @Override - public int hashCode() { - int h = 0; - for (int i = 0; i < array.length; i += 2) { - h += array[i].hashCode() ^ array[i + 1].hashCode(); - } - return h; - } - - @Override - public String toString() { - return toString(new StringBuilder()).toString(); - } - - private StringBuilder toString(StringBuilder sb) { - if (array.length == 0) { - return sb.append("{}"); - } - sb.append("{"); - sb.append(array[0]); - sb.append(":"); - sb.append(array[1]); - for (int i = 2; i < array.length; i += 2) { - sb.append(","); - sb.append(array[i].toString()); - sb.append(":"); - sb.append(array[i + 1].toString()); - } - sb.append("}"); - return sb; - } - - - -} diff --git a/msgpack-core/src/main/java/org/msgpack/value/impl/NilValueImpl.java b/msgpack-core/src/main/java/org/msgpack/value/impl/NilValueImpl.java deleted file mode 100644 index 3fea78364..000000000 --- a/msgpack-core/src/main/java/org/msgpack/value/impl/NilValueImpl.java +++ /dev/null @@ -1,60 +0,0 @@ -package org.msgpack.value.impl; - -import org.msgpack.core.MessagePacker; -import org.msgpack.value.ValueType; -import org.msgpack.value.NilValue; -import org.msgpack.value.Value; -import org.msgpack.value.ValueVisitor; - -import java.io.IOException; - -/** -* Created on 5/30/14. -*/ -public class NilValueImpl extends AbstractValue implements NilValue { - - private static NilValue instance = new NilValueImpl(); - - public static NilValue getInstance() { - return instance; - } - - @Override - public ValueType getValueType() { - return ValueType.NIL; - } - - @Override - public boolean equals(Object o) { - if (o == this) { - return true; - } - if (!(o instanceof Value)) { - return false; - } - return ((Value) o).isNil(); - } - - @Override - public int hashCode() { - return 0; - } - - @Override - public String toString() { - return "null"; - } - - @Override - public void writeTo(MessagePacker packer) throws IOException { - packer.packNil(); - } - @Override - public void accept(ValueVisitor visitor) { - visitor.visitNil(); - } - @Override - public NilValue toValue() { - return instance; - } -} diff --git a/msgpack-core/src/main/java/org/msgpack/value/impl/RawStringValueImpl.java b/msgpack-core/src/main/java/org/msgpack/value/impl/RawStringValueImpl.java deleted file mode 100644 index 7fd0d61f2..000000000 --- a/msgpack-core/src/main/java/org/msgpack/value/impl/RawStringValueImpl.java +++ /dev/null @@ -1,69 +0,0 @@ -package org.msgpack.value.impl; - -import org.msgpack.core.MessagePacker; -import org.msgpack.core.MessageStringCodingException; -import org.msgpack.value.*; - -import java.io.IOException; -import java.nio.ByteBuffer; - -/** -* Created on 5/30/14. -*/ -public class RawStringValueImpl extends RawValueImpl implements StringValue { - - public RawStringValueImpl(ByteBuffer byteBuffer) { - super(byteBuffer); - } - - @Override - public ValueType getValueType() { - return ValueType.STRING; - } - - @Override - public void accept(ValueVisitor visitor) { - visitor.visitString(this); - } - - @Override - public String toString() { - return super.toString(); - } - - @Override - public void writeTo(MessagePacker pk) throws IOException { - pk.packRawStringHeader(byteBuffer.remaining()); - pk.writePayload(byteBuffer); - } - - @Override - public StringValue toValue() { - return this; - } - - @Override - public boolean equals(Object o) { - if (o == this) { - return true; - } - if (!(o instanceof Value)) { - return false; - } - Value v = (Value) o; - if (!v.isString()) { - return false; - } - try { - return toString().equals(v.asString().toString()); - } catch (MessageStringCodingException ex) { - return false; - } - - } - - @Override - public int hashCode() { - return toString().hashCode(); - } -} diff --git a/msgpack-core/src/main/java/org/msgpack/value/impl/RawValueImpl.java b/msgpack-core/src/main/java/org/msgpack/value/impl/RawValueImpl.java deleted file mode 100644 index e9db5f129..000000000 --- a/msgpack-core/src/main/java/org/msgpack/value/impl/RawValueImpl.java +++ /dev/null @@ -1,116 +0,0 @@ -package org.msgpack.value.impl; - -import org.msgpack.core.MessagePacker; -import org.msgpack.core.MessageStringCodingException; -import org.msgpack.core.buffer.MessageBuffer; -import org.msgpack.value.BinaryValue; -import org.msgpack.value.RawValue; -import org.msgpack.value.Value; - -import java.io.IOException; -import java.nio.ByteBuffer; -import java.nio.charset.*; - -/** -* Created on 5/30/14. -*/ -public abstract class RawValueImpl extends AbstractValue implements RawValue { - - protected final ByteBuffer byteBuffer; - private transient String decodedStringCache; - private transient MessageStringCodingException codingException; - - public RawValueImpl(ByteBuffer byteBuffer) { - this.byteBuffer = byteBuffer.slice(); - } - - @Override - public byte[] toByteArray() { - byte[] byteArray = new byte[byteBuffer.remaining()]; - byteBuffer.slice().get(byteArray); - return byteArray; - } - - @Override - public RawValue toValue() { - return this; - } - - @Override - public ByteBuffer toByteBuffer() { - return byteBuffer.asReadOnlyBuffer(); - } - - @Override - public MessageBuffer toMessageBuffer() { - return MessageBuffer.wrap(byteBuffer); - } - - @Override - public String toString() { - if (decodedStringCache == null) { - decodeString(); - } - if (codingException != null) { - throw codingException; - } - return decodedStringCache; - } - - - private synchronized void decodeString() { - if (decodedStringCache != null) { - return; - } - ByteBuffer readOnlyBuffer = byteBuffer.asReadOnlyBuffer(); - try { - CharsetDecoder reportDecoder = Charset.forName("UTF-8").newDecoder() - .onMalformedInput(CodingErrorAction.REPLACE) - .onUnmappableCharacter(CodingErrorAction.REPLACE); - readOnlyBuffer.position(0); - decodedStringCache = reportDecoder.decode(readOnlyBuffer).toString(); - } catch (UnsupportedCharsetException neverThrown) { - throw new AssertionError(neverThrown); - } catch (CharacterCodingException ex) { - codingException = new MessageStringCodingException(ex); - try { - CharsetDecoder replaceDecoder = Charset.forName("UTF-8").newDecoder() - .onMalformedInput(CodingErrorAction.REPLACE) - .onUnmappableCharacter(CodingErrorAction.REPLACE); - readOnlyBuffer.position(0); - decodedStringCache = replaceDecoder.decode(readOnlyBuffer).toString(); - } catch (UnsupportedCharsetException neverThrown) { - throw new AssertionError(neverThrown); - } catch (CharacterCodingException neverThrown) { - throw new AssertionError(neverThrown); - } - } - } - - @Override - public boolean equals(Object o) { - if (o == this) { - return true; - } - if (!(o instanceof Value)) { - return false; - } - Value v = (Value) o; - if (!v.isBinary()) { - return false; - } - BinaryValue bv = v.asBinary(); - return bv.toByteBuffer().equals(byteBuffer); - } - - @Override - public int hashCode() { - return byteBuffer.hashCode(); - } - - @Override - public void writeTo(MessagePacker packer) throws IOException { - packer.packBinaryHeader(byteBuffer.remaining()); - packer.writePayload(byteBuffer); - } -} diff --git a/msgpack-core/src/main/java/org/msgpack/value/impl/StringValueImpl.java b/msgpack-core/src/main/java/org/msgpack/value/impl/StringValueImpl.java deleted file mode 100644 index 4bbe14d6f..000000000 --- a/msgpack-core/src/main/java/org/msgpack/value/impl/StringValueImpl.java +++ /dev/null @@ -1,84 +0,0 @@ -package org.msgpack.value.impl; - -import org.msgpack.core.MessagePack; -import org.msgpack.core.MessagePacker; -import org.msgpack.core.MessageStringCodingException; -import org.msgpack.core.buffer.MessageBuffer; -import org.msgpack.value.*; - -import java.io.IOException; -import java.nio.ByteBuffer; - -/** -* Created on 5/30/14. -*/ -public class StringValueImpl extends AbstractValue implements StringValue { - - private final String value; - - public StringValueImpl(String value) { - this.value = value; - } - - @Override - public ValueType getValueType() { - return ValueType.STRING; - } - - @Override - public byte[] toByteArray() { - return value.getBytes(MessagePack.UTF8); - } - - @Override - public MessageBuffer toMessageBuffer() { - return MessageBuffer.wrap(toByteArray()); - } - - @Override - public String toString() { - return value; - } - - @Override - public ByteBuffer toByteBuffer() { - return toMessageBuffer().toByteBuffer(); - } - - @Override - public void writeTo(MessagePacker pk) throws IOException { - pk.packString(value); - } - @Override - public void accept(ValueVisitor visitor) { - visitor.visitString(this); - } - @Override - public StringValue toValue() { - return ValueFactory.newString(value); - } - - @Override - public boolean equals(Object o) { - if (o == this) { - return true; - } - if (!(o instanceof Value)) { - return false; - } - Value v = (Value) o; - if (!v.isString()) { - return false; - } - try { - return v.asString().toString().equals(value); - } catch (MessageStringCodingException ex) { - return false; - } - } - - @Override - public int hashCode() { - return value.hashCode(); - } -} diff --git a/msgpack-core/src/main/java/org/msgpack/value/impl/ValueUnion.java b/msgpack-core/src/main/java/org/msgpack/value/impl/ValueUnion.java deleted file mode 100644 index 0a282ef0d..000000000 --- a/msgpack-core/src/main/java/org/msgpack/value/impl/ValueUnion.java +++ /dev/null @@ -1,131 +0,0 @@ -// -// MessagePack for Java -// -// 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.msgpack.value.impl; - -import java.util.List; -import java.util.Map; -import java.math.BigInteger; -import java.nio.ByteBuffer; - -import org.msgpack.value.Value; - -/** - * Union of multiple values so that we can minimize the object initialization cost - */ -class ValueUnion { - public static enum Type { - BOOLEAN, - LONG, - BIG_INTEGER, - DOUBLE, - BYTE_BUFFER, - STRING, - LIST, - MAP; - } - - private Type type; - - private long longValue; - private double doubleValue; - private Object objectValue; - - public void reset() { - this.type = null; - } - - public boolean isSet() { - return type != null; - } - - public Type getType() { - return type; - } - - public void setBoolean(boolean v) { - this.type = Type.BOOLEAN; - this.longValue = (v ? 1L : 0L); - } - - public boolean getBoolean() { - return longValue != 0L; - } - - public void setLong(long v) { - this.type = Type.LONG; - this.longValue = v; - } - - public long getLong() { - return longValue; - } - - public void setBigInteger(BigInteger v) { - this.type = Type.BIG_INTEGER; - this.objectValue = v; - } - - public BigInteger getBigInteger() { - return (BigInteger) objectValue; - } - - public void setDouble(double v) { - this.type = Type.DOUBLE; - this.doubleValue = v; - } - - public double getDouble() { - return doubleValue; - } - - public void setByteBuffer(ByteBuffer v) { - this.type = Type.BYTE_BUFFER; - this.objectValue = v; - } - - public ByteBuffer getByteBuffer() { - return (ByteBuffer) objectValue; - } - - public void setString(String v) { - this.type = Type.STRING; - this.objectValue = v; - } - - public String getString() { - return (String) objectValue; - } - - public void setList(List v) { - this.type = Type.LIST; - this.objectValue = v; - } - - @SuppressWarnings("unchecked") - public List getList() { - return (List) objectValue; - } - - public void setMap(Map v) { - this.type = Type.MAP; - this.objectValue = v; - } - - @SuppressWarnings("unchecked") - public Map getMap() { - return (Map) objectValue; - } -} diff --git a/msgpack-core/src/main/java/org/msgpack/core/example/MessagePackExample.java b/msgpack-core/src/test/java/org/msgpack/core/example/MessagePackExample.java similarity index 83% rename from msgpack-core/src/main/java/org/msgpack/core/example/MessagePackExample.java rename to msgpack-core/src/test/java/org/msgpack/core/example/MessagePackExample.java index 2720ab3f9..8e29c5255 100644 --- a/msgpack-core/src/main/java/org/msgpack/core/example/MessagePackExample.java +++ b/msgpack-core/src/test/java/org/msgpack/core/example/MessagePackExample.java @@ -16,12 +16,9 @@ package org.msgpack.core.example; import org.msgpack.core.*; -import org.msgpack.core.buffer.MessageBuffer; import org.msgpack.value.*; -import org.msgpack.value.holder.FloatHolder; -import org.msgpack.value.holder.IntegerHolder; -import org.msgpack.value.holder.ValueHolder; +import java.math.BigInteger; import java.io.*; import java.nio.ByteBuffer; import java.nio.charset.CodingErrorAction; @@ -128,7 +125,7 @@ public static void packer() throws IOException { // Write ext type data: https://github.com/msgpack/msgpack/blob/master/spec.md#ext-format-family byte[] extData = "custom data type".getBytes(MessagePack.UTF8); - packer.packExtendedTypeHeader(1, 10); // type number [0, 127], data byte length + packer.packExtensionTypeHeader((byte) 1, 10); // type number [0, 127], data byte length packer.writePayload(extData); // Succinct syntax for packing @@ -174,54 +171,55 @@ public static void readAndWriteFile() throws IOException { // Alternatively you can use ValueHolder to extract a value of any type // NOTE: Value interface is in a preliminary state, so the following code might change in future releases - ValueHolder v = new ValueHolder(); - format = unpacker.unpackValue(v); - switch(format.getValueType()) { + Value v = unpacker.unpackValue(); + switch(v.getValueType()) { case NIL: - Value nil = v.get(); - nil.isNil(); // true + v.isNilValue(); // true System.out.println("read nil"); break; case BOOLEAN: - boolean b = v.get().asBoolean().toBoolean(); + boolean b = v.asBooleanValue().getBoolean(); System.out.println("read boolean: " + b); break; case INTEGER: - IntegerHolder ih = v.getIntegerHolder(); - if(ih.isValidInt()) { // int range check [-2^31-1, 2^31-1] - int i = ih.asInt(); + IntegerValue iv = v.asIntegerValue(); + if(iv.isInIntRange()) { + int i = iv.castAsInt(); System.out.println("read int: " + i); } - else { - long l = ih.asLong(); + else if (iv.isInLongRange()) { + long l = iv.castAsLong(); System.out.println("read long: " + l); } + else { + BigInteger i = iv.castAsBigInteger(); + System.out.println("read long: " + i); + } break; case FLOAT: - FloatHolder fh = v.getFloatHolder(); - float f = fh.toFloat(); // read as float - double d = fh.toDouble(); // read as double + FloatValue fv = v.asFloatValue(); + float f = fv.castAsFloat(); // use as float + double d = fv.castAsDouble(); // use as double System.out.println("read float: " + d); break; case STRING: - String s = v.get().asString().toString(); + String s = v.asStringValue().getString(); System.out.println("read string: " + s); break; case BINARY: - // Message buffer is an efficient byte buffer - MessageBuffer mb = v.get().asBinary().toMessageBuffer(); - System.out.println("read binary: " + mb.toHexString(0, mb.size())); + byte[] mb = v.asBinaryValue().getByteArray(); + System.out.println("read binary: size=" + mb.length); break; case ARRAY: - ArrayValue arr = v.get().asArrayValue(); - for(ValueRef a : arr) { - System.out.println("read array element: " + a); + ArrayValue a = v.asArrayValue(); + for(Value e : a) { + System.out.println("read array element: " + e); } break; - case EXTENDED: - ExtendedValue ev = v.get().asExtended(); - int extType = ev.getExtType(); - byte[] extValue = ev.toByteArray(); + case EXTENSION: + ExtensionValue ev = v.asExtensionValue(); + byte extType = ev.getType(); + byte[] extValue = ev.getData(); break; } } diff --git a/msgpack-core/src/test/scala/org/msgpack/core/MessageFormatTest.scala b/msgpack-core/src/test/scala/org/msgpack/core/MessageFormatTest.scala index c4e381cd0..7f89760f8 100644 --- a/msgpack-core/src/test/scala/org/msgpack/core/MessageFormatTest.scala +++ b/msgpack-core/src/test/scala/org/msgpack/core/MessageFormatTest.scala @@ -52,14 +52,14 @@ class MessageFormatTest extends MessagePackSpec { check(Code.BIN16, ValueType.BINARY, MessageFormat.BIN16) check(Code.BIN32, ValueType.BINARY, MessageFormat.BIN32) - check(Code.FIXEXT1, ValueType.EXTENDED, MessageFormat.FIXEXT1) - check(Code.FIXEXT2, ValueType.EXTENDED, MessageFormat.FIXEXT2) - check(Code.FIXEXT4, ValueType.EXTENDED, MessageFormat.FIXEXT4) - check(Code.FIXEXT8, ValueType.EXTENDED, MessageFormat.FIXEXT8) - check(Code.FIXEXT16, ValueType.EXTENDED, MessageFormat.FIXEXT16) - check(Code.EXT8, ValueType.EXTENDED, MessageFormat.EXT8) - check(Code.EXT16, ValueType.EXTENDED, MessageFormat.EXT16) - check(Code.EXT32, ValueType.EXTENDED, MessageFormat.EXT32) + check(Code.FIXEXT1, ValueType.EXTENSION, MessageFormat.FIXEXT1) + check(Code.FIXEXT2, ValueType.EXTENSION, MessageFormat.FIXEXT2) + check(Code.FIXEXT4, ValueType.EXTENSION, MessageFormat.FIXEXT4) + check(Code.FIXEXT8, ValueType.EXTENSION, MessageFormat.FIXEXT8) + check(Code.FIXEXT16, ValueType.EXTENSION, MessageFormat.FIXEXT16) + check(Code.EXT8, ValueType.EXTENSION, MessageFormat.EXT8) + check(Code.EXT16, ValueType.EXTENSION, MessageFormat.EXT16) + check(Code.EXT32, ValueType.EXTENSION, MessageFormat.EXT32) check(Code.INT8, ValueType.INTEGER, MessageFormat.INT8) diff --git a/msgpack-core/src/test/scala/org/msgpack/core/MessagePackTest.scala b/msgpack-core/src/test/scala/org/msgpack/core/MessagePackTest.scala index 59d71b6e8..6c1fbb791 100644 --- a/msgpack-core/src/test/scala/org/msgpack/core/MessagePackTest.scala +++ b/msgpack-core/src/test/scala/org/msgpack/core/MessagePackTest.scala @@ -15,8 +15,7 @@ // package org.msgpack.core -import org.msgpack.value.Value -import org.msgpack.value.holder.ValueHolder +import org.msgpack.value.{Variable, Value} import scala.util.Random import MessagePack.Code @@ -175,7 +174,7 @@ class MessagePackTest extends MessagePackSpec { forAll { (v: Float) => check(v, _.packFloat(v), _.unpackFloat)} forAll { (v: Long) => check(v, _.packLong(v), _.unpackLong)} forAll { (v: Double) => check(v, _.packDouble(v), _.unpackDouble)} - check(null, _.packNil, _.unpackNil()) + check(null, _.packNil, {unpacker => unpacker.unpackNil(); null}) } "pack/unpack integer values" taggedAs("int") in { @@ -414,19 +413,18 @@ class MessagePackTest extends MessagePackSpec { } - "pack/unpack extended types" taggedAs("ext") in { - forAll { (dataLen: Int, tpe: Int) => + "pack/unpack extension types" taggedAs("ext") in { + forAll { (dataLen: Int, tpe: Byte) => val l = Math.abs(dataLen) - val t = Math.abs(tpe) % 128 whenever(l >= 0) { - val ext = new ExtendedTypeHeader(l, t) - check(ext, _.packExtendedTypeHeader(ext.getType, ext.getLength), _.unpackExtendedTypeHeader()) + val ext = new ExtensionTypeHeader(ExtensionTypeHeader.checkedCastToByte(tpe), l) + check(ext, _.packExtensionTypeHeader(ext.getType, ext.getLength), _.unpackExtensionTypeHeader()) } } for(l <- testHeaderLength) { - val ext = new ExtendedTypeHeader(l, Random.nextInt(128)) - check(ext, _.packExtendedTypeHeader(ext.getType, ext.getLength), _.unpackExtendedTypeHeader()) + val ext = new ExtensionTypeHeader(ExtensionTypeHeader.checkedCastToByte(Random.nextInt(128)), l) + check(ext, _.packExtensionTypeHeader(ext.getType, ext.getLength), _.unpackExtensionTypeHeader()) } } @@ -444,19 +442,18 @@ class MessagePackTest extends MessagePackSpec { } } }, { unpacker => - val holder = new ValueHolder() - unpacker.unpackValue(holder) - val v = holder.get() - - v.asArrayValue().toValueArray.map { m => + val v = new Variable() + unpacker.unpackValue(v) + import scala.collection.JavaConversions._ + v.asArrayValue().map { m => val mv = m.asMapValue() - val kvs = mv.toKeyValueSeq + val kvs = mv.getKeyValueArray kvs.grouped(2).map({ kvp: Array[Value] => val k = kvp(0) val v = kvp(1) - (k.asString().toString, v.asString().toString) + (k.asStringValue().getString, v.asStringValue().getString) }).toMap }.toList }) diff --git a/msgpack-core/src/test/scala/org/msgpack/core/MessagePackerTest.scala b/msgpack-core/src/test/scala/org/msgpack/core/MessagePackerTest.scala index 4c2dc46e9..590936239 100644 --- a/msgpack-core/src/test/scala/org/msgpack/core/MessagePackerTest.scala +++ b/msgpack-core/src/test/scala/org/msgpack/core/MessagePackerTest.scala @@ -128,7 +128,7 @@ class MessagePackerTest extends MessagePackSpec { def test(bufferSize: Int, stringSize: Int): Boolean = { val msgpack = new MessagePack(new MessagePack.ConfigBuilder().packerBufferSize(bufferSize).build) val str = "a" * stringSize - val rawString = ValueFactory.newRawString(str.getBytes("UTF-8")) + val rawString = ValueFactory.newString(str.getBytes("UTF-8")) val array = ValueFactory.newArray(rawString) val out = new ByteArrayOutputStream() val packer = msgpack.newPacker(out) diff --git a/msgpack-core/src/test/scala/org/msgpack/value/CursorTest.scala b/msgpack-core/src/test/scala/org/msgpack/value/CursorTest.scala deleted file mode 100644 index ee46ff7bd..000000000 --- a/msgpack-core/src/test/scala/org/msgpack/value/CursorTest.scala +++ /dev/null @@ -1,199 +0,0 @@ -// -// MessagePack for Java -// -// 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.msgpack.value - -import java.io.ByteArrayInputStream - -import org.msgpack.core.{MessagePack, MessageUnpacker, MessagePackSpec} -import ValueFactory._ -import scala.util.Random -import org.msgpack.value.holder.{ValueHolder, IntegerHolder} - -/** - * Created on 6/13/14. - */ -class CursorTest extends MessagePackSpec { - - val msgpack = MessagePack.DEFAULT - - def sampleData = createMessagePackData { packer => - packer.packValue( - ValueFactory.newArray( - newInt(10), - newBinary("message pack".getBytes(MessagePack.UTF8)), - newString("hello") - ) - ) - } - - def intSeq(n:Int) = createMessagePackData { packer => - (0 until n).foreach { i => - packer.packInt(Random.nextInt(65536)) - } - } - def binSeq(n:Int) = createMessagePackData { packer => - (0 until n).foreach { i => - val len = Random.nextInt(256) - val b = new Array[Byte](len) - Random.nextBytes(b) - packer.packBinaryHeader(b.length).writePayload(b) - } - } - - - "Cursor" should { - - "have array cursor" taggedAs("array") in { - - val cursor = msgpack.newUnpacker(sampleData).getCursor - // Traverse as references - val arrCursor = cursor.nextRef().getArrayCursor - arrCursor.size() shouldBe 3 - - import scala.collection.JavaConversions._ - for(v <- arrCursor) { - info(s"[${v.getValueType}]\t${v}") - } - } - - "have map cursor" taggedAs("map") in { - val packedData = createMessagePackData { packer => - packer packMapHeader(1) packString("f") packString("x") - } - - val cursor = msgpack.newUnpacker(packedData).getCursor - val mapCursor = cursor.nextRef().getMapCursor - mapCursor.size() shouldBe 1 - - val mapValue = mapCursor.toValue - val data = mapValue.toKeyValueSeq - - data should have length 2 - - data(0).asString().toString shouldBe "f" - data(1).asString().toString shouldBe "x" - } - - "traverse ValueRef faster than traversing Value" taggedAs("ref") in { - val N = 10000 - val data = binSeq(N) - - time("traversal", repeat=100) { - block("value") { - val cursor = msgpack.newUnpacker(data).getCursor - while(cursor.hasNext) { - cursor.next() - } - cursor.close() - } - block("value-ref") { - val cursor = msgpack.newUnpacker(data).getCursor - while(cursor.hasNext) { - cursor.nextRef() - } - cursor.close() - } - } - - } - - "have negligible overhead" taggedAs("perf") in { - val N = 10000 - val data = intSeq(N) - time("scan int-seq", repeat=1000) { - block("unpacker") { - val unpacker = msgpack.newUnpacker(data) - val intHolder = new IntegerHolder() - var count = 0 - while(unpacker.hasNext) { - val vt = unpacker.getNextFormat.getValueType - if(vt.isIntegerType) { - unpacker.unpackInteger(intHolder); - count += 1 - } - else { - throw new IllegalStateException(s"invalid format: ${vt}") - } - } - unpacker.close() - count shouldBe N - } - block("cursor") { - var count = 0 - val cursor = msgpack.newUnpacker(data).getCursor - while(cursor.hasNext) { - val ref = cursor.nextRef() - val v = ref.asInteger().toInt - count += 1 - } - cursor.close() - count shouldBe N - } - } - - } - - "create immutable map" taggedAs("im-map") in { - - val m = createMessagePackData { packer => - packer.packMapHeader(3) - - // A -> [1, "leo"] - packer.packString("A") - packer.packArrayHeader(2) - packer.packInt(1) - packer.packString("leo") - - // B -> 10 - packer.packString("B") - packer.packInt(10) - - // C -> {a -> 1.0f, b -> 5, c -> {cc->1}} - packer.packString("C") - packer.packMapHeader(3) - packer.packString("a") - packer.packFloat(1.0f) - packer.packString("b") - packer.packInt(5) - - packer.packString("c") - packer.packMapHeader(1) - packer.packString("cc") - packer.packInt(1) - - } - - val unpacker = msgpack.newUnpacker(m) - val vh = new ValueHolder - unpacker.unpackValue(vh) - val mapValue = vh.get().asMapValue() - - val map = mapValue.toMap - map.size shouldBe 3 - - val arr = map.get(ValueFactory.newString("A")).asArrayValue() - arr.size shouldBe 2 - - val cmap = map.get(ValueFactory.newString("C")).asMapValue() - cmap.size shouldBe 3 - cmap.toMap.get(ValueFactory.newString("c")).asMapValue().size() shouldBe 1 - - info(mapValue) - } - - - } -} diff --git a/msgpack-core/src/test/scala/org/msgpack/value/RawStringValueImplTest.scala b/msgpack-core/src/test/scala/org/msgpack/value/RawStringValueImplTest.scala index 1193a3310..bd57480e0 100644 --- a/msgpack-core/src/test/scala/org/msgpack/value/RawStringValueImplTest.scala +++ b/msgpack-core/src/test/scala/org/msgpack/value/RawStringValueImplTest.scala @@ -7,7 +7,7 @@ class RawStringValueImplTest extends MessagePackSpec { "StringValue" should { "return the same hash code if they are equal" in { val str = "a" - val a1 = ValueFactory.newRawString(str.getBytes("UTF-8")) + val a1 = ValueFactory.newString(str.getBytes("UTF-8")) val a2 = ValueFactory.newString(str) a1.shouldEqual(a2) diff --git a/msgpack-core/src/test/scala/org/msgpack/value/RawValueImplTest.scala b/msgpack-core/src/test/scala/org/msgpack/value/RawValueImplTest.scala deleted file mode 100644 index 6e56aa762..000000000 --- a/msgpack-core/src/test/scala/org/msgpack/value/RawValueImplTest.scala +++ /dev/null @@ -1,35 +0,0 @@ -package org.msgpack.value - -import org.msgpack.core.{MessagePack, MessagePackSpec} -import java.io.ByteArrayOutputStream - - -class RawValueImplTest extends MessagePackSpec { - - "RawValueImple" should { - "toString shouldn't return empty value" in { - val str = "aaa" - def newRawStr() = ValueFactory.newRawString(str.getBytes("UTF-8")) - - def pack(v: Value): Array[Byte] = { - val out = new ByteArrayOutputStream() - val packer = MessagePack.newDefaultPacker(out) - packer.packValue(v) - packer.close() - out.toByteArray - } - - { - val rawStr = newRawStr() - pack(rawStr) - rawStr.toString() shouldBe str - } - - { - val rawStr = newRawStr() - pack(rawStr) - rawStr.asString().toString shouldBe str - } - } - } -} diff --git a/msgpack-core/src/test/scala/org/msgpack/value/ValueFactoryTest.scala b/msgpack-core/src/test/scala/org/msgpack/value/ValueFactoryTest.scala index cb79a575e..91552e217 100644 --- a/msgpack-core/src/test/scala/org/msgpack/value/ValueFactoryTest.scala +++ b/msgpack-core/src/test/scala/org/msgpack/value/ValueFactoryTest.scala @@ -1,10 +1,9 @@ package org.msgpack.value -import org.scalatest.FunSuite import org.msgpack.core.MessagePackSpec /** - * Created on 6/13/14. + * */ class ValueFactoryTest extends MessagePackSpec { @@ -18,35 +17,35 @@ class ValueFactoryTest extends MessagePackSpec { isBinary: Boolean = false, isArray: Boolean = false, isMap: Boolean = false, - isExtended : Boolean = false, + isExtension : Boolean = false, isRaw : Boolean = false, isNumber : Boolean = false ) { - v.isNil shouldBe isNil - v.isBoolean shouldBe isBoolean - v.isInteger shouldBe isInteger - v.isFloat shouldBe isFloat - v.isString shouldBe isString - v.isBinary shouldBe isBinary - v.isArray shouldBe isArray - v.isMap shouldBe isMap - v.isExtended shouldBe isExtended - v.isRaw shouldBe isRaw - v.isNumber shouldBe isNumber + v.isNilValue shouldBe isNil + v.isBooleanValue shouldBe isBoolean + v.isIntegerValue shouldBe isInteger + v.isFloatValue shouldBe isFloat + v.isStringValue shouldBe isString + v.isBinaryValue shouldBe isBinary + v.isArrayValue shouldBe isArray + v.isMapValue shouldBe isMap + v.isExtensionValue shouldBe isExtension + v.isRawValue shouldBe isRaw + v.isNumberValue shouldBe isNumber } "ValueFactory" should { "create valid type values" in { - isValid(ValueFactory.nilValue(), expected=ValueType.NIL, isNil = true) + isValid(ValueFactory.newNil(), expected=ValueType.NIL, isNil = true) forAll{(v:Boolean) => isValid(ValueFactory.newBoolean(v), expected=ValueType.BOOLEAN, isBoolean = true)} - forAll{(v:Int) => isValid(ValueFactory.newInt(v), expected=ValueType.INTEGER, isInteger = true, isNumber = true)} + forAll{(v:Int) => isValid(ValueFactory.newInteger(v), expected=ValueType.INTEGER, isInteger = true, isNumber = true)} forAll{(v:Float) => isValid(ValueFactory.newFloat(v), expected=ValueType.FLOAT, isFloat = true, isNumber = true)} forAll{(v:String) => isValid(ValueFactory.newString(v), expected=ValueType.STRING, isString = true, isRaw = true)} forAll{(v:Array[Byte]) => isValid(ValueFactory.newBinary(v), expected=ValueType.BINARY, isBinary = true, isRaw = true)} isValid(ValueFactory.emptyArray(), expected=ValueType.ARRAY, isArray = true) isValid(ValueFactory.emptyMap(), expected=ValueType.MAP, isMap = true) - forAll{(v:Array[Byte]) => isValid(ValueFactory.newExtendedValue(0, v), expected=ValueType.EXTENDED, isExtended=true, isRaw=true)} + forAll{(v:Array[Byte]) => isValid(ValueFactory.newExtension(0, v), expected=ValueType.EXTENSION, isExtension=true, isRaw=true)} } } diff --git a/msgpack-core/src/test/scala/org/msgpack/value/ValueTypeTest.scala b/msgpack-core/src/test/scala/org/msgpack/value/ValueTypeTest.scala index 467162447..99c0ce4d0 100644 --- a/msgpack-core/src/test/scala/org/msgpack/value/ValueTypeTest.scala +++ b/msgpack-core/src/test/scala/org/msgpack/value/ValueTypeTest.scala @@ -13,97 +13,56 @@ class ValueTypeTest extends MessagePackSpec { "ValueType" should { - "lookup ValueType from a byte value" taggedAs("code") in { + "lookup ValueType from a byte value" taggedAs ("code") in { - def check(b:Byte, tpe:ValueType) { - ValueType.valueOf(b) shouldBe tpe + def check(b: Byte, tpe: ValueType) { + MessageFormat.valueOf(b).getValueType shouldBe tpe } - for(i <- 0 until 0x7f) + for (i <- 0 until 0x7f) check(i.toByte, ValueType.INTEGER) - for(i <- 0x80 until 0x8f) + for (i <- 0x80 until 0x8f) check(i.toByte, ValueType.MAP) - for(i <- 0x90 until 0x9f) + for (i <- 0x90 until 0x9f) check(i.toByte, ValueType.ARRAY) check(NIL, ValueType.NIL) try { - ValueType.valueOf(NEVER_USED) + MessageFormat.valueOf(NEVER_USED).getValueType fail("NEVER_USED type should not have ValueType") } catch { - case e:MessageFormatException => - // OK + case e: MessageFormatException => + // OK } check(TRUE, ValueType.BOOLEAN) check(FALSE, ValueType.BOOLEAN) - for(t <- Seq(BIN8, BIN16, BIN32)) + for (t <- Seq(BIN8, BIN16, BIN32)) check(t, ValueType.BINARY) - for(t <- Seq(FIXEXT1, FIXEXT2, FIXEXT4, FIXEXT8, FIXEXT16, EXT8, EXT16, EXT32)) - check(t, ValueType.EXTENDED) + for (t <- Seq(FIXEXT1, FIXEXT2, FIXEXT4, FIXEXT8, FIXEXT16, EXT8, EXT16, EXT32)) + check(t, ValueType.EXTENSION) - for(t <- Seq(INT8, INT16, INT32, INT64, UINT8, UINT16, UINT32, UINT64)) + for (t <- Seq(INT8, INT16, INT32, INT64, UINT8, UINT16, UINT32, UINT64)) check(t, ValueType.INTEGER) - for(t <- Seq(STR8, STR16, STR32)) + for (t <- Seq(STR8, STR16, STR32)) check(t, ValueType.STRING) - for(t <- Seq(FLOAT32, FLOAT64)) + for (t <- Seq(FLOAT32, FLOAT64)) check(t, ValueType.FLOAT) - for(t <- Seq(ARRAY16, ARRAY32)) + for (t <- Seq(ARRAY16, ARRAY32)) check(t, ValueType.ARRAY) - for(i <- 0xe0 until 0xff) + for (i <- 0xe0 until 0xff) check(i.toByte, ValueType.INTEGER) } - - "lookup table" in { - - val N = 100000 - val idx = { - val b = Array.newBuilder[Byte] - for(i <- 0 until N) { - val r = Iterator.continually(Random.nextInt(256)).find(_.toByte != Code.NEVER_USED).get - b += r.toByte - } - b.result() - } - - time("lookup", repeat=100) { - block("switch") { - var i = 0 - while(i < N) { - MessageFormat.toMessageFormat(idx(i)).getValueType() - i += 1 - } - } - - block("table") { - var i = 0 - while(i < N) { - ValueType.valueOf(idx(i)) - i += 1 - } - } - - } - - } - - "support isTypeOf" in { - for(v <- ValueType.values()) { - v.isTypeOf(v.getBitMask) shouldBe true - } - } - - } } diff --git a/msgpack-core/src/test/scala/org/msgpack/value/holder/FloatHolderTest.scala b/msgpack-core/src/test/scala/org/msgpack/value/holder/FloatHolderTest.scala deleted file mode 100644 index 126d39352..000000000 --- a/msgpack-core/src/test/scala/org/msgpack/value/holder/FloatHolderTest.scala +++ /dev/null @@ -1,26 +0,0 @@ -package org.msgpack.value.holder - -import org.msgpack.core.MessagePackSpec - -/** - * - */ -class FloatHolderTest extends MessagePackSpec { - - "FloatHolder" should { - - "display value in an appropriate format" in { - - val h = new FloatHolder - val f = 0.1341f - h.setFloat(f) - h.toString shouldBe java.lang.Float.toString(f) - - val d = 0.1341341344 - h.setDouble(d) - h.toString shouldBe java.lang.Double.toString(d) - } - - } - -} diff --git a/msgpack-jackson/src/main/java/org/msgpack/jackson/dataformat/MessagePackExtendedType.java b/msgpack-jackson/src/main/java/org/msgpack/jackson/dataformat/MessagePackExtendedType.java deleted file mode 100644 index 96bfac2c8..000000000 --- a/msgpack-jackson/src/main/java/org/msgpack/jackson/dataformat/MessagePackExtendedType.java +++ /dev/null @@ -1,25 +0,0 @@ -package org.msgpack.jackson.dataformat; - -import java.nio.ByteBuffer; - -/** - * Created by komamitsu on 3/7/15. - */ -public class MessagePackExtendedType { - private final int extType; - private final ByteBuffer byteBuffer; - - public MessagePackExtendedType(int extType, ByteBuffer byteBuffer) { - this.extType = extType; - this.byteBuffer = byteBuffer.isReadOnly() ? - byteBuffer : byteBuffer.asReadOnlyBuffer(); - } - - public int extType() { - return extType; - } - - public ByteBuffer byteBuffer() { - return byteBuffer; - } -} diff --git a/msgpack-jackson/src/main/java/org/msgpack/jackson/dataformat/MessagePackParser.java b/msgpack-jackson/src/main/java/org/msgpack/jackson/dataformat/MessagePackParser.java index 45ebcae71..1ae4597da 100644 --- a/msgpack-jackson/src/main/java/org/msgpack/jackson/dataformat/MessagePackParser.java +++ b/msgpack-jackson/src/main/java/org/msgpack/jackson/dataformat/MessagePackParser.java @@ -5,23 +5,21 @@ import com.fasterxml.jackson.core.io.IOContext; import com.fasterxml.jackson.core.json.DupDetector; import com.fasterxml.jackson.core.json.JsonReadContext; -import org.msgpack.core.MessageFormat; import org.msgpack.core.MessageUnpacker; import org.msgpack.core.buffer.ArrayBufferInput; import org.msgpack.core.buffer.InputStreamBufferInput; import org.msgpack.core.buffer.MessageBufferInput; -import org.msgpack.value.ExtendedValue; -import org.msgpack.value.ValueRef; -import org.msgpack.value.NumberValue; +import org.msgpack.value.Value; +import org.msgpack.value.Variable; +import org.msgpack.value.IntegerValue; import org.msgpack.value.ValueType; -import org.msgpack.value.holder.ValueHolder; +import org.msgpack.value.ValueFactory; import java.io.IOException; import java.io.InputStream; import java.math.BigDecimal; import java.math.BigInteger; import java.util.LinkedList; -import java.util.logging.Logger; public class MessagePackParser extends ParserMinimalBase { private static final ThreadLocal> messageUnpackerHolder = @@ -31,7 +29,8 @@ public class MessagePackParser extends ParserMinimalBase { private JsonReadContext parsingContext; private final LinkedList stack = new LinkedList(); - private final ValueHolder valueHolder = new ValueHolder(); + private Value value = ValueFactory.newNil(); + private Variable var = new Variable(); private boolean isClosed; private long tokenPosition; private long currentPosition; @@ -134,33 +133,34 @@ public JsonToken nextToken() throws IOException, JsonParseException { return null; } - MessageFormat nextFormat = messageUnpacker.getNextFormat(); - ValueType valueType = nextFormat.getValueType(); + ValueType type = messageUnpacker.getNextFormat().getValueType(); // We should push a new StackItem lazily after updating the current stack. StackItem newStack = null; - switch (valueType) { + switch (type) { case NIL: messageUnpacker.unpackNil(); + value = ValueFactory.newNil(); nextToken = JsonToken.VALUE_NULL; break; case BOOLEAN: boolean b = messageUnpacker.unpackBoolean(); + value = ValueFactory.newNil(); nextToken = b ? JsonToken.VALUE_TRUE : JsonToken.VALUE_FALSE; break; case INTEGER: - messageUnpacker.unpackValue(valueHolder); + value = messageUnpacker.unpackValue(var); nextToken = JsonToken.VALUE_NUMBER_INT; break; case FLOAT: - messageUnpacker.unpackValue(valueHolder); + value = messageUnpacker.unpackValue(var); nextToken = JsonToken.VALUE_NUMBER_FLOAT; break; case STRING: - messageUnpacker.unpackValue(valueHolder); + value = messageUnpacker.unpackValue(var); if (parsingContext.inObject() && _currToken != JsonToken.FIELD_NAME) { - parsingContext.setCurrentName(valueHolder.getRef().asRaw().toString()); + parsingContext.setCurrentName(value.asRawValue().stringValue()); nextToken = JsonToken.FIELD_NAME; } else { @@ -168,17 +168,25 @@ public JsonToken nextToken() throws IOException, JsonParseException { } break; case BINARY: - messageUnpacker.unpackValue(valueHolder); - nextToken = JsonToken.VALUE_EMBEDDED_OBJECT; + value = messageUnpacker.unpackValue(var); + if (parsingContext.inObject() && _currToken != JsonToken.FIELD_NAME) { + parsingContext.setCurrentName(value.asRawValue().stringValue()); + nextToken = JsonToken.FIELD_NAME; + } + else { + nextToken = JsonToken.VALUE_EMBEDDED_OBJECT; + } break; case ARRAY: + value = ValueFactory.newNil(); newStack = new StackItemForArray(messageUnpacker.unpackArrayHeader()); break; case MAP: + value = ValueFactory.newNil(); newStack = new StackItemForObject(messageUnpacker.unpackMapHeader()); break; - case EXTENDED: - messageUnpacker.unpackValue(valueHolder); + case EXTENSION: + value = messageUnpacker.unpackValue(var); nextToken = JsonToken.VALUE_EMBEDDED_OBJECT; break; default: @@ -212,7 +220,12 @@ protected void _handleEOF() throws JsonParseException {} @Override public String getText() throws IOException, JsonParseException { // This method can be called for new BigInteger(text) - return valueHolder.getRef().toString(); + if (value.isRawValue()) { + return value.asRawValue().stringValue(); + } + else { + return value.toString(); + } } @Override @@ -237,81 +250,78 @@ public int getTextOffset() throws IOException, JsonParseException { @Override public byte[] getBinaryValue(Base64Variant b64variant) throws IOException, JsonParseException { - return valueHolder.getRef().asBinary().toByteArray(); + return value.asRawValue().getByteArray(); } @Override public Number getNumberValue() throws IOException, JsonParseException { - NumberValue numberValue = valueHolder.getRef().asNumber(); - if (numberValue.isValidInt()) { - return numberValue.toInt(); - } - else if (numberValue.isValidLong()) { - return numberValue.toLong(); - } - else { - return numberValue.toBigInteger(); + if (value.isIntegerValue()) { + IntegerValue integerValue = value.asIntegerValue(); + if (integerValue.isInIntRange()) { + return integerValue.castAsInt(); + } + else if (integerValue.isInLongRange()) { + return integerValue.castAsLong(); + } + else { + return integerValue.castAsBigInteger(); + } + } else { + return value.asNumberValue().castAsDouble(); } } @Override public int getIntValue() throws IOException, JsonParseException { - return valueHolder.getRef().asNumber().toInt(); + return value.asNumberValue().castAsInt(); } @Override public long getLongValue() throws IOException, JsonParseException { - return valueHolder.getRef().asNumber().toLong(); + return value.asNumberValue().castAsLong(); } @Override public BigInteger getBigIntegerValue() throws IOException, JsonParseException { - return valueHolder.getRef().asNumber().toBigInteger(); + return value.asNumberValue().castAsBigInteger(); } @Override public float getFloatValue() throws IOException, JsonParseException { - return valueHolder.getRef().asFloat().toFloat(); + return value.asNumberValue().castAsFloat(); } @Override public double getDoubleValue() throws IOException, JsonParseException { - return valueHolder.getRef().asFloat().toDouble(); + return value.asNumberValue().castAsDouble(); } @Override public BigDecimal getDecimalValue() throws IOException { - ValueRef ref = valueHolder.getRef(); - - if (ref.isInteger()) { - NumberValue number = ref.asNumber(); + if (value.isIntegerValue()) { + IntegerValue number = value.asIntegerValue(); //optimization to not convert the value to BigInteger unnecessarily - if (number.isValidByte() || number.isValidShort() || number.isValidInt() || number.isValidLong()) { - return BigDecimal.valueOf(number.asLong()); + if (number.isInLongRange()) { + return BigDecimal.valueOf(number.castAsLong()); } else { - return new BigDecimal(number.asBigInteger()); + return new BigDecimal(number.castAsBigInteger()); } } - else if (ref.isFloat()) { - return BigDecimal.valueOf(ref.asFloat().toDouble()); + else if (value.isFloatValue()) { + return BigDecimal.valueOf(value.asFloatValue().castAsDouble()); } else { - throw new UnsupportedOperationException("Couldn't parse value as BigDecimal. " + ref); + throw new UnsupportedOperationException("Couldn't parse value as BigDecimal. " + value); } } @Override public Object getEmbeddedObject() throws IOException, JsonParseException { - ValueRef ref = valueHolder.getRef(); - - if (ref.isBinary()) { - return ref.asBinary().toByteArray(); - } else if (ref.isExtended()) { - ExtendedValue extendedValue = ref.asExtended().toValue(); - MessagePackExtendedType extendedType = - new MessagePackExtendedType(extendedValue.getExtType(), extendedValue.toByteBuffer()); - return extendedType; + if (value.isBinaryValue()) { + return value.asBinaryValue().getByteArray(); + } else if (value.isExtensionValue()) { + return value.asExtensionValue(); } else { throw new UnsupportedOperationException(); } @@ -319,15 +329,20 @@ public Object getEmbeddedObject() throws IOException, JsonParseException { @Override public NumberType getNumberType() throws IOException, JsonParseException { - NumberValue numberValue = valueHolder.getRef().asNumber(); - if (numberValue.isValidInt()) { - return NumberType.INT; - } - else if (numberValue.isValidLong()) { - return NumberType.LONG; - } - else { - return NumberType.BIG_INTEGER; + if (value.isIntegerValue()) { + IntegerValue integerValue = value.asIntegerValue(); + if (integerValue.isInIntRange()) { + return NumberType.INT; + } + else if (integerValue.isInLongRange()) { + return NumberType.LONG; + } + else { + return NumberType.BIG_INTEGER; + } + } else { + value.asNumberValue(); + return NumberType.DOUBLE; } } diff --git a/msgpack-jackson/src/test/java/org/msgpack/jackson/dataformat/MessagePackExtendedTypeTest.java b/msgpack-jackson/src/test/java/org/msgpack/jackson/dataformat/MessagePackExtendedTypeTest.java deleted file mode 100644 index 682773a7a..000000000 --- a/msgpack-jackson/src/test/java/org/msgpack/jackson/dataformat/MessagePackExtendedTypeTest.java +++ /dev/null @@ -1,60 +0,0 @@ -package org.msgpack.jackson.dataformat; - -import org.junit.Test; - -import java.nio.ByteBuffer; - -import static org.junit.Assert.*; - -public class MessagePackExtendedTypeTest { - private void assertExtendedType(MessagePackExtendedType x, - int expectedExtType, ByteBuffer expectedByteBuffer) { - assertEquals(expectedExtType, x.extType()); - assertEquals(expectedByteBuffer, x.byteBuffer()); - assertTrue(x.byteBuffer().isReadOnly()); - } - - @Test - public void testMessagePackExtendedType() { - byte[] bs = new byte[] {0x00, (byte) 0xCC, (byte) 0xFF}; - ByteBuffer expectedByteBuffer = ByteBuffer.wrap(bs); - - int extType = 1; - MessagePackExtendedType extendedType = - new MessagePackExtendedType(extType, ByteBuffer.wrap(bs)); - assertExtendedType(extendedType, extType, expectedByteBuffer); - - extType = 2; - ByteBuffer bb = ByteBuffer.allocate(3); - bb.put(bs); - bb.position(0); - extendedType = new MessagePackExtendedType(extType, bb); - assertExtendedType(extendedType, extType, expectedByteBuffer); - - extType = 3; - bb = ByteBuffer.allocateDirect(3); - bb.put(bs); - bb.position(0); - extendedType = new MessagePackExtendedType(extType, bb); - assertExtendedType(extendedType, extType, expectedByteBuffer); - - extType = -1; - extendedType = - new MessagePackExtendedType(extType, ByteBuffer.wrap(bs).asReadOnlyBuffer()); - assertExtendedType(extendedType, extType, expectedByteBuffer); - - extType = -2; - bb = ByteBuffer.allocate(3); - bb.put(bs); - bb.position(0); - extendedType = new MessagePackExtendedType(extType, bb.asReadOnlyBuffer()); - assertExtendedType(extendedType, extType, expectedByteBuffer); - - extType = -3; - bb = ByteBuffer.allocateDirect(3); - bb.put(bs); - bb.position(0); - extendedType = new MessagePackExtendedType(extType, bb.asReadOnlyBuffer()); - assertExtendedType(extendedType, extType, expectedByteBuffer); - } -} \ No newline at end of file diff --git a/msgpack-jackson/src/test/java/org/msgpack/jackson/dataformat/MessagePackParserTest.java b/msgpack-jackson/src/test/java/org/msgpack/jackson/dataformat/MessagePackParserTest.java index 2f227cce5..74de2ba7b 100644 --- a/msgpack-jackson/src/test/java/org/msgpack/jackson/dataformat/MessagePackParserTest.java +++ b/msgpack-jackson/src/test/java/org/msgpack/jackson/dataformat/MessagePackParserTest.java @@ -9,6 +9,7 @@ import org.msgpack.core.MessagePack; import org.msgpack.core.MessagePacker; import org.msgpack.core.buffer.OutputStreamBufferOutput; +import org.msgpack.value.ExtensionValue; import java.io.*; import java.math.BigDecimal; @@ -19,6 +20,7 @@ import java.util.List; import java.util.Map; +import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertNull; @@ -67,7 +69,7 @@ public void testParserShouldReadObject() throws IOException { // #9 byte[] extPayload = {-80, -50, -25, -114, -25, 16, 60, 68}; packer.packString("ext"); - packer.packExtendedTypeHeader(0, extPayload.length); + packer.packExtensionTypeHeader((byte) 0, extPayload.length); packer.writePayload(extPayload); packer.flush(); @@ -142,9 +144,9 @@ else if (k.equals("bool")) { else if (k.equals("ext")) { // #9 bitmap |= 1 << 10; - MessagePackExtendedType extendedType = (MessagePackExtendedType) v; - assertEquals(0, extendedType.extType()); - assertEquals(ByteBuffer.wrap(extPayload), extendedType.byteBuffer()); + ExtensionValue extensionValue = (ExtensionValue) v; + assertEquals(0, extensionValue.getType()); + assertArrayEquals(extPayload, extensionValue.getData()); } } assertEquals(0x7FF, bitmap); @@ -191,7 +193,7 @@ public void testParserShouldReadArray() throws IOException { packer.packBoolean(true); // #11 byte[] extPayload = {-80, -50, -25, -114, -25, 16, 60, 68}; - packer.packExtendedTypeHeader(-1, extPayload.length); + packer.packExtensionTypeHeader((byte) -1, extPayload.length); packer.writePayload(extPayload); packer.flush(); @@ -249,9 +251,9 @@ else if (k.equals("child_map_age")) { // #10 assertEquals(true, array.get(i++)); // #11 - MessagePackExtendedType extendedType = (MessagePackExtendedType) array.get(i++); - assertEquals(-1, extendedType.extType()); - assertEquals(ByteBuffer.wrap(extPayload), extendedType.byteBuffer()); + ExtensionValue extensionValue = (ExtensionValue) array.get(i++); + assertEquals(-1, extensionValue.getType()); + assertArrayEquals(extPayload, extensionValue.getData()); } @Test