unsafeConstructor = Unsafe.class.getDeclaredConstructor();
- unsafeConstructor.setAccessible(true);
- unsafe = unsafeConstructor.newInstance();
- }
- if(unsafe == null) {
- throw new RuntimeException("Unsafe is unavailable");
- }
-
- ARRAY_BYTE_BASE_OFFSET = unsafe.arrayBaseOffset(byte[].class);
- ARRAY_BYTE_INDEX_SCALE = unsafe.arrayIndexScale(byte[].class);
-
- // Make sure the VM thinks bytes are only one byte wide
- if(ARRAY_BYTE_INDEX_SCALE != 1) {
- throw new IllegalStateException("Byte array index scale must be 1, but is " + ARRAY_BYTE_INDEX_SCALE);
- }
-
- // Find the hidden constructor for DirectByteBuffer
- directByteBufferClass = ClassLoader.getSystemClassLoader().loadClass("java.nio.DirectByteBuffer");
- Constructor directByteBufferConstructor = null;
- DirectBufferConstructorType constructorType = null;
- Method mbWrap = null;
+ boolean hasUnsafe = false;
try {
- // TODO We should use MethodHandle for Java7, which can avoid the cost of boxing with JIT optimization
- directByteBufferConstructor = directByteBufferClass.getDeclaredConstructor(long.class, int.class, Object.class);
- constructorType = DirectBufferConstructorType.ARGS_LONG_INT_REF;
+ hasUnsafe = Class.forName("sun.misc.Unsafe") != null;
}
- catch(NoSuchMethodException e0) {
- try {
- // https://android.googlesource.com/platform/libcore/+/master/luni/src/main/java/java/nio/DirectByteBuffer.java
- // DirectByteBuffer(long address, int capacity)
- directByteBufferConstructor = directByteBufferClass.getDeclaredConstructor(long.class, int.class);
- constructorType = DirectBufferConstructorType.ARGS_LONG_INT;
- } catch (NoSuchMethodException e1) {
- try {
- directByteBufferConstructor = directByteBufferClass.getDeclaredConstructor(int.class, int.class);
- constructorType = DirectBufferConstructorType.ARGS_INT_INT;
- } catch (NoSuchMethodException e2) {
- Class> aClass = Class.forName("java.nio.MemoryBlock");
- mbWrap = aClass.getDeclaredMethod("wrapFromJni", int.class, long.class);
- mbWrap.setAccessible(true);
- directByteBufferConstructor = directByteBufferClass.getDeclaredConstructor(aClass, int.class, int.class);
- constructorType = DirectBufferConstructorType.ARGS_MB_INT_INT;
- }
- }
- }
- byteBufferConstructor = directByteBufferConstructor;
- directBufferConstructorType = constructorType;
- memoryBlockWrapFromJni = mbWrap;
- if(byteBufferConstructor == null)
- throw new RuntimeException("Constructor of DirectByteBuffer is not found");
-
- byteBufferConstructor.setAccessible(true);
-
- // Check the endian of this CPU
- boolean isLittleEndian = true;
- byte[] a = new byte[8];
- // use Unsafe.putLong to an array since Unsafe.getByte is not available in Android
- unsafe.putLong(a, (long) ARRAY_BYTE_BASE_OFFSET, 0x0102030405060708L);
- switch(a[0]) {
- case 0x01:
- isLittleEndian = false;
- break;
- case 0x08:
- isLittleEndian = true;
- break;
- default:
- assert false;
+ catch (Exception e) {
}
- // We need to use reflection to find MessageBuffer implementation classes because
- // importing these classes creates TypeProfile and adds some overhead to method calls.
- String bufferClsName;
- boolean useUniversalBuffer = Boolean.parseBoolean(System.getProperty("msgpack.universal-buffer", "false"));
- if(!useUniversalBuffer && !isAndroid && isJavaAtLeast7) {
- if(isLittleEndian)
- bufferClsName = "org.msgpack.core.buffer.MessageBuffer";
- else
- bufferClsName = "org.msgpack.core.buffer.MessageBufferBE";
- }
- else {
- bufferClsName = "org.msgpack.core.buffer.MessageBufferU";
- }
+ // Detect android VM
+ boolean isAndroid = System.getProperty("java.runtime.name", "").toLowerCase().contains("android");
- Class> bufferCls = Class.forName(bufferClsName);
- msgBufferClass = bufferCls;
+ // Is Google App Engine?
+ boolean isGAE = System.getProperty("com.google.appengine.runtime.version") != null;
- Constructor> mbArrCstr = bufferCls.getDeclaredConstructor(byte[].class);
- mbArrCstr.setAccessible(true);
- mbArrConstructor = mbArrCstr;
+ // For Java6, android and JVM that has no Unsafe class, use Universal MessageBuffer
+ useUniversalBuffer =
+ Boolean.parseBoolean(System.getProperty("msgpack.universal-buffer", "false"))
+ || isAndroid
+ || isGAE
+ || !isJavaAtLeast7
+ || !hasUnsafe;
- Constructor> mbBBCstr = bufferCls.getDeclaredConstructor(ByteBuffer.class);
- mbBBCstr.setAccessible(true);
- mbBBConstructor = mbBBCstr;
+ if (!useUniversalBuffer) {
+ // Fetch theUnsafe object for Oracle and OpenJDK
+ Field field = Unsafe.class.getDeclaredField("theUnsafe");
+ field.setAccessible(true);
+ unsafeInstance = (Unsafe) field.get(null);
+ if (unsafeInstance == null) {
+ throw new RuntimeException("Unsafe is unavailable");
+ }
+ arrayByteBaseOffset = unsafeInstance.arrayBaseOffset(byte[].class);
+ int arrayByteIndexScale = unsafeInstance.arrayIndexScale(byte[].class);
- // Requires Java7
- //newMsgBuffer = MethodHandles.lookup().unreflectConstructor(mbArrCstr).asType(
- // MethodType.methodType(bufferCls, byte[].class)
- //);
+ // Make sure the VM thinks bytes are only one byte wide
+ if (arrayByteIndexScale != 1) {
+ throw new IllegalStateException("Byte array index scale must be 1, but is " + arrayByteIndexScale);
+ }
+ }
}
- catch(Exception e) {
+ catch (Exception e) {
e.printStackTrace(System.err);
- throw new RuntimeException(e);
+ // Use MessageBufferU
+ useUniversalBuffer = true;
}
- }
+ finally {
+ // Initialize the static fields
+ unsafe = unsafeInstance;
+ ARRAY_BYTE_BASE_OFFSET = arrayByteBaseOffset;
- /**
- * Wraps the difference of access methods to DirectBuffers between Android and others.
- */
- private static class DirectBufferAccess {
- static Method mGetAddress;
- static Method mCleaner;
- static Method mClean;
-
- static {
- try {
- mGetAddress = directByteBufferClass.getDeclaredMethod("address");
- mGetAddress.setAccessible(true);
-
- mCleaner = directByteBufferClass.getDeclaredMethod("cleaner");
- mCleaner.setAccessible(true);
-
- mClean = mCleaner.getReturnType().getDeclaredMethod("clean");
- mClean.setAccessible(true);
+ // Switch MessageBuffer implementation according to the environment
+ isUniversalBuffer = useUniversalBuffer;
+ String bufferClsName;
+ if (isUniversalBuffer) {
+ bufferClsName = UNIVERSAL_MESSAGE_BUFFER;
}
- catch(NoSuchMethodException e) {
- throw new RuntimeException(e);
+ else {
+ // Check the endian of this CPU
+ boolean isLittleEndian = ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN;
+ bufferClsName = isLittleEndian ? DEFAULT_MESSAGE_BUFFER : BIGENDIAN_MESSAGE_BUFFER;
}
- }
- static long getAddress(Object base) {
try {
- return (Long) mGetAddress.invoke(base);
- }
- catch(IllegalAccessException e) {
- throw new RuntimeException(e);
- }
- catch(InvocationTargetException e) {
- throw new RuntimeException(e);
- }
- }
+ // We need to use reflection here to find MessageBuffer implementation classes because
+ // importing these classes creates TypeProfile and adds some overhead to method calls.
- static void clean(Object base) {
- try {
- Object cleaner = mCleaner.invoke(base);
- mClean.invoke(cleaner);
+ // MessageBufferX (default, BE or U) class
+ Class> bufferCls = Class.forName(bufferClsName);
+
+ // MessageBufferX(byte[]) constructor
+ Constructor> mbArrCstr = bufferCls.getDeclaredConstructor(byte[].class, int.class, int.class);
+ mbArrCstr.setAccessible(true);
+ mbArrConstructor = mbArrCstr;
}
- catch(Throwable e) {
- throw new RuntimeException(e);
+ catch (Exception e) {
+ e.printStackTrace(System.err);
+ throw new RuntimeException(e); // No more fallback exists if MessageBuffer constructors are inaccessible
}
}
}
- /**
- * MessageBuffer class to use. If this machine is big-endian, it uses MessageBufferBE, which overrides some methods in this class that translate endians. If not, uses MessageBuffer.
- */
- private final static Class> msgBufferClass;
-
- private final static Constructor> mbArrConstructor;
- private final static Constructor> mbBBConstructor;
-
- // Requires Java7
- //private final static MethodHandle newMsgBuffer;
-
/**
* Base object for resolving the relative address of the raw byte array.
* If base == null, the address value is a raw memory address
@@ -251,55 +170,19 @@ static void clean(Object base) {
*/
protected final int size;
- /**
- * Reference is used to hold a reference to an object that holds the underlying memory so that it cannot be
- * released by the garbage collector.
- */
- protected final ByteBuffer reference;
-
- // TODO life-time management of this buffer
- //private AtomicInteger referenceCounter;
-
-
- static MessageBuffer newOffHeapBuffer(int length) {
- // This method is not available in Android OS
- long address = unsafe.allocateMemory(length);
- return new MessageBuffer(address, length);
- }
-
- public static MessageBuffer newDirectBuffer(int length) {
- ByteBuffer m = ByteBuffer.allocateDirect(length);
- return newMessageBuffer(m);
- }
-
- public static MessageBuffer newBuffer(int length) {
- return newMessageBuffer(new byte[length]);
+ public static MessageBuffer allocate(int length)
+ {
+ return wrap(new byte[length]);
}
- public static MessageBuffer wrap(byte[] array) {
- return newMessageBuffer(array);
+ public static MessageBuffer wrap(byte[] array)
+ {
+ return newMessageBuffer(array, 0, array.length);
}
- public static MessageBuffer wrap(ByteBuffer bb) {
- return newMessageBuffer(bb).slice(bb.position(), bb.remaining());
- }
-
- /**
- * Creates a new MessageBuffer instance backed by ByteBuffer
- *
- * @param bb
- * @return
- */
- private static MessageBuffer newMessageBuffer(ByteBuffer bb) {
- checkNotNull(bb);
- try {
- // We need to use reflection to create MessageBuffer instances in order to prevent TypeProfile generation for getInt method. TypeProfile will be
- // generated to resolve one of the method references when two or more classes overrides the method.
- return (MessageBuffer) mbBBConstructor.newInstance(bb);
- }
- catch(Exception e) {
- throw new RuntimeException(e);
- }
+ public static MessageBuffer wrap(byte[] array, int offset, int length)
+ {
+ return newMessageBuffer(array, offset, length);
}
/**
@@ -308,84 +191,47 @@ private static MessageBuffer newMessageBuffer(ByteBuffer bb) {
* @param arr
* @return
*/
- private static MessageBuffer newMessageBuffer(byte[] arr) {
+ private static MessageBuffer newMessageBuffer(byte[] arr, int off, int len)
+ {
checkNotNull(arr);
try {
- return (MessageBuffer) mbArrConstructor.newInstance(arr);
+ return (MessageBuffer) mbArrConstructor.newInstance(arr, off, len);
}
- catch(Throwable e) {
+ catch (Throwable e) {
throw new RuntimeException(e);
}
}
- public static void releaseBuffer(MessageBuffer buffer) {
- if(buffer.base instanceof byte[]) {
+ public static void releaseBuffer(MessageBuffer buffer)
+ {
+ if (isUniversalBuffer || buffer.base instanceof byte[]) {
// We have nothing to do. Wait until the garbage-collector collects this array object
}
- else if(directByteBufferClass.isInstance(buffer.base)) {
- DirectBufferAccess.clean(buffer.base);
- }
else {
// Maybe cannot reach here
unsafe.freeMemory(buffer.address);
}
}
- /**
- * Create a MessageBuffer instance from a given memory address and length
- *
- * @param address
- * @param length
- */
- MessageBuffer(long address, int length) {
- this.base = null;
- this.address = address;
- this.size = length;
- this.reference = null;
- }
-
- /**
- * Create a MessageBuffer instance from a given ByteBuffer instance
- *
- * @param bb
- */
- MessageBuffer(ByteBuffer bb) {
- if(bb.isDirect()) {
- // Direct buffer or off-heap memory
- this.base = null;
- this.address = DirectBufferAccess.getAddress(bb);
- this.size = bb.capacity();
- this.reference = bb;
- }
- else if(bb.hasArray()) {
- this.base = bb.array();
- this.address = ARRAY_BYTE_BASE_OFFSET;
- this.size = bb.array().length;
- this.reference = null;
- }
- else {
- throw new IllegalArgumentException("Only the array-backed ByteBuffer or DirectBuffer are supported");
- }
- }
-
-
/**
* Create a MessageBuffer instance from an java heap array
*
* @param arr
+ * @param offset
+ * @param length
*/
- MessageBuffer(byte[] arr) {
+ MessageBuffer(byte[] arr, int offset, int length)
+ {
this.base = arr;
- this.address = ARRAY_BYTE_BASE_OFFSET;
- this.size = arr.length;
- this.reference = null;
+ this.address = ARRAY_BYTE_BASE_OFFSET + offset;
+ this.size = length;
}
- MessageBuffer(Object base, long address, int length, ByteBuffer reference) {
+ protected MessageBuffer(Object base, long address, int length)
+ {
this.base = base;
this.address = address;
this.size = length;
- this.reference = reference;
}
/**
@@ -393,29 +239,35 @@ else if(bb.hasArray()) {
*
* @return
*/
- public int size() {
+ public int size()
+ {
return size;
}
- public MessageBuffer slice(int offset, int length) {
+ public MessageBuffer slice(int offset, int length)
+ {
// TODO ensure deleting this slice does not collapse this MessageBuffer
- if(offset == 0 && length == size())
+ if (offset == 0 && length == size()) {
return this;
+ }
else {
checkArgument(offset + length <= size());
- return new MessageBuffer(base, address + offset, length, reference);
+ return new MessageBuffer(base, address + offset, length);
}
}
- public byte getByte(int index) {
+ public byte getByte(int index)
+ {
return unsafe.getByte(base, address + index);
}
- public boolean getBoolean(int index) {
+ public boolean getBoolean(int index)
+ {
return unsafe.getBoolean(base, address + index);
}
- public short getShort(int index) {
+ public short getShort(int index)
+ {
short v = unsafe.getShort(base, address + index);
return Short.reverseBytes(v);
}
@@ -426,46 +278,56 @@ public short getShort(int index) {
* @param index
* @return
*/
- public int getInt(int index) {
+ public int getInt(int index)
+ {
// Reading little-endian value
int i = unsafe.getInt(base, address + index);
// Reversing the endian
return Integer.reverseBytes(i);
}
- public float getFloat(int index) {
+ public float getFloat(int index)
+ {
return Float.intBitsToFloat(getInt(index));
}
- public long getLong(int index) {
+ public long getLong(int index)
+ {
long l = unsafe.getLong(base, address + index);
return Long.reverseBytes(l);
}
- public double getDouble(int index) {
+ public double getDouble(int index)
+ {
return Double.longBitsToDouble(getLong(index));
}
- public void getBytes(int index, byte[] dst, int dstOffset, int length) {
+ public void getBytes(int index, byte[] dst, int dstOffset, int length)
+ {
unsafe.copyMemory(base, address + index, dst, ARRAY_BYTE_BASE_OFFSET + dstOffset, length);
}
- public void getBytes(int index, int len, ByteBuffer dst) {
- if(dst.remaining() > len)
+ public void getBytes(int index, int len, ByteBuffer dst)
+ {
+ if (dst.remaining() < len) {
throw new BufferOverflowException();
- ByteBuffer src = toByteBuffer(index, len);
+ }
+ ByteBuffer src = sliceAsByteBuffer(index, len);
dst.put(src);
}
- public void putByte(int index, byte v) {
+ public void putByte(int index, byte v)
+ {
unsafe.putByte(base, address + index, v);
}
- public void putBoolean(int index, boolean v) {
+ public void putBoolean(int index, boolean v)
+ {
unsafe.putBoolean(base, address + index, v);
}
- public void putShort(int index, short v) {
+ public void putShort(int index, short v)
+ {
v = Short.reverseBytes(v);
unsafe.putShort(base, address + index, v);
}
@@ -476,51 +338,59 @@ public void putShort(int index, short v) {
* @param index
* @param v
*/
- public void putInt(int index, int v) {
+ public void putInt(int index, int v)
+ {
// Reversing the endian
v = Integer.reverseBytes(v);
unsafe.putInt(base, address + index, v);
}
- public void putFloat(int index, float v) {
+ public void putFloat(int index, float v)
+ {
putInt(index, Float.floatToRawIntBits(v));
}
- public void putLong(int index, long l) {
+ public void putLong(int index, long l)
+ {
// Reversing the endian
l = Long.reverseBytes(l);
unsafe.putLong(base, address + index, l);
}
- public void putDouble(int index, double v) {
+ public void putDouble(int index, double v)
+ {
putLong(index, Double.doubleToRawLongBits(v));
}
- public void putBytes(int index, byte[] src, int srcOffset, int length) {
+ public void putBytes(int index, byte[] src, int srcOffset, int length)
+ {
unsafe.copyMemory(src, ARRAY_BYTE_BASE_OFFSET + srcOffset, base, address + index, length);
}
- public void putByteBuffer(int index, ByteBuffer src, int len) {
+ public void putByteBuffer(int index, ByteBuffer src, int len)
+ {
assert (len <= src.remaining());
+ assert (!isUniversalBuffer);
- if(src.isDirect()) {
+ if (src.isDirect()) {
unsafe.copyMemory(null, DirectBufferAccess.getAddress(src) + src.position(), base, address + index, len);
+ src.position(src.position() + len);
}
- else if(src.hasArray()) {
+ else if (src.hasArray()) {
byte[] srcArray = src.array();
unsafe.copyMemory(srcArray, ARRAY_BYTE_BASE_OFFSET + src.position(), base, address + index, len);
+ src.position(src.position() + len);
}
else {
- if(base != null) {
+ if (base != null) {
src.get((byte[]) base, index, len);
}
else {
- for(int i = 0; i < len; ++i) {
+ for (int i = 0; i < len; ++i) {
unsafe.putByte(base, address + index, src.get());
}
}
}
- src.position(src.position() + len);
}
/**
@@ -530,36 +400,9 @@ else if(src.hasArray()) {
* @param length
* @return
*/
- public ByteBuffer toByteBuffer(int index, int length) {
- if(hasArray()) {
- return ByteBuffer.wrap((byte[]) base, (int) ((address - ARRAY_BYTE_BASE_OFFSET) + index), length);
- }
- try {
- ByteBuffer bb = null;
- switch (directBufferConstructorType) {
- case ARGS_LONG_INT_REF:
- bb = (ByteBuffer) byteBufferConstructor.newInstance(address + index, length, reference);
- break;
- case ARGS_LONG_INT:
- bb = (ByteBuffer) byteBufferConstructor.newInstance(address + index, length);
- break;
- case ARGS_INT_INT:
- bb = (ByteBuffer) byteBufferConstructor.newInstance((int)address + index, length);
- break;
- case ARGS_MB_INT_INT:
- bb = (ByteBuffer) byteBufferConstructor.newInstance(
- memoryBlockWrapFromJni.invoke(null, address + index, length),
- length, 0);
- break;
- default:
- throw new IllegalStateException("Unexpected value");
- }
- return bb;
- }
- catch(Throwable e) {
- // Convert checked exception to unchecked exception
- throw new RuntimeException(e);
- }
+ public ByteBuffer sliceAsByteBuffer(int index, int length)
+ {
+ return ByteBuffer.wrap((byte[]) base, (int) ((address - ARRAY_BYTE_BASE_OFFSET) + index), length);
}
/**
@@ -567,8 +410,9 @@ public ByteBuffer toByteBuffer(int index, int length) {
*
* @return
*/
- public ByteBuffer toByteBuffer() {
- return toByteBuffer(0, size());
+ public ByteBuffer sliceAsByteBuffer()
+ {
+ return sliceAsByteBuffer(0, size());
}
/**
@@ -576,45 +420,21 @@ public ByteBuffer toByteBuffer() {
*
* @return
*/
- public byte[] toByteArray() {
+ public byte[] toByteArray()
+ {
byte[] b = new byte[size()];
unsafe.copyMemory(base, address, b, ARRAY_BYTE_BASE_OFFSET, size());
return b;
}
- @Insecure
- public boolean hasArray() {
- return base instanceof byte[];
- }
-
- @Insecure
- public byte[] getArray() {
+ public byte[] array()
+ {
return (byte[]) base;
}
- @Insecure
- public Object getBase() {
- return base;
- }
-
- @Insecure
- public long getAddress() {
- return address;
- }
-
- @Insecure
- public int offset() {
- if(hasArray()) {
- return (int) address - ARRAY_BYTE_BASE_OFFSET;
- }
- else {
- return 0;
- }
- }
-
- @Insecure
- public ByteBuffer getReference() {
- return reference;
+ public int arrayOffset()
+ {
+ return (int) address - ARRAY_BYTE_BASE_OFFSET;
}
/**
@@ -625,18 +445,20 @@ public ByteBuffer getReference() {
* @param offset
* @param length
*/
- public void copyTo(int index, MessageBuffer dst, int offset, int length) {
+ public void copyTo(int index, MessageBuffer dst, int offset, int length)
+ {
unsafe.copyMemory(base, address + index, dst.base, dst.address + offset, length);
}
- public String toHexString(int offset, int length) {
+ public String toHexString(int offset, int length)
+ {
StringBuilder s = new StringBuilder();
- for(int i = offset; i < length; ++i) {
- if(i != offset)
+ for (int i = offset; i < length; ++i) {
+ if (i != offset) {
s.append(" ");
+ }
s.append(String.format("%02x", getByte(i)));
}
return s.toString();
}
-
}
diff --git a/msgpack-core/src/main/java/org/msgpack/core/buffer/MessageBufferBE.java b/msgpack-core/src/main/java/org/msgpack/core/buffer/MessageBufferBE.java
index e879e4c81..1326b396e 100644
--- a/msgpack-core/src/main/java/org/msgpack/core/buffer/MessageBufferBE.java
+++ b/msgpack-core/src/main/java/org/msgpack/core/buffer/MessageBufferBE.java
@@ -1,7 +1,20 @@
+//
+// 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.buffer;
-import java.nio.ByteBuffer;
-
import static org.msgpack.core.Preconditions.checkArgument;
/**
@@ -9,70 +22,82 @@
* The specification of Message Pack demands writing short/int/float/long/double values in the big-endian format.
* In the big-endian machine, we do not need to swap the byte order.
*/
-public class MessageBufferBE extends MessageBuffer {
-
- MessageBufferBE(ByteBuffer bb) {
- super(bb);
+public class MessageBufferBE
+ extends MessageBuffer
+{
+ MessageBufferBE(byte[] arr, int offset, int length)
+ {
+ super(arr, offset, length);
}
- private MessageBufferBE(Object base, long address, int length, ByteBuffer reference) {
- super(base, address, length, reference);
+ private MessageBufferBE(Object base, long address, int length)
+ {
+ super(base, address, length);
}
@Override
- public MessageBufferBE slice(int offset, int length) {
- if(offset == 0 && length == size())
+ public MessageBufferBE slice(int offset, int length)
+ {
+ if (offset == 0 && length == size()) {
return this;
+ }
else {
checkArgument(offset + length <= size());
- return new MessageBufferBE(base, address + offset, length, reference);
+ return new MessageBufferBE(base, address + offset, length);
}
}
@Override
- public short getShort(int index) {
+ public short getShort(int index)
+ {
return unsafe.getShort(base, address + index);
}
@Override
- public int getInt(int index) {
+ public int getInt(int index)
+ {
// We can simply return the integer value as big-endian value
return unsafe.getInt(base, address + index);
}
- public long getLong(int index) {
+ public long getLong(int index)
+ {
return unsafe.getLong(base, address + index);
}
@Override
- public float getFloat(int index) {
+ public float getFloat(int index)
+ {
return unsafe.getFloat(base, address + index);
}
@Override
- public double getDouble(int index) {
+ public double getDouble(int index)
+ {
return unsafe.getDouble(base, address + index);
}
@Override
- public void putShort(int index, short v) {
+ public void putShort(int index, short v)
+ {
unsafe.putShort(base, address + index, v);
}
@Override
- public void putInt(int index, int v) {
+ public void putInt(int index, int v)
+ {
unsafe.putInt(base, address + index, v);
}
@Override
- public void putLong(int index, long v) {
+ public void putLong(int index, long v)
+ {
unsafe.putLong(base, address + index, v);
}
@Override
- public void putDouble(int index, double v) {
+ public void putDouble(int index, double v)
+ {
unsafe.putDouble(base, address + index, v);
}
-
-
}
diff --git a/msgpack-core/src/main/java/org/msgpack/core/buffer/MessageBufferInput.java b/msgpack-core/src/main/java/org/msgpack/core/buffer/MessageBufferInput.java
index 447c71798..46eea243e 100644
--- a/msgpack-core/src/main/java/org/msgpack/core/buffer/MessageBufferInput.java
+++ b/msgpack-core/src/main/java/org/msgpack/core/buffer/MessageBufferInput.java
@@ -1,3 +1,18 @@
+//
+// 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.buffer;
import java.io.Closeable;
@@ -6,16 +21,17 @@
/**
* Provides a sequence of MessageBuffers that contains message packed data.
*/
-public interface MessageBufferInput extends Closeable {
-
+public interface MessageBufferInput
+ extends Closeable
+{
/**
* Get a next buffer to read.
- * @return the next MessageBuffer, or null if no more buffer is available.
+ *
+ * When this method is called, the formally allocated buffer can be safely discarded.
+ *
+ * @return the next MessageBuffer, or return null if no more buffer is available.
* @throws IOException when error occurred when reading the data
*/
- public MessageBuffer next() throws IOException;
-
-
+ MessageBuffer next()
+ throws IOException;
}
-
-
diff --git a/msgpack-core/src/main/java/org/msgpack/core/buffer/MessageBufferOutput.java b/msgpack-core/src/main/java/org/msgpack/core/buffer/MessageBufferOutput.java
index 4b529c44f..024414bae 100644
--- a/msgpack-core/src/main/java/org/msgpack/core/buffer/MessageBufferOutput.java
+++ b/msgpack-core/src/main/java/org/msgpack/core/buffer/MessageBufferOutput.java
@@ -1,33 +1,76 @@
+//
+// 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.buffer;
-
import java.io.Closeable;
import java.io.IOException;
+import java.io.Flushable;
/**
- * Provides a sequence of MessageBuffers for packing the input data
+ * Provides a buffered output stream for packing objects
*/
-public interface MessageBufferOutput extends Closeable {
-
+public interface MessageBufferOutput
+ extends Closeable, Flushable
+{
/**
- * Retrieves the next buffer for writing message packed data
+ * Allocates the next buffer for writing message packed data.
+ * If the previously allocated buffer is not flushed yet, this next method should discard
+ * it without writing it.
*
- * @param bufferSize the buffer size to retrieve
+ * @param minimumSize the mimium required buffer size to allocate
* @return
* @throws IOException
*/
- public MessageBuffer next(int bufferSize) throws IOException;
+ MessageBuffer next(int minimumSize)
+ throws IOException;
/**
- * Output the buffer contents. If you need to output a part of the
- * buffer use {@link MessageBuffer#slice(int, int)}
- * @param buf
+ * Flushes the previously allocated buffer.
+ * This method is not always called because next method also flushes previously allocated buffer.
+ * This method is called when write method is called or application wants to control the timing of flush.
+ *
+ * @param length the size of buffer to flush
* @throws IOException
*/
- public void flush(MessageBuffer buf) throws IOException;
-
-}
-
-
+ void writeBuffer(int length)
+ throws IOException;
+ /**
+ * Writes an external payload data.
+ * This method should follow semantics of OutputStream.
+ *
+ * @param buffer the data to write
+ * @param offset the start offset in the data
+ * @param length the number of bytes to write
+ * @return
+ * @throws IOException
+ */
+ void write(byte[] buffer, int offset, int length)
+ throws IOException;
+ /**
+ * Writes an external payload data.
+ * This buffer is given - this MessageBufferOutput owns the buffer and may modify contents of the buffer. Contents of this buffer won't be modified by the caller.
+ *
+ * @param buffer the data to add
+ * @param offset the start offset in the data
+ * @param length the number of bytes to add
+ * @return
+ * @throws IOException
+ */
+ void add(byte[] buffer, int offset, int length)
+ throws IOException;
+}
diff --git a/msgpack-core/src/main/java/org/msgpack/core/buffer/MessageBufferU.java b/msgpack-core/src/main/java/org/msgpack/core/buffer/MessageBufferU.java
index 8ce58aa03..1e8783738 100644
--- a/msgpack-core/src/main/java/org/msgpack/core/buffer/MessageBufferU.java
+++ b/msgpack-core/src/main/java/org/msgpack/core/buffer/MessageBufferU.java
@@ -1,36 +1,60 @@
+//
+// 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.buffer;
-
import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import static org.msgpack.core.Preconditions.*;
+import static org.msgpack.core.Preconditions.checkArgument;
/**
* Universal MessageBuffer implementation supporting Java6 and Android.
* This buffer always uses ByteBuffer-based memory access
*/
-public class MessageBufferU extends MessageBuffer {
+public class MessageBufferU
+ extends MessageBuffer
+{
+ private final ByteBuffer wrap;
- MessageBufferU(ByteBuffer bb) {
- super(null, 0L, bb.capacity(), bb.order(ByteOrder.BIG_ENDIAN));
- checkNotNull(reference);
+ MessageBufferU(byte[] arr, int offset, int length)
+ {
+ super(arr, offset, length);
+ ByteBuffer bb = ByteBuffer.wrap(arr);
+ bb.position(offset);
+ bb.limit(offset + length);
+ this.wrap = bb.slice();
}
- MessageBufferU(byte[] arr) {
- this(ByteBuffer.wrap(arr));
+ private MessageBufferU(Object base, long address, int length, ByteBuffer wrap)
+ {
+ super(base, address, length);
+ this.wrap = wrap;
}
@Override
- public MessageBufferU slice(int offset, int length) {
- if(offset == 0 && length == size())
+ public MessageBufferU slice(int offset, int length)
+ {
+ if (offset == 0 && length == size()) {
return this;
+ }
else {
checkArgument(offset + length <= size());
try {
- reference.position(offset);
- reference.limit(offset + length);
- return new MessageBufferU(reference.slice());
+ wrap.position(offset);
+ wrap.limit(offset + length);
+ return new MessageBufferU(base, address + offset, length, wrap.slice());
}
finally {
resetBufferPosition();
@@ -38,99 +62,134 @@ public MessageBufferU slice(int offset, int length) {
}
}
- private void resetBufferPosition() {
- reference.position(0);
- reference.limit(size);
+ private void resetBufferPosition()
+ {
+ wrap.position(0);
+ wrap.limit(size);
}
@Override
- public byte getByte(int index) {
- return reference.get(index);
+ public byte getByte(int index)
+ {
+ return wrap.get(index);
}
+
@Override
- public boolean getBoolean(int index) {
- return reference.get(index) != 0;
+ public boolean getBoolean(int index)
+ {
+ return wrap.get(index) != 0;
}
+
@Override
- public short getShort(int index) {
- return reference.getShort(index);
+ public short getShort(int index)
+ {
+ return wrap.getShort(index);
}
+
@Override
- public int getInt(int index) {
- return reference.getInt(index);
+ public int getInt(int index)
+ {
+ return wrap.getInt(index);
}
+
@Override
- public float getFloat(int index) {
- return reference.getFloat(index);
+ public float getFloat(int index)
+ {
+ return wrap.getFloat(index);
}
+
@Override
- public long getLong(int index) {
- return reference.getLong(index);
+ public long getLong(int index)
+ {
+ return wrap.getLong(index);
}
+
@Override
- public double getDouble(int index) {
- return reference.getDouble(index);
+ public double getDouble(int index)
+ {
+ return wrap.getDouble(index);
}
+
@Override
- public void getBytes(int index, int len, ByteBuffer dst) {
+ public void getBytes(int index, int len, ByteBuffer dst)
+ {
try {
- reference.position(index);
- reference.limit(index + len);
- dst.put(reference);
+ wrap.position(index);
+ wrap.limit(index + len);
+ dst.put(wrap);
}
finally {
resetBufferPosition();
}
}
+
@Override
- public void putByte(int index, byte v) {
- reference.put(index, v);
+ public void putByte(int index, byte v)
+ {
+ wrap.put(index, v);
}
+
@Override
- public void putBoolean(int index, boolean v) {
- reference.put(index, v ? (byte) 1 : (byte) 0);
+ public void putBoolean(int index, boolean v)
+ {
+ wrap.put(index, v ? (byte) 1 : (byte) 0);
}
+
@Override
- public void putShort(int index, short v) {
- reference.putShort(index, v);
+ public void putShort(int index, short v)
+ {
+ wrap.putShort(index, v);
}
+
@Override
- public void putInt(int index, int v) {
- reference.putInt(index, v);
+ public void putInt(int index, int v)
+ {
+ wrap.putInt(index, v);
}
+
@Override
- public void putFloat(int index, float v) {
- reference.putFloat(index, v);
+ public void putFloat(int index, float v)
+ {
+ wrap.putFloat(index, v);
}
+
@Override
- public void putLong(int index, long l) {
- reference.putLong(index, l);
+ public void putLong(int index, long l)
+ {
+ wrap.putLong(index, l);
}
+
@Override
- public void putDouble(int index, double v) {
- reference.putDouble(index, v);
+ public void putDouble(int index, double v)
+ {
+ wrap.putDouble(index, v);
}
+
@Override
- public ByteBuffer toByteBuffer(int index, int length) {
+ public ByteBuffer sliceAsByteBuffer(int index, int length)
+ {
try {
- reference.position(index);
- reference.limit(index + length);
- return reference.slice();
+ wrap.position(index);
+ wrap.limit(index + length);
+ return wrap.slice();
}
finally {
resetBufferPosition();
}
}
+
@Override
- public ByteBuffer toByteBuffer() {
- return toByteBuffer(0, size);
+ public ByteBuffer sliceAsByteBuffer()
+ {
+ return sliceAsByteBuffer(0, size);
}
@Override
- public void getBytes(int index, byte[] dst, int dstOffset, int length) {
+ public void getBytes(int index, byte[] dst, int dstOffset, int length)
+ {
try {
- reference.position(index);
- reference.get(dst, dstOffset, length);
+ wrap.position(index);
+ wrap.get(dst, dstOffset, length);
}
finally {
resetBufferPosition();
@@ -138,18 +197,20 @@ public void getBytes(int index, byte[] dst, int dstOffset, int length) {
}
@Override
- public void putByteBuffer(int index, ByteBuffer src, int len) {
+ public void putByteBuffer(int index, ByteBuffer src, int len)
+ {
assert (len <= src.remaining());
- if(src.hasArray()) {
- putBytes(index, src.array(), src.position(), len);
+ if (src.hasArray()) {
+ putBytes(index, src.array(), src.position() + src.arrayOffset(), len);
src.position(src.position() + len);
}
else {
int prevSrcLimit = src.limit();
try {
src.limit(src.position() + len);
- reference.put(src);
+ wrap.position(index);
+ wrap.put(src);
}
finally {
src.limit(prevSrcLimit);
@@ -158,10 +219,11 @@ public void putByteBuffer(int index, ByteBuffer src, int len) {
}
@Override
- public void putBytes(int index, byte[] src, int srcOffset, int length) {
+ public void putBytes(int index, byte[] src, int srcOffset, int length)
+ {
try {
- reference.position(index);
- reference.put(src, srcOffset, length);
+ wrap.position(index);
+ wrap.put(src, srcOffset, length);
}
finally {
resetBufferPosition();
@@ -169,17 +231,20 @@ public void putBytes(int index, byte[] src, int srcOffset, int length) {
}
@Override
- public void copyTo(int index, MessageBuffer dst, int offset, int length) {
+ public void copyTo(int index, MessageBuffer dst, int offset, int length)
+ {
try {
- reference.position(index);
- dst.putByteBuffer(offset, reference, length);
+ wrap.position(index);
+ dst.putByteBuffer(offset, wrap, length);
}
finally {
resetBufferPosition();
}
}
+
@Override
- public byte[] toByteArray() {
+ public byte[] toByteArray()
+ {
byte[] b = new byte[size()];
getBytes(0, b, 0, b.length);
return b;
diff --git a/msgpack-core/src/main/java/org/msgpack/core/buffer/OutputStreamBufferOutput.java b/msgpack-core/src/main/java/org/msgpack/core/buffer/OutputStreamBufferOutput.java
index 768c3621d..08fd3960b 100644
--- a/msgpack-core/src/main/java/org/msgpack/core/buffer/OutputStreamBufferOutput.java
+++ b/msgpack-core/src/main/java/org/msgpack/core/buffer/OutputStreamBufferOutput.java
@@ -1,3 +1,18 @@
+//
+// 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.buffer;
import java.io.IOException;
@@ -8,59 +23,79 @@
/**
* MessageBufferOutput adapter for {@link java.io.OutputStream}.
*/
-public class OutputStreamBufferOutput implements MessageBufferOutput {
-
+public class OutputStreamBufferOutput
+ implements MessageBufferOutput
+{
private OutputStream out;
private MessageBuffer buffer;
- private byte[] tmpBuf;
- public OutputStreamBufferOutput(OutputStream out) {
+ public OutputStreamBufferOutput(OutputStream out)
+ {
+ this(out, 8192);
+ }
+
+ public OutputStreamBufferOutput(OutputStream out, int bufferSize)
+ {
this.out = checkNotNull(out, "output is null");
+ this.buffer = MessageBuffer.allocate(bufferSize);
}
/**
- * Reset Stream. This method doesn't close the old resource.
+ * Reset Stream. This method doesn't close the old stream.
+ *
* @param out new stream
- * @return the old resource
+ * @return the old stream
*/
- public OutputStream reset(OutputStream out) throws IOException {
+ public OutputStream reset(OutputStream out)
+ throws IOException
+ {
OutputStream old = this.out;
this.out = out;
return old;
}
@Override
- public MessageBuffer next(int bufferSize) throws IOException {
- if(buffer == null || buffer.size != bufferSize) {
- return buffer = MessageBuffer.newBuffer(bufferSize);
- }
- else {
- return buffer;
+ public MessageBuffer next(int mimimumSize)
+ throws IOException
+ {
+ if (buffer.size() < mimimumSize) {
+ buffer = MessageBuffer.allocate(mimimumSize);
}
+ return buffer;
}
@Override
- public void flush(MessageBuffer buf) throws IOException {
- int writeLen = buf.size();
- if(buf.hasArray()) {
- out.write(buf.getArray(), buf.offset(), writeLen);
- }
- else {
- if(tmpBuf == null || tmpBuf.length < writeLen) {
- tmpBuf = new byte[writeLen];
- }
- buf.getBytes(0, tmpBuf, 0, writeLen);
- out.write(tmpBuf, 0, writeLen);
- }
+ public void writeBuffer(int length)
+ throws IOException
+ {
+ write(buffer.array(), buffer.arrayOffset(), length);
}
@Override
- public void close() throws IOException {
- try {
- out.flush();
- }
- finally {
- out.close();
- }
+ public void write(byte[] buffer, int offset, int length)
+ throws IOException
+ {
+ out.write(buffer, offset, length);
+ }
+
+ @Override
+ public void add(byte[] buffer, int offset, int length)
+ throws IOException
+ {
+ write(buffer, offset, length);
+ }
+
+ @Override
+ public void close()
+ throws IOException
+ {
+ out.close();
+ }
+
+ @Override
+ public void flush()
+ throws IOException
+ {
+ out.flush();
}
}
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..4d7a6e8c2 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.Iterator;
+import java.util.List;
+
/**
- * 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..c66f7a67c 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,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.
-*/
-public interface BinaryValue extends RawValue {
- BinaryValue toValue();
+ * 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
+{
}
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..6ccf5c9ef 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,30 @@
+//
+// 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.
-*/
-public interface BooleanValue extends Value {
- public boolean toBoolean();
- public BooleanValue toValue();
+ * 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
+{
+ /**
+ * 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..5a076ecbc 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,17 @@
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..dbaf73a18 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,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.
-*/
-public interface FloatValue extends NumberValue {
- FloatValue toValue();
+ * 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
+{
}
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..9301c2eb8
--- /dev/null
+++ b/msgpack-core/src/main/java/org/msgpack/value/ImmutableArrayValue.java
@@ -0,0 +1,35 @@
+//
+// 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.Iterator;
+import java.util.List;
+
+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..475241a57
--- /dev/null
+++ b/msgpack-core/src/main/java/org/msgpack/value/ImmutableBinaryValue.java
@@ -0,0 +1,21 @@
+//
+// 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..dd2afad43
--- /dev/null
+++ b/msgpack-core/src/main/java/org/msgpack/value/ImmutableBooleanValue.java
@@ -0,0 +1,21 @@
+//
+// 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..5e984db05
--- /dev/null
+++ b/msgpack-core/src/main/java/org/msgpack/value/ImmutableExtensionValue.java
@@ -0,0 +1,21 @@
+//
+// 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..7105483d1
--- /dev/null
+++ b/msgpack-core/src/main/java/org/msgpack/value/ImmutableFloatValue.java
@@ -0,0 +1,21 @@
+//
+// 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..3482583ff
--- /dev/null
+++ b/msgpack-core/src/main/java/org/msgpack/value/ImmutableIntegerValue.java
@@ -0,0 +1,21 @@
+//
+// 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..cc3122f03
--- /dev/null
+++ b/msgpack-core/src/main/java/org/msgpack/value/ImmutableMapValue.java
@@ -0,0 +1,21 @@
+//
+// 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..8a7857287
--- /dev/null
+++ b/msgpack-core/src/main/java/org/msgpack/value/ImmutableNilValue.java
@@ -0,0 +1,21 @@
+//
+// 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..42afcf304
--- /dev/null
+++ b/msgpack-core/src/main/java/org/msgpack/value/ImmutableNumberValue.java
@@ -0,0 +1,21 @@
+//
+// 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..36698dbeb
--- /dev/null
+++ b/msgpack-core/src/main/java/org/msgpack/value/ImmutableRawValue.java
@@ -0,0 +1,21 @@
+//
+// 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..6e3f95360
--- /dev/null
+++ b/msgpack-core/src/main/java/org/msgpack/value/ImmutableStringValue.java
@@ -0,0 +1,21 @@
+//
+// 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..6a5740029
--- /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;
+
+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..8480751c4 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,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;
+import org.msgpack.core.MessageFormat;
+
+import java.math.BigInteger;
+
/**
-* Created on 5/30/14.
-*/
-public interface IntegerValue extends NumberValue {
- IntegerValue toValue();
+ * 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
+{
+ /**
+ * 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 most succinct MessageFormat type to represent this integer value.
+ * @return
+ */
+ MessageFormat mostSuccinctMessageFormat();
+
+ /**
+ * 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 asByte();
+
+ /**
+ * 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 asShort();
+
+ /**
+ * 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 asInt();
+
+ /**
+ * 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 asLong();
+
+ /**
+ * Returns the value as a {@code BigInteger}.
+ */
+ BigInteger asBigInteger();
}
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..fa7f55c8d 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,54 @@
+//
+// 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.Collection;
import java.util.Map;
+import java.util.Set;
/**
-* 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..8f5835001 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,24 @@
+//
+// 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();
+public interface NilValue
+ extends Value
+{
}
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..3e5bd75e0 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,65 @@
+//
+// 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.
-*/
-public interface NumberValue extends Value {
+ * The base interface {@code NumberValue} of {@code IntegerValue} and {@code FloatValue}. To extract primitive type values, call toXXX methods, which may lose some information by rounding or truncation.
+ *
+ * @see org.msgpack.value.IntegerValue
+ * @see org.msgpack.value.FloatValue
+ */
+public interface NumberValue
+ extends Value
+{
+ /**
+ * Represent this value as a byte value, which may involve rounding or truncation of the original value.
+ * the value.
+ */
+ byte toByte();
/**
- * 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
+ * Represent this value as a short value, which may involve rounding or truncation of the original value.
*/
- public boolean isValidByte();
+ short toShort();
/**
- * 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
+ * Represent this value as an int value, which may involve rounding or truncation of the original value.
+ * value.
*/
- public boolean isValidShort();
+ int toInt();
/**
- * 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
+ * Represent this value as a long value, which may involve rounding or truncation of the original value.
*/
- public boolean isValidInt();
+ long toLong();
/**
- * 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
+ * Represent this value as a BigInteger, which may involve rounding or truncation of the original value.
*/
- public boolean isValidLong();
+ BigInteger toBigInteger();
/**
- * 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 32-bit float value, which may involve rounding or truncation of the original value.
*/
- public boolean isWhole();
+ float toFloat();
/**
- * 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.
- */
- 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.
+ * Represent this value as a 64-bit double value, which may involve rounding or truncation of the original 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();
-
- /**
- * 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};
- */
- public byte asByte() throws MessageOverflowException;
-
- /**
- * 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}
- */
- public short asShort() throws MessageOverflowException;
-
- /**
- * 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}
- */
- public int asInt() throws MessageOverflowException;
-
- /**
- * 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}
- */
- public long asLong() throws MessageOverflowException;
-
- /**
- * Convert this value into a BigInteger value.
- * @return
- * @throws org.msgpack.core.MessageOverflowException
- */
- public BigInteger asBigInteger() throws MessageOverflowException;
-
+ double toDouble();
}
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..8857b5340 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;
/**
- * 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();
+public interface RawValue
+ extends Value
+{
+ /**
+ * Returns the value as {@code byte[]}.
+ *
+ * This method copies the byte array.
+ */
+ byte[] asByteArray();
+
+ /**
+ * 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 asByteBuffer();
- @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 asString();
- public RawValue toValue();
+ /**
+ * Returns the value as {@code String}.
+ *
+ * This method replaces an invalid UTF-8 byte sequence with U+FFFD replacement character.
+ */
+ String toString();
}
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..0c812d58d 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,30 @@
+//
+// 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 asString()} method throws {@code MessageTypeStringCodingException} if the value includes invalid byte sequence. {@code toJson()} method replaces an invalid byte sequence with U+FFFD replacement character.
+ *
+ * @see org.msgpack.value.RawValue
*/
-public interface StringValue extends RawValue {
- public StringValue toValue();
+public interface StringValue
+ extends RawValue
+{
}
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..2fae838b4 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,248 @@
//
package org.msgpack.value;
+import org.msgpack.core.MessagePacker;
-import org.msgpack.core.*;
+import java.io.IOException;
/**
- * Value is a holder of a message-packed value.
+ * Value is an implementation of MessagePack type system. To retrieve values from a Value object,
+ * You need to check its {@link ValueType} then call an appropriate asXXXValue method.
+ *
+ *
+ *
*/
-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();
- public ArrayValue asArrayValue() throws MessageTypeException;
- public MapValue asMapValue() throws MessageTypeException;
+ /**
+ * 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();
+
+ /**
+ * 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);
+
+ /**
+ * Returns json representation of this Value.
+ *
+ * Following behavior is not configurable at this release and they might be changed at future releases:
+ *
+ * * if a key of MapValue is not string, the key is converted to a string using toString method.
+ * * NaN and Infinity of DoubleValue are converted to null.
+ * * ExtensionValue is converted to a 2-element array where first element is a number and second element is the data encoded in hex.
+ * * BinaryValue is converted to a string using UTF-8 encoding. Invalid byte sequence is replaced with U+FFFD replacement character.
+ * * Invalid UTF-8 byte sequences in StringValue is replaced with U+FFFD replacement character
+ */
+ String toJson();
}
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..b0ffc932a 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,213 @@
//
package org.msgpack.value;
-import org.msgpack.value.impl.*;
+import org.msgpack.value.impl.ImmutableArrayValueImpl;
+import org.msgpack.value.impl.ImmutableBigIntegerValueImpl;
+import org.msgpack.value.impl.ImmutableBinaryValueImpl;
+import org.msgpack.value.impl.ImmutableBooleanValueImpl;
+import org.msgpack.value.impl.ImmutableDoubleValueImpl;
+import org.msgpack.value.impl.ImmutableExtensionValueImpl;
+import org.msgpack.value.impl.ImmutableLongValueImpl;
+import org.msgpack.value.impl.ImmutableMapValueImpl;
+import org.msgpack.value.impl.ImmutableNilValueImpl;
+import org.msgpack.value.impl.ImmutableStringValueImpl;
+import java.math.BigInteger;
+import java.util.AbstractMap;
+import java.util.Arrays;
+import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
-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 extends Value> list) {
+ public static ImmutableArrayValue newArray(List extends Value> 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 extends Value, ? extends Value>... pairs)
+ {
+ MapBuilder b = new MapBuilder();
+ for (Map.Entry extends Value, ? extends Value> 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 MapBuilder put(Map.Entry extends Value, ? extends Value> pair)
+ {
+ put(pair.getKey(), pair.getValue());
+ return this;
+ }
+
+ public MapBuilder put(Value key, Value value)
+ {
+ map.put(key, value);
+ return this;
+ }
+
+ public MapBuilder putAll(Iterable extends Map.Entry extends Value, ? extends Value>> entries)
+ {
+ for (Map.Entry extends Value, ? extends Value> entry : entries) {
+ put(entry.getKey(), entry.getValue());
+ }
+ return this;
+ }
+
+ public MapBuilder putAll(Map extends Value, ? extends Value> map)
+ {
+ for (Map.Entry extends Value, ? extends Value> entry : map.entrySet()) {
+ put(entry);
+ }
+ return this;
+ }
}
- /**
- * 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..715ebbd18 100644
--- a/msgpack-core/src/main/java/org/msgpack/value/ValueType.java
+++ b/msgpack-core/src/main/java/org/msgpack/value/ValueType.java
@@ -15,13 +15,11 @@
//
package org.msgpack.value;
-import org.msgpack.core.MessageFormat;
-
/**
* MessageTypeFamily is a group of {@link org.msgpack.core.MessageFormat}s
*/
-public enum ValueType {
-
+public enum ValueType
+{
NIL(false, false),
BOOLEAN(false, false),
INTEGER(true, false),
@@ -30,77 +28,69 @@ 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) {
+ 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() {
+ public boolean isNilType()
+ {
return this == NIL;
}
- public boolean isBooleanType() {
+ public boolean isBooleanType()
+ {
return this == BOOLEAN;
}
- public boolean isNumberType() {
+ public boolean isNumberType()
+ {
return numberType;
}
- public boolean isIntegerType() {
+ public boolean isIntegerType()
+ {
return this == INTEGER;
}
- public boolean isFloatType() {
+ public boolean isFloatType()
+ {
return this == FLOAT;
}
- public boolean isRawType() {
+ public boolean isRawType()
+ {
return rawType;
}
- public boolean isStringType() {
+ public boolean isStringType()
+ {
return this == STRING;
}
- public boolean isBinaryType() {
+ public boolean isBinaryType()
+ {
return this == BINARY;
}
- public boolean isArrayType() {
+ public boolean isArrayType()
+ {
return this == ARRAY;
}
- public boolean isMapType() {
+ public boolean isMapType()
+ {
return this == MAP;
}
- public boolean isExtendedType() {
- return this == EXTENDED;
- }
-
- public static ValueType valueOf(byte b) {
- return MessageFormat.valueOf(b).getValueType();
+ public boolean isExtensionType()
+ {
+ return this == EXTENSION;
}
-
- 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..59e6930cb
--- /dev/null
+++ b/msgpack-core/src/main/java/org/msgpack/value/Variable.java
@@ -0,0 +1,1235 @@
+//
+// 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.MessageFormat;
+import org.msgpack.core.MessageIntegerOverflowException;
+import org.msgpack.core.MessagePack;
+import org.msgpack.core.MessagePacker;
+import org.msgpack.core.MessageStringCodingException;
+import org.msgpack.core.MessageTypeCastException;
+import org.msgpack.value.impl.ImmutableBigIntegerValueImpl;
+
+import java.io.IOException;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.nio.ByteBuffer;
+import java.nio.charset.CharacterCodingException;
+import java.nio.charset.CharsetDecoder;
+import java.nio.charset.CodingErrorAction;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+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 toJson()
+ {
+ return Variable.this.toJson();
+ }
+
+ @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 toByte()
+ {
+ if (type == Type.BIG_INTEGER) {
+ return ((BigInteger) objectValue).byteValue();
+ }
+ return (byte) longValue;
+ }
+
+ @Override
+ public short toShort()
+ {
+ if (type == Type.BIG_INTEGER) {
+ return ((BigInteger) objectValue).shortValue();
+ }
+ return (short) longValue;
+ }
+
+ @Override
+ public int toInt()
+ {
+ if (type == Type.BIG_INTEGER) {
+ return ((BigInteger) objectValue).intValue();
+ }
+ return (int) longValue;
+ }
+
+ @Override
+ public long toLong()
+ {
+ if (type == Type.BIG_INTEGER) {
+ return ((BigInteger) objectValue).longValue();
+ }
+ return (long) longValue;
+ }
+
+ @Override
+ public BigInteger toBigInteger()
+ {
+ 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 toFloat()
+ {
+ if (type == Type.BIG_INTEGER) {
+ return ((BigInteger) objectValue).floatValue();
+ }
+ else if (type == Type.DOUBLE) {
+ return (float) doubleValue;
+ }
+ return (float) longValue;
+ }
+
+ @Override
+ public double toDouble()
+ {
+ 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 MessageFormat mostSuccinctMessageFormat()
+ {
+ return ImmutableBigIntegerValueImpl.mostSuccinctMessageFormat(this);
+ }
+
+ @Override
+ public byte asByte()
+ {
+ if (!isInByteRange()) {
+ throw new MessageIntegerOverflowException(longValue);
+ }
+ return (byte) longValue;
+ }
+
+ @Override
+ public short asShort()
+ {
+ if (!isInByteRange()) {
+ throw new MessageIntegerOverflowException(longValue);
+ }
+ return (short) longValue;
+ }
+
+ @Override
+ public int asInt()
+ {
+ if (!isInIntRange()) {
+ throw new MessageIntegerOverflowException(longValue);
+ }
+ return (int) longValue;
+ }
+
+ @Override
+ public long asLong()
+ {
+ if (!isInLongRange()) {
+ throw new MessageIntegerOverflowException(longValue);
+ }
+ return longValue;
+ }
+
+ @Override
+ public BigInteger asBigInteger()
+ {
+ 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 toLong
+ return this;
+ }
+
+ public Variable setFloatValue(float v)
+ {
+ this.type = Type.DOUBLE;
+ this.accessor = floatAccessor;
+ this.longValue = (long) v; // AbstractNumberValueAccessor uses toLong
+ 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[] asByteArray()
+ {
+ return (byte[]) objectValue;
+ }
+
+ @Override
+ public ByteBuffer asByteBuffer()
+ {
+ return ByteBuffer.wrap(asByteArray());
+ }
+
+ @Override
+ public String asString()
+ {
+ 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 for performance optimization
+ @Override
+ public String toString()
+ {
+ 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(asByteArray());
+ }
+
+ @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 toJson()
+ {
+ return immutableValue().toJson(); // 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..31adb5b1a
--- /dev/null
+++ b/msgpack-core/src/main/java/org/msgpack/value/impl/AbstractImmutableRawValue.java
@@ -0,0 +1,185 @@
+//
+// 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.MessageStringCodingException;
+import org.msgpack.value.ImmutableRawValue;
+
+import java.nio.ByteBuffer;
+import java.nio.charset.CharacterCodingException;
+import java.nio.charset.CharsetDecoder;
+import java.nio.charset.CodingErrorAction;
+import java.util.Arrays;
+
+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[] asByteArray()
+ {
+ return Arrays.copyOf(data, data.length);
+ }
+
+ @Override
+ public ByteBuffer asByteBuffer()
+ {
+ return ByteBuffer.wrap(data).asReadOnlyBuffer();
+ }
+
+ @Override
+ public String asString()
+ {
+ if (decodedStringCache == null) {
+ decodeString();
+ }
+ if (codingException != null) {
+ throw new MessageStringCodingException(codingException);
+ }
+ else {
+ return decodedStringCache;
+ }
+ }
+
+ @Override
+ public String toJson()
+ {
+ StringBuilder sb = new StringBuilder();
+ appendJsonString(sb, toString());
+ return sb.toString();
+ }
+
+ 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(asByteBuffer()).toString();
+ }
+ catch (CharacterCodingException ex) {
+ try {
+ CharsetDecoder replaceDecoder = MessagePack.UTF8.newDecoder()
+ .onMalformedInput(CodingErrorAction.REPLACE)
+ .onUnmappableCharacter(CodingErrorAction.REPLACE);
+ this.decodedStringCache = replaceDecoder.decode(asByteBuffer()).toString();
+ }
+ catch (CharacterCodingException neverThrown) {
+ throw new MessageStringCodingException(neverThrown);
+ }
+ this.codingException = ex;
+ }
+ }
+ }
+
+ @Override
+ public String toString()
+ {
+ if (decodedStringCache == null) {
+ decodeString();
+ }
+ return decodedStringCache;
+ }
+
+ static void appendJsonString(StringBuilder sb, String string)
+ {
+ sb.append("\"");
+ for (int i = 0; i < string.length(); i++) {
+ char ch = string.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("\"");
+ }
+
+ private static final char[] HEX_TABLE = "0123456789ABCDEF".toCharArray();
+
+ private static 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..1dae99cf2
--- /dev/null
+++ b/msgpack-core/src/main/java/org/msgpack/value/impl/AbstractImmutableValue.java
@@ -0,0 +1,166 @@
+//
+// 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.ImmutableArrayValue;
+import org.msgpack.value.ImmutableBinaryValue;
+import org.msgpack.value.ImmutableBooleanValue;
+import org.msgpack.value.ImmutableExtensionValue;
+import org.msgpack.value.ImmutableFloatValue;
+import org.msgpack.value.ImmutableIntegerValue;
+import org.msgpack.value.ImmutableMapValue;
+import org.msgpack.value.ImmutableNilValue;
+import org.msgpack.value.ImmutableNumberValue;
+import org.msgpack.value.ImmutableRawValue;
+import org.msgpack.value.ImmutableStringValue;
+import org.msgpack.value.ImmutableValue;
+
+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..3e1b732c2
--- /dev/null
+++ b/msgpack-core/src/main/java/org/msgpack/value/impl/ImmutableArrayValueImpl.java
@@ -0,0 +1,263 @@
+//
+// 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.ArrayValue;
+import org.msgpack.value.ImmutableArrayValue;
+import org.msgpack.value.Value;
+import org.msgpack.value.ValueType;
+
+import java.io.IOException;
+import java.util.AbstractList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+
+/**
+ * {@code ImmutableArrayValueImpl} Implements {@code ImmutableArrayValue} using a {@code Value[]} field.
+ *
+ * @see org.msgpack.value.IntegerValue
+ */
+public class ImmutableArrayValueImpl
+ extends AbstractImmutableValue
+ implements ImmutableArrayValue
+{
+ private static final 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 toJson()
+ {
+ if (array.length == 0) {
+ return "[]";
+ }
+ StringBuilder sb = new StringBuilder();
+ sb.append("[");
+ sb.append(array[0].toJson());
+ for (int i = 1; i < array.length; i++) {
+ sb.append(",");
+ sb.append(array[i].toJson());
+ }
+ sb.append("]");
+ return sb.toString();
+ }
+
+ @Override
+ public String toString()
+ {
+ if (array.length == 0) {
+ return "[]";
+ }
+ StringBuilder sb = new StringBuilder();
+ sb.append("[");
+ appendString(sb, array[0]);
+ for (int i = 1; i < array.length; i++) {
+ sb.append(",");
+ appendString(sb, array[i]);
+ }
+ sb.append("]");
+ return sb.toString();
+ }
+
+ private static void appendString(StringBuilder sb, Value value)
+ {
+ if (value.isRawValue()) {
+ sb.append(value.toJson());
+ }
+ else {
+ sb.append(value.toString());
+ }
+ }
+
+ 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 51%
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..c6fe39386 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,65 @@
+//
+// 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.MessageFormat;
import org.msgpack.core.MessageIntegerOverflowException;
import org.msgpack.core.MessagePacker;
-import org.msgpack.value.ValueType;
+import org.msgpack.value.ImmutableIntegerValue;
+import org.msgpack.value.ImmutableNumberValue;
import org.msgpack.value.IntegerValue;
import org.msgpack.value.Value;
-import org.msgpack.value.ValueVisitor;
+import org.msgpack.value.ValueType;
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
+{
+ public static MessageFormat mostSuccinctMessageFormat(IntegerValue v)
+ {
+ if (v.isInByteRange()) {
+ return MessageFormat.INT8;
+ }
+ else if (v.isInShortRange()) {
+ return MessageFormat.INT16;
+ }
+ else if (v.isInIntRange()) {
+ return MessageFormat.INT32;
+ }
+ else if (v.isInLongRange()) {
+ return MessageFormat.INT64;
+ }
+ else {
+ return MessageFormat.UINT64;
+ }
+ }
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);
@@ -33,121 +72,153 @@ public BigIntegerValueImpl(BigInteger value) {
private static final BigInteger LONG_MAX = BigInteger.valueOf((long) Long.MAX_VALUE);
@Override
- public ValueType getValueType() {
+ public ValueType getValueType()
+ {
return ValueType.INTEGER;
}
@Override
- public byte toByte() {
+ public ImmutableIntegerValue immutableValue()
+ {
+ return this;
+ }
+
+ @Override
+ public ImmutableNumberValue asNumberValue()
+ {
+ return this;
+ }
+
+ @Override
+ public ImmutableIntegerValue asIntegerValue()
+ {
+ return this;
+ }
+
+ @Override
+ public byte toByte()
+ {
return value.byteValue();
}
@Override
- public short toShort() {
+ public short toShort()
+ {
return value.shortValue();
}
@Override
- public int toInt() {
+ public int toInt()
+ {
return value.intValue();
}
@Override
- public long toLong() {
+ public long toLong()
+ {
return value.longValue();
}
@Override
- public BigInteger toBigInteger() {
+ public BigInteger toBigInteger()
+ {
return value;
}
@Override
- public float toFloat() {
+ public float toFloat()
+ {
return value.floatValue();
}
@Override
- public double toDouble() {
+ public double toDouble()
+ {
return value.doubleValue();
}
@Override
- public byte asByte() throws MessageIntegerOverflowException {
- if (!isValidByte()) {
- throw new MessageIntegerOverflowException(value);
- }
- return value.byteValue();
+ public boolean isInByteRange()
+ {
+ return 0 <= value.compareTo(BYTE_MIN) && value.compareTo(BYTE_MAX) <= 0;
}
@Override
- public short asShort() throws MessageIntegerOverflowException {
- if (!isValidShort()) {
- throw new MessageIntegerOverflowException(value);
- }
- return value.shortValue();
+ public boolean isInShortRange()
+ {
+ return 0 <= value.compareTo(SHORT_MIN) && value.compareTo(SHORT_MAX) <= 0;
}
@Override
- public int asInt() throws MessageIntegerOverflowException {
- if (!isValidInt()) {
- throw new MessageIntegerOverflowException(value);
- }
- return value.intValue();
+ public boolean isInIntRange()
+ {
+ return 0 <= value.compareTo(INT_MIN) && value.compareTo(INT_MAX) <= 0;
}
@Override
- public long asLong() throws MessageIntegerOverflowException {
- if (!isValidLong()) {
- throw new MessageIntegerOverflowException(value);
- }
- return value.longValue();
+ public boolean isInLongRange()
+ {
+ return 0 <= value.compareTo(LONG_MIN) && value.compareTo(LONG_MAX) <= 0;
}
@Override
- public BigInteger asBigInteger() throws MessageIntegerOverflowException {
- return value;
+ public MessageFormat mostSuccinctMessageFormat()
+ {
+ return mostSuccinctMessageFormat(this);
}
@Override
- public boolean isValidByte() {
- return 0 <= value.compareTo(BYTE_MIN) && value.compareTo(BYTE_MAX) <= 0;
+ public byte asByte()
+ {
+ if (!isInByteRange()) {
+ throw new MessageIntegerOverflowException(value);
+ }
+ return value.byteValue();
}
@Override
- public boolean isValidShort() {
- return 0 <= value.compareTo(SHORT_MIN) && value.compareTo(SHORT_MAX) <= 0;
+ public short asShort()
+ {
+ if (!isInShortRange()) {
+ throw new MessageIntegerOverflowException(value);
+ }
+ return value.shortValue();
}
@Override
- public boolean isValidInt() {
- return 0 <= value.compareTo(INT_MIN) && value.compareTo(INT_MAX) <= 0;
+ public int asInt()
+ {
+ if (!isInIntRange()) {
+ throw new MessageIntegerOverflowException(value);
+ }
+ return value.intValue();
}
@Override
- public boolean isValidLong() {
- return 0 <= value.compareTo(LONG_MIN) && value.compareTo(LONG_MAX) <= 0;
+ public long asLong()
+ {
+ if (!isInLongRange()) {
+ throw new MessageIntegerOverflowException(value);
+ }
+ return value.longValue();
}
+
@Override
- public boolean isWhole() {
- return true;
+ public BigInteger asBigInteger()
+ {
+ return value;
}
@Override
- public void writeTo(MessagePacker pk) throws IOException {
+ 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) {
+ public boolean equals(Object o)
+ {
if (o == this) {
return true;
}
@@ -155,18 +226,21 @@ public boolean equals(Object o) {
return false;
}
Value v = (Value) o;
- if (!v.isInteger()) {
+
+ if (!v.isIntegerValue()) {
return false;
}
- IntegerValue iv = v.asInteger();
+ IntegerValue iv = v.asIntegerValue();
return value.equals(iv.toBigInteger());
}
@Override
- public int hashCode() {
+ public int hashCode()
+ {
if (INT_MIN.compareTo(value) <= 0 && value.compareTo(INT_MAX) <= 0) {
return (int) value.longValue();
- } else if (LONG_MIN.compareTo(value) <= 0
+ }
+ else if (LONG_MIN.compareTo(value) <= 0
&& value.compareTo(LONG_MAX) <= 0) {
long v = value.longValue();
return (int) (v ^ (v >>> 32));
@@ -175,7 +249,14 @@ public int hashCode() {
}
@Override
- public String toString() {
+ public String toJson()
+ {
return value.toString();
}
+
+ @Override
+ public String toString()
+ {
+ return toJson();
+ }
}
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..2d444ae83
--- /dev/null
+++ b/msgpack-core/src/main/java/org/msgpack/value/impl/ImmutableBinaryValueImpl.java
@@ -0,0 +1,95 @@
+//
+// 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 toString()} and {@code asString()} 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().asByteArray());
+ }
+ }
+
+ @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..535e91c61
--- /dev/null
+++ b/msgpack-core/src/main/java/org/msgpack/value/impl/ImmutableBooleanValueImpl.java
@@ -0,0 +1,110 @@
+//
+// 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 final ImmutableBooleanValue TRUE = new ImmutableBooleanValueImpl(true);
+ public static final 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 toJson()
+ {
+ return Boolean.toString(value);
+ }
+
+ @Override
+ public String toString()
+ {
+ return toJson();
+ }
+}
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..2aae1633a
--- /dev/null
+++ b/msgpack-core/src/main/java/org/msgpack/value/impl/ImmutableDoubleValueImpl.java
@@ -0,0 +1,144 @@
+//
+// 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 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 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().toDouble();
+ }
+
+ @Override
+ public int hashCode()
+ {
+ long v = Double.doubleToLongBits(value);
+ return (int) (v ^ (v >>> 32));
+ }
+
+ @Override
+ public String toJson()
+ {
+ if (Double.isNaN(value) || Double.isInfinite(value)) {
+ return "null";
+ }
+ else {
+ return Double.toString(value);
+ }
+ }
+
+ @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..eb14cc767
--- /dev/null
+++ b/msgpack-core/src/main/java/org/msgpack/value/impl/ImmutableExtensionValueImpl.java
@@ -0,0 +1,138 @@
+//
+// 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.ExtensionValue;
+import org.msgpack.value.ImmutableExtensionValue;
+import org.msgpack.value.Value;
+import org.msgpack.value.ValueType;
+
+import java.io.IOException;
+import java.util.Arrays;
+
+/**
+ * {@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 toJson()
+ {
+ StringBuilder sb = new StringBuilder();
+ sb.append('[');
+ sb.append(Byte.toString(type));
+ sb.append(",\"");
+ for (byte e : data) {
+ sb.append(Integer.toString((int) e, 16));
+ }
+ sb.append("\"]");
+ return sb.toString();
+ }
+
+ @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 50%
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..872b97af0 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,45 @@
+//
+// 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.MessageFormat;
import org.msgpack.core.MessageIntegerOverflowException;
import org.msgpack.core.MessagePacker;
-import org.msgpack.value.ValueType;
+import org.msgpack.value.ImmutableIntegerValue;
+import org.msgpack.value.ImmutableNumberValue;
import org.msgpack.value.IntegerValue;
import org.msgpack.value.Value;
-import org.msgpack.value.ValueVisitor;
+import org.msgpack.value.ValueType;
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;
}
@@ -29,123 +51,150 @@ public LongValueImpl(long value) {
private static final long INT_MAX = (long) Integer.MAX_VALUE;
@Override
- public ValueType getValueType() {
+ public ValueType getValueType()
+ {
return ValueType.INTEGER;
}
@Override
- public IntegerValue asInteger() {
+ public ImmutableIntegerValue immutableValue()
+ {
+ return this;
+ }
+
+ @Override
+ public ImmutableNumberValue asNumberValue()
+ {
return this;
}
@Override
- public byte toByte() {
+ public ImmutableIntegerValue asIntegerValue()
+ {
+ return this;
+ }
+
+ @Override
+ public byte toByte()
+ {
return (byte) value;
}
@Override
- public short toShort() {
+ public short toShort()
+ {
return (short) value;
}
@Override
- public int toInt() {
+ public int toInt()
+ {
return (int) value;
}
@Override
- public long toLong() {
+ public long toLong()
+ {
return value;
}
@Override
- public BigInteger toBigInteger() {
+ public BigInteger toBigInteger()
+ {
return BigInteger.valueOf(value);
}
@Override
- public float toFloat() {
+ public float toFloat()
+ {
return (float) value;
}
@Override
- public double toDouble() {
+ public double toDouble()
+ {
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 MessageFormat mostSuccinctMessageFormat()
+ {
+ return ImmutableBigIntegerValueImpl.mostSuccinctMessageFormat(this);
}
@Override
- public boolean isValidByte() {
- return BYTE_MIN <= value && value <= BYTE_MAX;
+ public byte asByte()
+ {
+ if (!isInByteRange()) {
+ throw new MessageIntegerOverflowException(value);
+ }
+ return (byte) value;
}
@Override
- public boolean isValidShort() {
- return SHORT_MIN <= value && value <= SHORT_MAX;
+ public short asShort()
+ {
+ if (!isInShortRange()) {
+ throw new MessageIntegerOverflowException(value);
+ }
+ return (short) value;
}
@Override
- public boolean isValidInt() {
- return INT_MIN <= value && value <= INT_MAX;
+ public int asInt()
+ {
+ if (!isInIntRange()) {
+ throw new MessageIntegerOverflowException(value);
+ }
+ return (int) value;
}
@Override
- public boolean isValidLong() {
- return true;
+ public long asLong()
+ {
+ return value;
}
+
@Override
- public boolean isWhole() {
- return true;
+ public BigInteger asBigInteger()
+ {
+ return BigInteger.valueOf((long) value);
}
@Override
- public void writeTo(MessagePacker pk) throws IOException {
+ 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) {
+ public boolean equals(Object o)
+ {
if (o == this) {
return true;
}
@@ -153,27 +202,37 @@ 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();
}
@Override
- public int hashCode() {
+ public int hashCode()
+ {
if (INT_MIN <= value && value <= INT_MAX) {
return (int) value;
- } else {
+ }
+ else {
return (int) (value ^ (value >>> 32));
}
}
@Override
- public String toString() {
+ public String toJson()
+ {
return Long.toString(value);
}
+
+ @Override
+ public String toString()
+ {
+ return toJson();
+ }
}
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..dc55d783f
--- /dev/null
+++ b/msgpack-core/src/main/java/org/msgpack/value/impl/ImmutableMapValueImpl.java
@@ -0,0 +1,373 @@
+//
+// 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.ImmutableMapValue;
+import org.msgpack.value.MapValue;
+import org.msgpack.value.Value;
+import org.msgpack.value.ValueType;
+
+import java.io.IOException;
+import java.util.AbstractCollection;
+import java.util.AbstractMap;
+import java.util.AbstractSet;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Set;
+
+/**
+ * {@code ImmutableMapValueImpl} Implements {@code ImmutableMapValue} using a {@code Value[]} field.
+ *
+ * @see org.msgpack.value.MapValue
+ */
+public class ImmutableMapValueImpl
+ extends AbstractImmutableValue
+ implements ImmutableMapValue
+{
+ private static final 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 toJson()
+ {
+ if (kvs.length == 0) {
+ return "{}";
+ }
+ StringBuilder sb = new StringBuilder();
+ sb.append("{");
+ appendJsonKey(sb, kvs[0]);
+ sb.append(":");
+ sb.append(kvs[1].toJson());
+ for (int i = 2; i < kvs.length; i += 2) {
+ sb.append(",");
+ appendJsonKey(sb, kvs[i]);
+ sb.append(":");
+ sb.append(kvs[i + 1].toJson());
+ }
+ sb.append("}");
+ return sb.toString();
+ }
+
+ private static void appendJsonKey(StringBuilder sb, Value key)
+ {
+ if (key.isRawValue()) {
+ sb.append(key.toJson());
+ }
+ else {
+ ImmutableStringValueImpl.appendJsonString(sb, key.toString());
+ }
+ }
+
+ @Override
+ public String toString()
+ {
+ if (kvs.length == 0) {
+ return "{}";
+ }
+ StringBuilder sb = new StringBuilder();
+ sb.append("{");
+ appendString(sb, kvs[0]);
+ sb.append(":");
+ appendString(sb, kvs[1]);
+ for (int i = 2; i < kvs.length; i += 2) {
+ sb.append(",");
+ appendString(sb, kvs[i]);
+ sb.append(":");
+ appendString(sb, kvs[i + 1]);
+ }
+ sb.append("}");
+ return sb.toString();
+ }
+
+ private static void appendString(StringBuilder sb, Value value)
+ {
+ if (value.isRawValue()) {
+ sb.append(value.toJson());
+ }
+ else {
+ sb.append(value.toString());
+ }
+ }
+
+ 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..7077d115e
--- /dev/null
+++ b/msgpack-core/src/main/java/org/msgpack/value/impl/ImmutableNilValueImpl.java
@@ -0,0 +1,101 @@
+//
+// 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.ImmutableNilValue;
+import org.msgpack.value.Value;
+import org.msgpack.value.ValueType;
+
+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 toJson();
+ }
+
+ @Override
+ public String toJson()
+ {
+ 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..dbdb57195
--- /dev/null
+++ b/msgpack-core/src/main/java/org/msgpack/value/impl/ImmutableStringValueImpl.java
@@ -0,0 +1,100 @@
+//
+// 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.ImmutableStringValue;
+import org.msgpack.value.Value;
+import org.msgpack.value.ValueType;
+
+import java.io.IOException;
+import java.util.Arrays;
+
+/**
+ * {@code ImmutableStringValueImpl} Implements {@code ImmutableStringValue} using a {@code byte[]} field.
+ * This implementation caches result of {@code toString()} and {@code asString()} 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().asByteArray());
+ }
+ }
+
+ @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 adc0c00a1..000000000
--- a/msgpack-core/src/main/java/org/msgpack/value/impl/MapValueImpl.java
+++ /dev/null
@@ -1,276 +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();
- }
- }
-
-
- 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 63%
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..e8802a037 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
@@ -15,38 +15,51 @@
//
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.io.*;
-import java.nio.ByteBuffer;
-import java.nio.charset.CodingErrorAction;
+import org.msgpack.core.MessageFormat;
+import org.msgpack.core.MessagePack;
+import org.msgpack.core.MessagePack.PackerConfig;
+import org.msgpack.core.MessagePack.UnpackerConfig;
+import org.msgpack.core.MessagePacker;
+import org.msgpack.core.MessageUnpacker;
+import org.msgpack.value.ArrayValue;
+import org.msgpack.value.ExtensionValue;
+import org.msgpack.value.FloatValue;
+import org.msgpack.value.IntegerValue;
+import org.msgpack.value.Value;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.math.BigInteger;
/**
* This class describes the usage of MessagePack v07
*/
-public class MessagePackExample {
-
+public class MessagePackExample
+{
+ private MessagePackExample()
+ {
+ }
/**
* Basic usage example
+ *
* @throws IOException
*/
- public static void basicUsage() throws IOException {
-
+ public static void basicUsage()
+ throws IOException
+ {
// Serialize with MessagePacker
ByteArrayOutputStream out = new ByteArrayOutputStream();
MessagePacker packer = MessagePack.newDefaultPacker(out);
packer
- .packInt(1)
- .packString("leo")
- .packArrayHeader(2)
- .packString("xxx-xxxx")
- .packString("yyy-yyyy");
+ .packInt(1)
+ .packString("leo")
+ .packArrayHeader(2)
+ .packString("xxx-xxxx")
+ .packString("yyy-yyyy");
packer.close();
// Deserialize with MessageUnpacker
@@ -55,7 +68,7 @@ public static void basicUsage() throws IOException {
String name = unpacker.unpackString(); // "leo"
int numPhones = unpacker.unpackArrayHeader(); // 2
String[] phones = new String[numPhones];
- for(int i=0; i < numPhones; ++i) {
+ for (int i = 0; i < numPhones; ++i) {
phones[i] = unpacker.unpackString(); // phones = {"xxx-xxxx", "yyy-yyyy"}
}
unpacker.close();
@@ -63,10 +76,11 @@ public static void basicUsage() throws IOException {
System.out.println(String.format("id:%d, name:%s, phone:[%s]", id, name, join(phones)));
}
- private static String join(String[] in) {
+ private static String join(String[] in)
+ {
StringBuilder s = new StringBuilder();
- for(int i=0; i 0) {
+ for (int i = 0; i < in.length; ++i) {
+ if (i > 0) {
s.append(", ");
}
s.append(in[i]);
@@ -76,10 +90,12 @@ private static String join(String[] in) {
/**
* Packing various types of data
+ *
* @throws IOException
*/
- public static void packer() throws IOException {
-
+ public static void packer()
+ throws IOException
+ {
// Create a MesagePacker (encoder) instance
ByteArrayOutputStream out = new ByteArrayOutputStream();
MessagePacker packer = MessagePack.newDefaultPacker(out);
@@ -105,9 +121,9 @@ public static void packer() throws IOException {
packer.writePayload(s);
// pack arrays
- int[] arr = new int[]{3, 5, 1, 0, -1, 255};
+ int[] arr = new int[] {3, 5, 1, 0, -1, 255};
packer.packArrayHeader(arr.length);
- for(int v : arr) {
+ for (int v : arr) {
packer.packInt(v);
}
@@ -121,39 +137,32 @@ public static void packer() throws IOException {
packer.packInt(2);
// pack binary data
- byte[] ba = new byte[]{1, 2, 3, 4};
+ byte[] ba = new byte[] {1, 2, 3, 4};
packer.packBinaryHeader(ba.length);
packer.writePayload(ba);
-
// 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
packer
- .packInt(1)
- .packString("leo")
- .packArrayHeader(2)
- .packString("xxx-xxxx")
- .packString("yyy-yyyy");
-
-
- // [Advanced] write data using ByteBuffer
- ByteBuffer bb = ByteBuffer.wrap(new byte[] {'b', 'i', 'n', 'a', 'r', 'y', 'd', 'a', 't', 'a'});
- packer.packBinaryHeader(bb.remaining());
- packer.writePayload(bb);
-
+ .packInt(1)
+ .packString("leo")
+ .packArrayHeader(2)
+ .packString("xxx-xxxx")
+ .packString("yyy-yyyy");
}
-
/**
* An example of reading and writing MessagePack data
+ *
* @throws IOException
*/
- public static void readAndWriteFile() throws IOException {
-
+ public static void readAndWriteFile()
+ throws IOException
+ {
File tempFile = File.createTempFile("target/tmp", ".txt");
tempFile.deleteOnExit();
@@ -167,99 +176,92 @@ public static void readAndWriteFile() throws IOException {
// Read packed data from a file. No need exists to wrap the file stream with an buffer
MessageUnpacker unpacker = MessagePack.newDefaultUnpacker(new FileInputStream(tempFile));
- while(unpacker.hasNext()) {
+ while (unpacker.hasNext()) {
// [Advanced] You can check the detailed data format with getNextFormat()
// Here is a list of message pack data format: https://github.com/msgpack/msgpack/blob/master/spec.md#overview
MessageFormat format = unpacker.getNextFormat();
// 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.toInt();
System.out.println("read int: " + i);
}
- else {
- long l = ih.asLong();
+ else if (iv.isInLongRange()) {
+ long l = iv.toLong();
System.out.println("read long: " + l);
}
+ else {
+ BigInteger i = iv.toBigInteger();
+ 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.toFloat(); // use as float
+ double d = fv.toDouble(); // use as double
System.out.println("read float: " + d);
break;
case STRING:
- String s = v.get().asString().toString();
+ String s = v.asStringValue().asString();
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().asByteArray();
+ 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;
}
}
-
}
/**
* Example of using custom MessagePack configuration
+ *
* @throws IOException
*/
- public static void configuration() throws IOException {
-
- // Build a conifiguration
- MessagePack.Config config = new MessagePack.ConfigBuilder()
- .onMalFormedInput(CodingErrorAction.REPLACE) // Drop malformed and unmappable UTF-8 characters
- .onUnmappableCharacter(CodingErrorAction.REPLACE)
- .packerBufferSize(8192 * 2)
- .build();
- // Create a that uses this configuration
- MessagePack msgpack = new MessagePack(config);
-
- // Pack data
+ public static void configuration()
+ throws IOException
+ {
ByteArrayOutputStream out = new ByteArrayOutputStream();
- MessagePacker packer = msgpack.newPacker(out);
+ PackerConfig packerConfig = new PackerConfig();
+ packerConfig.smallStringOptimizationThreshold = 256; // String
+ MessagePacker packer = packerConfig.newPacker(out);
+
packer.packInt(10);
packer.packBoolean(true);
packer.close();
// Unpack data
+ UnpackerConfig unpackerConfig = new UnpackerConfig();
+ unpackerConfig.stringDecoderBufferSize = 16 * 1024; // If your data contains many large strings (the default is 8k)
+
byte[] packedData = out.toByteArray();
- MessageUnpacker unpacker = msgpack.newUnpacker(packedData);
+ MessageUnpacker unpacker = unpackerConfig.newUnpacker(packedData);
int i = unpacker.unpackInt(); // 10
boolean b = unpacker.unpackBoolean(); // true
unpacker.close();
}
-
-
-
-
-
}
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..be9d270cd 100644
--- a/msgpack-core/src/test/scala/org/msgpack/core/MessageFormatTest.scala
+++ b/msgpack-core/src/test/scala/org/msgpack/core/MessageFormatTest.scala
@@ -1,65 +1,84 @@
+//
+// 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
-import org.scalatest.exceptions.TestFailedException
import org.msgpack.core.MessagePack.Code
-import scala.util.Random
import org.msgpack.value.ValueType
+import org.scalatest.exceptions.TestFailedException
+
+import scala.util.Random
/**
* Created on 2014/05/07.
*/
-class MessageFormatTest extends MessagePackSpec {
-
+class MessageFormatTest
+ extends MessagePackSpec {
"MessageFormat" should {
"cover all byte codes" in {
-
- def checkV(b:Byte, tpe:ValueType) {
+ def checkV(b: Byte, tpe: ValueType) {
try
MessageFormat.valueOf(b).getValueType shouldBe tpe
catch {
- case e:TestFailedException =>
+ case e: TestFailedException =>
error(f"Failure when looking at byte ${b}%02x")
throw e
}
}
- def checkF(b:Byte, f:MessageFormat) {
+ def checkF(b: Byte, f: MessageFormat) {
MessageFormat.valueOf(b) shouldBe f
}
- def check(b:Byte, tpe:ValueType, f:MessageFormat) {
+ def check(b: Byte, tpe: ValueType, f: MessageFormat) {
checkV(b, tpe)
checkF(b, f)
}
- for(i <- 0 until 0x7f)
+ for (i <- 0 until 0x7f) {
check(i.toByte, ValueType.INTEGER, MessageFormat.POSFIXINT)
+ }
- for(i <- 0x80 until 0x8f)
+ for (i <- 0x80 until 0x8f) {
check(i.toByte, ValueType.MAP, MessageFormat.FIXMAP)
+ }
- for(i <- 0x90 until 0x9f)
+ for (i <- 0x90 until 0x9f) {
check(i.toByte, ValueType.ARRAY, MessageFormat.FIXARRAY)
+ }
check(Code.NIL, ValueType.NIL, MessageFormat.NIL)
MessageFormat.valueOf(Code.NEVER_USED) shouldBe MessageFormat.NEVER_USED
- for(i <- Seq(Code.TRUE, Code.FALSE))
+ for (i <- Seq(Code.TRUE, Code.FALSE)) {
check(i, ValueType.BOOLEAN, MessageFormat.BOOLEAN)
+ }
check(Code.BIN8, ValueType.BINARY, MessageFormat.BIN8)
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)
@@ -82,13 +101,12 @@ class MessageFormatTest extends MessagePackSpec {
check(Code.ARRAY16, ValueType.ARRAY, MessageFormat.ARRAY16)
check(Code.ARRAY32, ValueType.ARRAY, MessageFormat.ARRAY32)
- for(i <- 0xe0 to 0xff)
+ for (i <- 0xe0 to 0xff) {
check(i.toByte, ValueType.INTEGER, MessageFormat.NEGFIXINT)
-
+ }
}
"improve the valueOf performance" in {
-
val N = 1000000
val idx = (0 until N).map(x => Random.nextInt(256).toByte).toArray[Byte]
@@ -98,7 +116,7 @@ class MessageFormatTest extends MessagePackSpec {
time("lookup", repeat = 10) {
block("switch") {
var i = 0
- while(i < N) {
+ while (i < N) {
MessageFormat.toMessageFormat(idx(i))
i += 1
}
@@ -106,18 +124,12 @@ class MessageFormatTest extends MessagePackSpec {
block("table") {
var i = 0
- while(i < N) {
+ while (i < N) {
MessageFormat.valueOf(idx(i))
i += 1
}
}
-
}
-
}
-
}
-
-
-
}
diff --git a/msgpack-core/src/test/scala/org/msgpack/core/MessagePackSpec.scala b/msgpack-core/src/test/scala/org/msgpack/core/MessagePackSpec.scala
index 8eec662c4..b8be3bed0 100644
--- a/msgpack-core/src/test/scala/org/msgpack/core/MessagePackSpec.scala
+++ b/msgpack-core/src/test/scala/org/msgpack/core/MessagePackSpec.scala
@@ -15,12 +15,14 @@
//
package org.msgpack.core
+import java.io.ByteArrayOutputStream
+
import org.scalatest._
+import org.scalatest.prop.PropertyChecks
import xerial.core.log.{LogLevel, Logger}
import xerial.core.util.{TimeReport, Timer}
+
import scala.language.implicitConversions
-import org.scalatest.prop.PropertyChecks
-import java.io.ByteArrayOutputStream
trait MessagePackSpec
extends WordSpec
@@ -32,43 +34,36 @@ trait MessagePackSpec
with Benchmark
with Logger {
- implicit def toTag(s:String) : Tag = Tag(s)
+ implicit def toTag(s: String): Tag = Tag(s)
- def toHex(arr:Array[Byte]) = arr.map(x => f"$x%02x").mkString(" ")
+ def toHex(arr: Array[Byte]) = arr.map(x => f"$x%02x").mkString(" ")
-
- def createMessagePackData(f: MessagePacker => Unit) : Array[Byte] = {
- val b = new ByteArrayOutputStream()
+ def createMessagePackData(f: MessagePacker => Unit): Array[Byte] = {
+ val b = new
+ ByteArrayOutputStream()
val packer = MessagePack.newDefaultPacker(b)
f(packer)
packer.close()
b.toByteArray
}
-
-
-
-
}
-
-trait Benchmark extends Timer {
+trait Benchmark
+ extends Timer {
val numWarmUpRuns = 10
-
override protected def time[A](blockName: String, logLevel: LogLevel, repeat: Int)(f: => A): TimeReport = {
- super.time(blockName, logLevel=LogLevel.INFO, repeat)(f)
+ super.time(blockName, logLevel = LogLevel.INFO, repeat)(f)
}
override protected def block[A](name: String, repeat: Int)(f: => A): TimeReport = {
var i = 0
- while(i < numWarmUpRuns) {
+ while (i < numWarmUpRuns) {
f
i += 1
}
super.block(name, repeat)(f)
-
}
-
}
\ No newline at end of file
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..112c3e5a7 100644
--- a/msgpack-core/src/test/scala/org/msgpack/core/MessagePackTest.scala
+++ b/msgpack-core/src/test/scala/org/msgpack/core/MessagePackTest.scala
@@ -15,26 +15,27 @@
//
package org.msgpack.core
-import org.msgpack.value.Value
-import org.msgpack.value.holder.ValueHolder
-
-import scala.util.Random
-import MessagePack.Code
import java.io.ByteArrayOutputStream
import java.math.BigInteger
import java.nio.CharBuffer
-import java.nio.charset.{UnmappableCharacterException, CodingErrorAction}
+import java.nio.charset.{CodingErrorAction, UnmappableCharacterException}
+
+import org.msgpack.core.MessagePack.Code
+import org.msgpack.core.MessagePack.{UnpackerConfig, PackerConfig}
+import org.msgpack.value.{Value, Variable}
+
+import scala.util.Random
/**
* Created on 2014/05/07.
*/
-class MessagePackTest extends MessagePackSpec {
+class MessagePackTest extends MessagePackSpec {
def isValidUTF8(s: String) = {
MessagePack.UTF8.newEncoder().canEncode(s)
}
- def containsUnmappableCharacter(s: String) : Boolean = {
+ def containsUnmappableCharacter(s: String): Boolean = {
try {
MessagePack.UTF8.newEncoder().onUnmappableCharacter(CodingErrorAction.REPORT).encode(CharBuffer.wrap(s))
false
@@ -59,6 +60,36 @@ class MessagePackTest extends MessagePackSpec {
}
}
+ "detect fixarray values" in {
+ val packer = MessagePack.newDefaultBufferPacker()
+ packer.packArrayHeader(0)
+ packer.close
+ val bytes = packer.toByteArray
+ MessagePack.newDefaultUnpacker(bytes).unpackArrayHeader() shouldBe 0
+ try {
+ MessagePack.newDefaultUnpacker(bytes).unpackMapHeader()
+ fail("Shouldn't reach here")
+ }
+ catch {
+ case e: MessageTypeException => // OK
+ }
+ }
+
+ "detect fixmap values" in {
+ val packer = MessagePack.newDefaultBufferPacker()
+ packer.packMapHeader(0)
+ packer.close
+ val bytes = packer.toByteArray
+ MessagePack.newDefaultUnpacker(bytes).unpackMapHeader() shouldBe 0
+ try {
+ MessagePack.newDefaultUnpacker(bytes).unpackArrayHeader()
+ fail("Shouldn't reach here")
+ }
+ catch {
+ case e: MessageTypeException => // OK
+ }
+ }
+
"detect fixint quickly" in {
val N = 100000
@@ -117,39 +148,52 @@ class MessagePackTest extends MessagePackSpec {
}
- def check[A](v: A, pack: MessagePacker => Unit, unpack: MessageUnpacker => A, msgpack:MessagePack = MessagePack.DEFAULT): Unit = {
+ def check[A](
+ v: A,
+ pack: MessagePacker => Unit,
+ unpack: MessageUnpacker => A,
+ packerConfig: PackerConfig = new PackerConfig(),
+ unpackerConfig: UnpackerConfig = new UnpackerConfig()
+ ): Unit = {
var b: Array[Byte] = null
try {
val bs = new ByteArrayOutputStream()
- val packer = msgpack.newPacker(bs)
+ val packer = packerConfig.newPacker(bs)
pack(packer)
packer.close()
b = bs.toByteArray
- val unpacker = msgpack.newUnpacker(b)
+ val unpacker = unpackerConfig.newUnpacker(b)
val ret = unpack(unpacker)
ret shouldBe v
}
catch {
case e: Exception =>
warn(e.getMessage)
- if (b != null)
+ if (b != null) {
warn(s"packed data (size:${b.length}): ${toHex(b)}")
+ }
throw e
}
}
- def checkException[A](v: A, pack: MessagePacker => Unit, unpack: MessageUnpacker => A, msgpack:MessagePack=MessagePack.DEFAULT) : Unit = {
+ def checkException[A](
+ v: A,
+ pack: MessagePacker => Unit,
+ unpack: MessageUnpacker => A,
+ packerConfig: PackerConfig = new PackerConfig(),
+ unpaackerConfig: UnpackerConfig = new UnpackerConfig()
+ ): Unit = {
var b: Array[Byte] = null
val bs = new ByteArrayOutputStream()
- val packer = msgpack.newPacker(bs)
+ val packer = packerConfig.newPacker(bs)
pack(packer)
packer.close()
b = bs.toByteArray
- val unpacker = msgpack.newUnpacker(b)
+ val unpacker = unpaackerConfig.newUnpacker(b)
val ret = unpack(unpacker)
fail("cannot not reach here")
@@ -160,30 +204,29 @@ class MessagePackTest extends MessagePackSpec {
checkException[A](v, pack, unpack)
}
catch {
- case e:MessageIntegerOverflowException => // OK
+ case e: MessageIntegerOverflowException => // OK
}
}
-
-
-
- "pack/unpack primitive values" taggedAs("prim") in {
- forAll { (v: Boolean) => check(v, _.packBoolean(v), _.unpackBoolean)}
- forAll { (v: Byte) => check(v, _.packByte(v), _.unpackByte)}
- forAll { (v: Short) => check(v, _.packShort(v), _.unpackShort)}
- forAll { (v: Int) => check(v, _.packInt(v), _.unpackInt)}
- 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())
+ "pack/unpack primitive values" taggedAs ("prim") in {
+ forAll { (v: Boolean) => check(v, _.packBoolean(v), _.unpackBoolean) }
+ forAll { (v: Byte) => check(v, _.packByte(v), _.unpackByte) }
+ forAll { (v: Short) => check(v, _.packShort(v), _.unpackShort) }
+ forAll { (v: Int) => check(v, _.packInt(v), _.unpackInt) }
+ 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, { unpacker => unpacker.unpackNil(); null })
}
- "pack/unpack integer values" taggedAs("int") in {
- val sampleData = Seq[Long](Int.MinValue.toLong - 10, -65535, -8191, -1024, -255, -127, -63, -31, -15, -7, -3, -1, 0, 2, 4, 8, 16, 32, 64, 128, 256, 1024, 8192, 65536, Int.MaxValue.toLong + 10)
- for(v <- sampleData) {
+ "pack/unpack integer values" taggedAs ("int") in {
+ val sampleData = Seq[Long](Int.MinValue.toLong -
+ 10, -65535, -8191, -1024, -255, -127, -63, -31, -15, -7, -3, -1, 0, 2, 4, 8, 16, 32, 64, 128, 256, 1024, 8192, 65536,
+ Int.MaxValue.toLong + 10)
+ for (v <- sampleData) {
check(v, _.packLong(v), _.unpackLong)
- if(v.isValidInt) {
+ if (v.isValidInt) {
val vi = v.toInt
check(vi, _.packInt(vi), _.unpackInt)
}
@@ -191,7 +234,7 @@ class MessagePackTest extends MessagePackSpec {
checkOverflow(v, _.packLong(v), _.unpackInt)
}
- if(v.isValidShort) {
+ if (v.isValidShort) {
val vi = v.toShort
check(vi, _.packShort(vi), _.unpackShort)
}
@@ -199,7 +242,7 @@ class MessagePackTest extends MessagePackSpec {
checkOverflow(v, _.packLong(v), _.unpackShort)
}
- if(v.isValidByte) {
+ if (v.isValidByte) {
val vi = v.toByte
check(vi, _.packByte(vi), _.unpackByte)
}
@@ -211,23 +254,23 @@ class MessagePackTest extends MessagePackSpec {
}
- "pack/unpack BigInteger" taggedAs("bi") in {
+ "pack/unpack BigInteger" taggedAs ("bi") in {
forAll { (a: Long) =>
val v = BigInteger.valueOf(a)
check(v, _.packBigInteger(v), _.unpackBigInteger)
}
- for(bi <- Seq(BigInteger.valueOf(Long.MaxValue).add(BigInteger.valueOf(1)))) {
+ for (bi <- Seq(BigInteger.valueOf(Long.MaxValue).add(BigInteger.valueOf(1)))) {
check(bi, _.packBigInteger(bi), _.unpackBigInteger())
}
- for(bi <- Seq(BigInteger.valueOf(Long.MaxValue).shiftLeft(10))) {
+ for (bi <- Seq(BigInteger.valueOf(Long.MaxValue).shiftLeft(10))) {
try {
checkException(bi, _.packBigInteger(bi), _.unpackBigInteger())
fail("cannot reach here")
}
catch {
- case e:IllegalArgumentException => // OK
+ case e: IllegalArgumentException => // OK
}
}
@@ -245,14 +288,14 @@ class MessagePackTest extends MessagePackSpec {
"pack/unpack large strings" taggedAs ("large-string") in {
// Large string
val strLen = Seq(1000, 2000, 10000, 50000, 100000, 500000)
- for(l <- strLen) {
- val v : String = Iterator.continually(Random.nextString(l * 10)).find(isValidUTF8).get
+ for (l <- strLen) {
+ val v: String = Iterator.continually(Random.nextString(l * 10)).find(isValidUTF8).get
check(v, _.packString(v), _.unpackString)
}
}
- "report errors when packing/unpacking malformed strings" taggedAs("malformed") in {
+ "report errors when packing/unpacking malformed strings" taggedAs ("malformed") in {
// TODO produce malformed utf-8 strings in Java8"
pending
// Create 100 malformed UTF8 Strings
@@ -287,45 +330,37 @@ class MessagePackTest extends MessagePackSpec {
}
}
- "report errors when packing/unpacking strings that contain unmappable characters" taggedAs("unmap") in {
+ "report errors when packing/unpacking strings that contain unmappable characters" taggedAs ("unmap") in {
val unmappable = Array[Byte](0xfc.toByte, 0x0a.toByte)
//val unmappableChar = Array[Char](new Character(0xfc0a).toChar)
// Report error on unmappable character
- val config = new MessagePack.ConfigBuilder().onMalFormedInput(CodingErrorAction.REPORT).onUnmappableCharacter(CodingErrorAction.REPORT).build()
- val msgpack = new MessagePack(config)
+ val unpackerConfig = new UnpackerConfig()
+ unpackerConfig.actionOnMalformedString = CodingErrorAction.REPORT
+ unpackerConfig.actionOnUnmappableString = CodingErrorAction.REPORT
- for(bytes <- Seq(unmappable)) {
+ for (bytes <- Seq(unmappable)) {
When("unpacking")
try {
- checkException(bytes,
- { packer =>
+ checkException(bytes, { packer =>
packer.packRawStringHeader(bytes.length)
packer.writePayload(bytes)
},
_.unpackString(),
- msgpack)
+ new PackerConfig(),
+ unpackerConfig)
}
catch {
- case e:MessageStringCodingException => // OK
+ case e: MessageStringCodingException => // OK
}
-
-// When("packing")
-// try {
-// val s = new String(unmappableChar)
-// checkException(s, _.packString(s), _.unpackString())
-// }
-// catch {
-// case e:MessageStringCodingException => // OK
-// }
- }
+ }
}
"pack/unpack binary" taggedAs ("binary") in {
forAll { (v: Array[Byte]) =>
- check(v, { packer => packer.packBinaryHeader(v.length); packer.writePayload(v)}, { unpacker =>
+ check(v, { packer => packer.packBinaryHeader(v.length); packer.writePayload(v) }, { unpacker =>
val len = unpacker.unpackBinaryHeader()
val out = new Array[Byte](len)
unpacker.readPayload(out, 0, len)
@@ -335,10 +370,10 @@ class MessagePackTest extends MessagePackSpec {
}
val len = Seq(1000, 2000, 10000, 50000, 100000, 500000)
- for(l <- len) {
+ for (l <- len) {
val v = new Array[Byte](l)
Random.nextBytes(v)
- check(v, { packer => packer.packBinaryHeader(v.length); packer.writePayload(v)}, { unpacker =>
+ check(v, { packer => packer.packBinaryHeader(v.length); packer.writePayload(v) }, { unpacker =>
val len = unpacker.unpackBinaryHeader()
val out = new Array[Byte](len)
unpacker.readPayload(out, 0, len)
@@ -359,14 +394,15 @@ class MessagePackTest extends MessagePackSpec {
}, { unpacker =>
val len = unpacker.unpackArrayHeader()
val out = new Array[Int](len)
- for (i <- 0 until v.length)
+ for (i <- 0 until v.length) {
out(i) = unpacker.unpackInt
+ }
out
}
)
}
- for(l <- testHeaderLength) {
+ for (l <- testHeaderLength) {
check(l, _.packArrayHeader(l), _.unpackArrayHeader())
}
@@ -393,14 +429,15 @@ class MessagePackTest extends MessagePackSpec {
}, { unpacker =>
val len = unpacker.unpackMapHeader()
val b = Seq.newBuilder[(Int, String)]
- for (i <- 0 until len)
+ for (i <- 0 until len) {
b += ((unpacker.unpackInt, unpacker.unpackString))
+ }
b.result
}
)
}
- for(l <- testHeaderLength) {
+ for (l <- testHeaderLength) {
check(l, _.packMapHeader(l), _.unpackMapHeader())
}
@@ -414,19 +451,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())
+ for (l <- testHeaderLength) {
+ val ext = new ExtensionTypeHeader(ExtensionTypeHeader.checkedCastToByte(Random.nextInt(128)), l)
+ check(ext, _.packExtensionTypeHeader(ext.getType, ext.getLength), _.unpackExtensionTypeHeader())
}
}
@@ -444,23 +480,22 @@ 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().asString, v.asStringValue().asString)
}).toMap
}.toList
})
}
}
-}
\ No newline at end of file
+}
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 4fb621e46..2fbe461d1 100644
--- a/msgpack-core/src/test/scala/org/msgpack/core/MessagePackerTest.scala
+++ b/msgpack-core/src/test/scala/org/msgpack/core/MessagePackerTest.scala
@@ -15,25 +15,24 @@
//
package org.msgpack.core
-import java.io.{FileInputStream, FileOutputStream, File, ByteArrayOutputStream}
+import java.io.{ByteArrayOutputStream, File, FileInputStream, FileOutputStream}
-import org.msgpack.core.buffer.{ChannelBufferOutput, MessageBufferOutput, OutputStreamBufferOutput}
+import org.msgpack.core.MessagePack.{UnpackerConfig, PackerConfig}
+import org.msgpack.core.buffer.{ChannelBufferOutput, OutputStreamBufferOutput}
+import org.msgpack.value.ValueFactory
import xerial.core.io.IOUtil
import scala.util.Random
-import org.msgpack.value.ValueFactory
/**
*
*/
class MessagePackerTest extends MessagePackSpec {
- val msgpack = MessagePack.DEFAULT
-
- def verifyIntSeq(answer:Array[Int], packed:Array[Byte]) {
- val unpacker = msgpack.newUnpacker(packed)
+ def verifyIntSeq(answer: Array[Int], packed: Array[Byte]) {
+ val unpacker = MessagePack.newDefaultUnpacker(packed)
val b = Array.newBuilder[Int]
- while(unpacker.hasNext) {
+ while (unpacker.hasNext) {
b += unpacker.unpackInt()
}
val result = b.result
@@ -49,7 +48,8 @@ class MessagePackerTest extends MessagePackSpec {
def createTempFileWithOutputStream = {
val f = createTempFile
- val out = new FileOutputStream(f)
+ val out = new
+ FileOutputStream(f)
(f, out)
}
@@ -64,37 +64,48 @@ class MessagePackerTest extends MessagePackSpec {
"reset the internal states" in {
val intSeq = (0 until 100).map(i => Random.nextInt).toArray
- val b = new ByteArrayOutputStream
- val packer = msgpack.newPacker(b)
+ val b = new
+ ByteArrayOutputStream
+ val packer = MessagePack.newDefaultPacker(b)
intSeq foreach packer.packInt
packer.close
verifyIntSeq(intSeq, b.toByteArray)
val intSeq2 = intSeq.reverse
- val b2 = new ByteArrayOutputStream
- packer.reset(new OutputStreamBufferOutput(b2))
+ val b2 = new
+ ByteArrayOutputStream
+ packer
+ .reset(new
+ OutputStreamBufferOutput(b2))
intSeq2 foreach packer.packInt
packer.close
verifyIntSeq(intSeq2, b2.toByteArray)
val intSeq3 = intSeq2.sorted
- val b3 = new ByteArrayOutputStream
- packer.reset(new OutputStreamBufferOutput(b3))
+ val b3 = new
+ ByteArrayOutputStream
+ packer
+ .reset(new
+ OutputStreamBufferOutput(b3))
intSeq3 foreach packer.packInt
packer.close
verifyIntSeq(intSeq3, b3.toByteArray)
}
- "improve the performance via reset method" taggedAs("reset") in {
+ "improve the performance via reset method" taggedAs ("reset") in {
val N = 1000
val t = time("packer", repeat = 10) {
block("no-buffer-reset") {
- val out = new ByteArrayOutputStream
- IOUtil.withResource(msgpack.newPacker(out)) { packer =>
+ val out = new
+ ByteArrayOutputStream
+ IOUtil.withResource(MessagePack.newDefaultPacker(out)) { packer =>
for (i <- 0 until N) {
- val outputStream = new ByteArrayOutputStream()
- packer.reset(new OutputStreamBufferOutput(outputStream))
+ val outputStream = new
+ ByteArrayOutputStream()
+ packer
+ .reset(new
+ OutputStreamBufferOutput(outputStream))
packer.packInt(0)
packer.flush()
}
@@ -102,11 +113,15 @@ class MessagePackerTest extends MessagePackSpec {
}
block("buffer-reset") {
- val out = new ByteArrayOutputStream
- IOUtil.withResource(msgpack.newPacker(out)) { packer =>
- val bufferOut = new OutputStreamBufferOutput(new ByteArrayOutputStream())
+ val out = new
+ ByteArrayOutputStream
+ IOUtil.withResource(MessagePack.newDefaultPacker(out)) { packer =>
+ val bufferOut = new
+ OutputStreamBufferOutput(new
+ ByteArrayOutputStream())
for (i <- 0 until N) {
- val outputStream = new ByteArrayOutputStream()
+ val outputStream = new
+ ByteArrayOutputStream()
bufferOut.reset(outputStream)
packer.reset(bufferOut)
packer.packInt(0)
@@ -117,33 +132,30 @@ class MessagePackerTest extends MessagePackSpec {
}
t("buffer-reset").averageWithoutMinMax should be <= t("no-buffer-reset").averageWithoutMinMax
-
}
"pack larger string array than byte buf" taggedAs ("larger-string-array-than-byte-buf") in {
// Based on https://github.com/msgpack/msgpack-java/issues/154
- // TODO: Refactor this test code to fit other ones.
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)
+ val out = new ByteArrayOutputStream(bufferSize)
+ val packer = MessagePack.newDefaultPacker(out)
packer.packValue(array)
packer.close()
out.toByteArray
true
}
- val testCases = List(
+ val testCases = Seq(
32 -> 30,
33 -> 31,
32 -> 31,
34 -> 32
)
- testCases.foreach{
+ testCases.foreach {
case (bufferSize, stringSize) => test(bufferSize, stringSize)
}
}
@@ -154,20 +166,28 @@ class MessagePackerTest extends MessagePackSpec {
packer.packInt(99)
packer.close
- val up0 = MessagePack.newDefaultUnpacker(new FileInputStream(f0))
+ val up0 = MessagePack
+ .newDefaultUnpacker(new
+ FileInputStream(f0))
up0.unpackInt shouldBe 99
up0.hasNext shouldBe false
up0.close
val (f1, out1) = createTempFileWithOutputStream
- packer.reset(new OutputStreamBufferOutput(out1))
+ packer
+ .reset(new
+ OutputStreamBufferOutput(out1))
packer.packInt(99)
packer.flush
- packer.reset(new OutputStreamBufferOutput(out1))
+ packer
+ .reset(new
+ OutputStreamBufferOutput(out1))
packer.packString("hello")
packer.close
- val up1 = MessagePack.newDefaultUnpacker(new FileInputStream(f1))
+ val up1 = MessagePack
+ .newDefaultUnpacker(new
+ FileInputStream(f1))
up1.unpackInt shouldBe 99
up1.unpackString shouldBe "hello"
up1.hasNext shouldBe false
@@ -180,41 +200,86 @@ class MessagePackerTest extends MessagePackSpec {
packer.packInt(99)
packer.close
- val up0 = MessagePack.newDefaultUnpacker(new FileInputStream(f0))
+ val up0 = MessagePack
+ .newDefaultUnpacker(new
+ FileInputStream(f0))
up0.unpackInt shouldBe 99
up0.hasNext shouldBe false
up0.close
val (f1, out1) = createTempFileWithChannel
- packer.reset(new ChannelBufferOutput(out1))
+ packer
+ .reset(new
+ ChannelBufferOutput(out1))
packer.packInt(99)
packer.flush
- packer.reset(new ChannelBufferOutput(out1))
+ packer
+ .reset(new
+ ChannelBufferOutput(out1))
packer.packString("hello")
packer.close
- val up1 = MessagePack.newDefaultUnpacker(new FileInputStream(f1))
+ val up1 = MessagePack
+ .newDefaultUnpacker(new
+ FileInputStream(f1))
up1.unpackInt shouldBe 99
up1.unpackString shouldBe "hello"
up1.hasNext shouldBe false
up1.close
}
+
+ "pack a lot of String within expected time" in {
+ val count = 20000
+
+ def measureDuration(outputStream: java.io.OutputStream) = {
+ val packer = MessagePack.newDefaultPacker(outputStream)
+ var i = 0
+ while (i < count) {
+ packer.packString("0123456789ABCDEF")
+ i += 1
+ }
+ packer.close
+ }
+
+ val t = time("packString into OutputStream", repeat = 10) {
+ block("byte-array-output-stream") {
+ measureDuration(new ByteArrayOutputStream())
+ }
+
+ block("file-output-stream") {
+ val (_, fileOutput) = createTempFileWithOutputStream
+ measureDuration(fileOutput)
+ }
+ }
+ t("file-output-stream").averageWithoutMinMax shouldBe < (t("byte-array-output-stream").averageWithoutMinMax * 5)
+ }
}
"compute totalWrittenBytes" in {
- val out = new ByteArrayOutputStream
- val packerTotalWrittenBytes = IOUtil.withResource(msgpack.newPacker(out)) { packer =>
+ val out = new
+ ByteArrayOutputStream
+ val packerTotalWrittenBytes = IOUtil.withResource(MessagePack.newDefaultPacker(out)) { packer =>
packer.packByte(0) // 1
- .packBoolean(true) // 1
- .packShort(12) // 1
- .packInt(1024) // 3
- .packLong(Long.MaxValue) // 5
- .packString("foobar") // 7
- .flush()
+ .packBoolean(true) // 1
+ .packShort(12) // 1
+ .packInt(1024) // 3
+ .packLong(Long.MaxValue) // 5
+ .packString("foobar") // 7
+ .flush()
packer.getTotalWrittenBytes
}
out.toByteArray.length shouldBe packerTotalWrittenBytes
}
+
+ "support read-only buffer" taggedAs ("read-only") in {
+ val payload = Array[Byte](1)
+ val out = new
+ ByteArrayOutputStream()
+ val packer = MessagePack.newDefaultPacker(out)
+ .packBinaryHeader(1)
+ .writePayload(payload)
+ .close()
+ }
}
diff --git a/msgpack-core/src/test/scala/org/msgpack/core/MessageUnpackerTest.scala b/msgpack-core/src/test/scala/org/msgpack/core/MessageUnpackerTest.scala
index 1428c68a9..e8ed65be7 100644
--- a/msgpack-core/src/test/scala/org/msgpack/core/MessageUnpackerTest.scala
+++ b/msgpack-core/src/test/scala/org/msgpack/core/MessageUnpackerTest.scala
@@ -1,21 +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.core
import java.io._
-import scala.util.Random
+import java.nio.ByteBuffer
+
import org.msgpack.core.buffer._
import org.msgpack.value.ValueType
import xerial.core.io.IOUtil
+import scala.util.Random
+
/**
* Created on 2014/05/07.
*/
class MessageUnpackerTest extends MessagePackSpec {
- val msgpack = MessagePack.DEFAULT
-
- def testData : Array[Byte] = {
+ def testData: Array[Byte] = {
val out = new ByteArrayOutputStream()
- val packer = msgpack.newPacker(out)
+ val packer = MessagePack.newDefaultPacker(out)
packer
.packArrayHeader(2)
@@ -33,12 +49,11 @@ class MessageUnpackerTest extends MessagePackSpec {
arr
}
- val intSeq = (for(i <- 0 until 100) yield Random.nextInt()).toArray[Int]
-
- def testData2 : Array[Byte] = {
+ val intSeq = (for (i <- 0 until 100) yield Random.nextInt()).toArray[Int]
+ def testData2: Array[Byte] = {
val out = new ByteArrayOutputStream()
- val packer = msgpack.newPacker(out);
+ val packer = MessagePack.newDefaultPacker(out);
packer
.packBoolean(true)
@@ -52,7 +67,7 @@ class MessageUnpackerTest extends MessagePackSpec {
arr
}
- def write(packer:MessagePacker, r:Random) {
+ def write(packer: MessagePacker, r: Random) {
val tpeIndex = Iterator.continually(r.nextInt(MessageFormat.values().length)).find(_ != MessageFormat.NEVER_USED.ordinal()).get
val tpe = MessageFormat.values()(tpeIndex)
tpe.getValueType match {
@@ -85,7 +100,7 @@ class MessageUnpackerTest extends MessagePackSpec {
trace(s"array len: $len")
packer.packArrayHeader(len)
var i = 0
- while(i < len) {
+ while (i < len) {
write(packer, r)
i += 1
}
@@ -94,7 +109,7 @@ class MessageUnpackerTest extends MessagePackSpec {
packer.packMapHeader(len)
trace(s"map len: ${len}")
var i = 0
- while(i < len * 2) {
+ while (i < len * 2) {
write(packer, r)
i += 1
}
@@ -105,10 +120,10 @@ class MessageUnpackerTest extends MessagePackSpec {
}
}
- def testData3(N:Int) : Array[Byte] = {
+ def testData3(N: Int): Array[Byte] = {
val out = new ByteArrayOutputStream()
- val packer = msgpack.newPacker(out)
+ val packer = MessagePack.newDefaultPacker(out)
val r = new Random(0)
@@ -122,7 +137,7 @@ class MessageUnpackerTest extends MessagePackSpec {
}
- def readValue(unpacker:MessageUnpacker) {
+ def readValue(unpacker: MessageUnpacker) {
val f = unpacker.getNextFormat()
f.getValueType match {
case ValueType.ARRAY =>
@@ -152,20 +167,20 @@ class MessageUnpackerTest extends MessagePackSpec {
f
}
- def checkFile(u:MessageUnpacker) = {
+ def checkFile(u: MessageUnpacker) = {
u.unpackInt shouldBe 99
u.hasNext shouldBe false
}
"MessageUnpacker" should {
- "parse message packed data" taggedAs("unpack") in {
+ "parse message packed data" taggedAs ("unpack") in {
val arr = testData
- val unpacker = msgpack.newUnpacker(arr)
+ val unpacker = MessagePack.newDefaultUnpacker(arr)
var count = 0
- while(unpacker.hasNext) {
+ while (unpacker.hasNext) {
count += 1
readValue(unpacker)
}
@@ -175,9 +190,9 @@ class MessageUnpackerTest extends MessagePackSpec {
"skip reading values" in {
- val unpacker = msgpack.newUnpacker(testData)
+ val unpacker = MessagePack.newDefaultUnpacker(testData)
var skipCount = 0
- while(unpacker.hasNext) {
+ while (unpacker.hasNext) {
unpacker.skipValue()
skipCount += 1
}
@@ -186,15 +201,15 @@ class MessageUnpackerTest extends MessagePackSpec {
unpacker.getTotalReadBytes shouldBe testData.length
}
- "compare skip performance" taggedAs("skip") in {
+ "compare skip performance" taggedAs ("skip") in {
val N = 10000
val data = testData3(N)
time("skip performance", repeat = 100) {
block("switch") {
- val unpacker = msgpack.newUnpacker(data)
+ val unpacker = MessagePack.newDefaultUnpacker(data)
var skipCount = 0
- while(unpacker.hasNext) {
+ while (unpacker.hasNext) {
unpacker.skipValue()
skipCount += 1
}
@@ -210,8 +225,8 @@ class MessageUnpackerTest extends MessagePackSpec {
val ib = Seq.newBuilder[Int]
- val unpacker = msgpack.newUnpacker(testData2)
- while(unpacker.hasNext) {
+ val unpacker = MessagePack.newDefaultUnpacker(testData2)
+ while (unpacker.hasNext) {
val f = unpacker.getNextFormat
f.getValueType match {
case ValueType.INTEGER =>
@@ -231,7 +246,7 @@ class MessageUnpackerTest extends MessagePackSpec {
}
- class SplitMessageBufferInput(array:Array[Array[Byte]]) extends MessageBufferInput {
+ class SplitMessageBufferInput(array: Array[Array[Byte]]) extends MessageBufferInput {
var cursor = 0
override def next(): MessageBuffer = {
if (cursor < array.length) {
@@ -239,19 +254,20 @@ class MessageUnpackerTest extends MessagePackSpec {
cursor += 1
MessageBuffer.wrap(a)
}
- else
+ else {
null
+ }
}
override def close(): Unit = {}
}
- "read data at the buffer boundary" taggedAs("boundary") in {
+ "read data at the buffer boundary" taggedAs ("boundary") in {
trait SplitTest {
- val data : Array[Byte]
+ val data: Array[Byte]
def run {
- val unpacker = msgpack.newUnpacker(data)
+ val unpacker = MessagePack.newDefaultUnpacker(data)
val numElems = {
var c = 0
while (unpacker.hasNext) {
@@ -265,7 +281,7 @@ class MessageUnpackerTest extends MessagePackSpec {
debug(s"split at $splitPoint")
val (h, t) = data.splitAt(splitPoint)
val bin = new SplitMessageBufferInput(Array(h, t))
- val unpacker = new MessageUnpacker(bin)
+ val unpacker = MessagePack.newDefaultUnpacker(bin)
var count = 0
while (unpacker.hasNext) {
count += 1
@@ -278,12 +294,12 @@ class MessageUnpackerTest extends MessagePackSpec {
}
}
- new SplitTest { val data = testData }.run
- new SplitTest { val data = testData3(30) }.run
+ new SplitTest {val data = testData}.run
+ new SplitTest {val data = testData3(30)}.run
}
- "be faster then msgpack-v6 skip" taggedAs("cmp-skip") in {
+ "be faster then msgpack-v6 skip" taggedAs ("cmp-skip") in {
val data = testData3(10000)
val N = 100
@@ -308,7 +324,7 @@ class MessageUnpackerTest extends MessagePackSpec {
}
block("v7") {
- val unpacker = msgpack.newUnpacker(data)
+ val unpacker = MessagePack.newDefaultUnpacker(data)
var count = 0
try {
while (unpacker.hasNext) {
@@ -324,22 +340,22 @@ class MessageUnpackerTest extends MessagePackSpec {
t("v7").averageWithoutMinMax should be <= t("v6").averageWithoutMinMax
}
- import org.msgpack.`type`.{ValueType=>ValueTypeV6}
+ import org.msgpack.`type`.{ValueType => ValueTypeV6}
- "be faster than msgpack-v6 read value" taggedAs("cmp-unpack") in {
+ "be faster than msgpack-v6 read value" taggedAs ("cmp-unpack") in {
- def readValueV6(unpacker:org.msgpack.unpacker.MessagePackUnpacker) {
+ def readValueV6(unpacker: org.msgpack.unpacker.MessagePackUnpacker) {
val vt = unpacker.getNextType()
vt match {
case ValueTypeV6.ARRAY =>
val len = unpacker.readArrayBegin()
var i = 0
- while(i < len) { readValueV6(unpacker); i += 1 }
+ while (i < len) {readValueV6(unpacker); i += 1}
unpacker.readArrayEnd()
case ValueTypeV6.MAP =>
val len = unpacker.readMapBegin()
var i = 0
- while(i < len) { readValueV6(unpacker); readValueV6(unpacker); i += 1 }
+ while (i < len) {readValueV6(unpacker); readValueV6(unpacker); i += 1}
unpacker.readMapEnd()
case ValueTypeV6.NIL =>
unpacker.readNil()
@@ -358,18 +374,18 @@ class MessageUnpackerTest extends MessagePackSpec {
val buf = new Array[Byte](8192)
- def readValue(unpacker:MessageUnpacker) {
+ def readValue(unpacker: MessageUnpacker) {
val f = unpacker.getNextFormat
val vt = f.getValueType
vt match {
case ValueType.ARRAY =>
val len = unpacker.unpackArrayHeader()
var i = 0
- while(i < len) { readValue(unpacker); i += 1 }
+ while (i < len) {readValue(unpacker); i += 1}
case ValueType.MAP =>
val len = unpacker.unpackMapHeader()
var i = 0
- while(i < len) { readValue(unpacker); readValue(unpacker); i += 1 }
+ while (i < len) {readValue(unpacker); readValue(unpacker); i += 1}
case ValueType.NIL =>
unpacker.unpackNil()
case ValueType.INTEGER =>
@@ -391,26 +407,26 @@ class MessageUnpackerTest extends MessagePackSpec {
val data = testData3(10000)
val N = 100
- val t = time("unpack performance", repeat=N) {
+ val t = time("unpack performance", repeat = N) {
block("v6") {
val v6 = new org.msgpack.MessagePack()
val unpacker = new org.msgpack.unpacker.MessagePackUnpacker(v6, new ByteArrayInputStream(data))
var count = 0
try {
- while(true) {
+ while (true) {
readValueV6(unpacker)
count += 1
}
}
catch {
- case e:EOFException =>
+ case e: EOFException =>
}
finally
unpacker.close()
}
block("v7") {
- val unpacker = msgpack.newUnpacker(data)
+ val unpacker = MessagePack.newDefaultUnpacker(data)
var count = 0
try {
while (unpacker.hasNext) {
@@ -428,10 +444,10 @@ class MessageUnpackerTest extends MessagePackSpec {
}
- "be faster for reading binary than v6" taggedAs("cmp-binary") in {
+ "be faster for reading binary than v6" taggedAs ("cmp-binary") in {
val bos = new ByteArrayOutputStream()
- val packer = msgpack.newPacker(bos)
+ val packer = MessagePack.newDefaultPacker(bos)
val L = 10000
val R = 100
(0 until R).foreach { i =>
@@ -441,12 +457,12 @@ class MessageUnpackerTest extends MessagePackSpec {
packer.close()
val b = bos.toByteArray
- time("unpackBinary", repeat=100) {
+ time("unpackBinary", repeat = 100) {
block("v6") {
val v6 = new org.msgpack.MessagePack()
val unpacker = new org.msgpack.unpacker.MessagePackUnpacker(v6, new ByteArrayInputStream(b))
var i = 0
- while(i < R) {
+ while (i < R) {
val out = unpacker.readByteArray()
i += 1
}
@@ -454,9 +470,9 @@ class MessageUnpackerTest extends MessagePackSpec {
}
block("v7") {
- val unpacker = msgpack.newUnpacker(b)
+ val unpacker = MessagePack.newDefaultUnpacker(b)
var i = 0
- while(i < R) {
+ while (i < R) {
val len = unpacker.unpackBinaryHeader()
val out = new Array[Byte](len)
unpacker.readPayload(out, 0, len)
@@ -466,9 +482,9 @@ class MessageUnpackerTest extends MessagePackSpec {
}
block("v7-ref") {
- val unpacker = msgpack.newUnpacker(b)
+ val unpacker = MessagePack.newDefaultUnpacker(b)
var i = 0
- while(i < R) {
+ while (i < R) {
val len = unpacker.unpackBinaryHeader()
val out = unpacker.readPayloadAsReference(len)
i += 1
@@ -478,21 +494,21 @@ class MessageUnpackerTest extends MessagePackSpec {
}
}
- "read payload as a reference" taggedAs("ref") in {
+ "read payload as a reference" taggedAs ("ref") in {
val dataSizes = Seq(0, 1, 5, 8, 16, 32, 128, 256, 1024, 2000, 10000, 100000)
- for(s <- dataSizes) {
+ for (s <- dataSizes) {
When(f"data size is $s%,d")
val data = new Array[Byte](s)
Random.nextBytes(data)
val b = new ByteArrayOutputStream()
- val packer = msgpack.newPacker(b)
+ val packer = MessagePack.newDefaultPacker(b)
packer.packBinaryHeader(s)
packer.writePayload(data)
packer.close()
- val unpacker = msgpack.newUnpacker(b.toByteArray)
+ val unpacker = MessagePack.newDefaultUnpacker(b.toByteArray)
val len = unpacker.unpackBinaryHeader()
len shouldBe s
val ref = unpacker.readPayloadAsReference(len)
@@ -507,14 +523,14 @@ class MessageUnpackerTest extends MessagePackSpec {
}
- "reset the internal states" taggedAs("reset") in {
+ "reset the internal states" taggedAs ("reset") in {
val data = intSeq
val b = createMessagePackData(packer => data foreach packer.packInt)
- val unpacker = msgpack.newUnpacker(b)
+ val unpacker = MessagePack.newDefaultUnpacker(b)
val unpacked = Array.newBuilder[Int]
- while(unpacker.hasNext) {
+ while (unpacker.hasNext) {
unpacked += unpacker.unpackInt()
}
unpacker.close
@@ -525,7 +541,7 @@ class MessageUnpackerTest extends MessagePackSpec {
val bi = new ArrayBufferInput(b2)
unpacker.reset(bi)
val unpacked2 = Array.newBuilder[Int]
- while(unpacker.hasNext) {
+ while (unpacker.hasNext) {
unpacked2 += unpacker.unpackInt()
}
unpacker.close
@@ -535,7 +551,7 @@ class MessageUnpackerTest extends MessagePackSpec {
bi.reset(b2)
unpacker.reset(bi)
val unpacked3 = Array.newBuilder[Int]
- while(unpacker.hasNext) {
+ while (unpacker.hasNext) {
unpacked3 += unpacker.unpackInt()
}
unpacker.close
@@ -543,10 +559,10 @@ class MessageUnpackerTest extends MessagePackSpec {
}
- "improve the performance via reset method" taggedAs("reset-arr") in {
+ "improve the performance via reset method" taggedAs ("reset-arr") in {
val out = new ByteArrayOutputStream
- val packer = msgpack.newPacker(out)
+ val packer = MessagePack.newDefaultPacker(out)
packer.packInt(0)
packer.flush
val arr = out.toByteArray
@@ -555,7 +571,7 @@ class MessageUnpackerTest extends MessagePackSpec {
val N = 1000
val t = time("unpacker", repeat = 10) {
block("no-buffer-reset") {
- IOUtil.withResource(msgpack.newUnpacker(arr)) { unpacker =>
+ IOUtil.withResource(MessagePack.newDefaultUnpacker(arr)) { unpacker =>
for (i <- 0 until N) {
val buf = new ArrayBufferInput(arr)
unpacker.reset(buf)
@@ -566,7 +582,7 @@ class MessageUnpackerTest extends MessagePackSpec {
}
block("reuse-array-input") {
- IOUtil.withResource(msgpack.newUnpacker(arr)) { unpacker =>
+ IOUtil.withResource(MessagePack.newDefaultUnpacker(arr)) { unpacker =>
val buf = new ArrayBufferInput(arr)
for (i <- 0 until N) {
buf.reset(arr)
@@ -578,7 +594,7 @@ class MessageUnpackerTest extends MessagePackSpec {
}
block("reuse-message-buffer") {
- IOUtil.withResource(msgpack.newUnpacker(arr)) { unpacker =>
+ IOUtil.withResource(MessagePack.newDefaultUnpacker(arr)) { unpacker =>
val buf = new ArrayBufferInput(arr)
for (i <- 0 until N) {
buf.reset(mb)
@@ -590,8 +606,8 @@ class MessageUnpackerTest extends MessagePackSpec {
}
}
- t("reuse-message-buffer").averageWithoutMinMax should be <= t("no-buffer-reset").averageWithoutMinMax
- // This performance comparition is too close, so we disabled it
+ // This performance comparison is too close, so we disabled it
+ // t("reuse-message-buffer").averageWithoutMinMax should be <= t("no-buffer-reset").averageWithoutMinMax
// t("reuse-array-input").averageWithoutMinMax should be <= t("no-buffer-reset").averageWithoutMinMax
}
@@ -618,5 +634,58 @@ class MessageUnpackerTest extends MessagePackSpec {
checkFile(u)
u.close
}
+
+ "unpack large string data" taggedAs ("large-string") in {
+ def createLargeData(stringLength: Int): Array[Byte] = {
+ val out = new ByteArrayOutputStream()
+ val packer = MessagePack.newDefaultPacker(out)
+
+ packer
+ .packArrayHeader(2)
+ .packString("l" * stringLength)
+ .packInt(1)
+
+ packer.close()
+
+ out.toByteArray
+ }
+
+ Seq(8191, 8192, 8193, 16383, 16384, 16385).foreach { n =>
+ val arr = createLargeData(n)
+
+ val unpacker = MessagePack.newDefaultUnpacker(arr)
+
+ unpacker.unpackArrayHeader shouldBe 2
+ unpacker.unpackString.length shouldBe n
+ unpacker.unpackInt shouldBe 1
+
+ unpacker.getTotalReadBytes shouldBe arr.length
+ }
+ }
+
+ "unpack string crossing end of buffer" in {
+ def check(expected: String, strLen: Int) = {
+ val bytes = new Array[Byte](strLen)
+ val out = new ByteArrayOutputStream
+
+ val packer = MessagePack.newDefaultPacker(out)
+ packer.packBinaryHeader(bytes.length)
+ packer.writePayload(bytes)
+ packer.packString(expected)
+ packer.close
+
+ val unpacker = MessagePack.newDefaultUnpacker(new InputStreamBufferInput(new ByteArrayInputStream(out.toByteArray)))
+ val len = unpacker.unpackBinaryHeader
+ unpacker.readPayload(len)
+ val got = unpacker.unpackString
+ unpacker.close
+
+ got shouldBe expected
+ }
+
+ Seq("\u3042", "a\u3042", "\u3042a", "\u3042\u3044\u3046\u3048\u304A\u304B\u304D\u304F\u3051\u3053\u3055\u3057\u3059\u305B\u305D").foreach { s =>
+ Seq(8185, 8186, 8187, 8188, 16377, 16378, 16379, 16380).foreach { n => check(s, n)}
+ }
+ }
}
}
diff --git a/msgpack-core/src/test/scala/org/msgpack/core/buffer/ByteStringTest.scala b/msgpack-core/src/test/scala/org/msgpack/core/buffer/ByteStringTest.scala
new file mode 100644
index 000000000..2c080b59a
--- /dev/null
+++ b/msgpack-core/src/test/scala/org/msgpack/core/buffer/ByteStringTest.scala
@@ -0,0 +1,46 @@
+//
+// 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.buffer
+
+import akka.util.ByteString
+import org.msgpack.core.{MessagePack, MessagePackSpec, MessageUnpacker}
+
+class ByteStringTest
+ extends MessagePackSpec {
+
+ val unpackedString = "foo"
+ val byteString = ByteString(createMessagePackData(_.packString(unpackedString)))
+
+ def unpackString(messageBuffer: MessageBuffer) = {
+ val input = new
+ MessageBufferInput {
+
+ private var isRead = false
+
+ override def next(): MessageBuffer =
+ if (isRead) {
+ null
+ }
+ else {
+ isRead = true
+ messageBuffer
+ }
+ override def close(): Unit = {}
+ }
+
+ MessagePack.newDefaultUnpacker(input).unpackString()
+ }
+}
diff --git a/msgpack-core/src/test/scala/org/msgpack/core/buffer/MessageBufferInputTest.scala b/msgpack-core/src/test/scala/org/msgpack/core/buffer/MessageBufferInputTest.scala
index 379badf7e..1638806ee 100644
--- a/msgpack-core/src/test/scala/org/msgpack/core/buffer/MessageBufferInputTest.scala
+++ b/msgpack-core/src/test/scala/org/msgpack/core/buffer/MessageBufferInputTest.scala
@@ -1,23 +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.core.buffer
-import org.msgpack.core.{MessageUnpacker, MessagePack, MessagePackSpec}
import java.io._
-import xerial.core.io.IOUtil
-import scala.util.Random
-import java.util.zip.{GZIPOutputStream, GZIPInputStream}
import java.nio.ByteBuffer
-import org.msgpack.unpacker.MessagePackUnpacker
+import java.util.zip.{GZIPInputStream, GZIPOutputStream}
+
+import org.msgpack.core.{MessagePack, MessagePackSpec, MessageUnpacker}
+import xerial.core.io.IOUtil._
+
+import scala.util.Random
-/**
- * Created on 5/30/14.
- */
-class MessageBufferInputTest extends MessagePackSpec {
+class MessageBufferInputTest
+ extends MessagePackSpec {
val targetInputSize = Seq(0, 10, 500, 1000, 2000, 4000, 8000, 10000, 30000, 50000, 100000)
- def testData(size:Int) = {
+ def testData(size: Int) = {
//debug(s"test data size: ${size}")
- val b = new Array[Byte](size)
+ val b = new
+ Array[Byte](size)
Random.nextBytes(b)
b
}
@@ -25,17 +40,19 @@ class MessageBufferInputTest extends MessagePackSpec {
def testDataSet = {
targetInputSize.map(testData)
}
-
- def runTest(factory:Array[Byte] => MessageBufferInput) {
- for(b <- testDataSet) {
+
+ def runTest(factory: Array[Byte] => MessageBufferInput) {
+ for (b <- testDataSet) {
checkInputData(b, factory(b))
}
}
- implicit class InputData(b:Array[Byte]) {
+ implicit class InputData(b: Array[Byte]) {
def compress = {
- val compressed = new ByteArrayOutputStream()
- val out = new GZIPOutputStream(compressed)
+ val compressed = new
+ ByteArrayOutputStream()
+ val out = new
+ GZIPOutputStream(compressed)
out.write(b)
out.close()
compressed.toByteArray
@@ -45,59 +62,61 @@ class MessageBufferInputTest extends MessagePackSpec {
ByteBuffer.wrap(b)
}
- def saveToTmpFile : File = {
- val tmp = File.createTempFile("testbuf", ".dat", new File("target"))
+ def saveToTmpFile: File = {
+ val tmp = File
+ .createTempFile("testbuf",
+ ".dat",
+ new
+ File("target"))
tmp.getParentFile.mkdirs()
tmp.deleteOnExit()
- IOUtil.withResource(new FileOutputStream(tmp)) { out =>
+ withResource(new
+ FileOutputStream(tmp)) { out =>
out.write(b)
}
tmp
}
}
-
-
- def checkInputData(inputData:Array[Byte], in:MessageBufferInput) {
+ def checkInputData(inputData: Array[Byte], in: MessageBufferInput) {
When(s"input data size = ${inputData.length}")
var cursor = 0
- for(m <- Iterator.continually(in.next).takeWhile(_ != null)) {
+ for (m <- Iterator.continually(in.next).takeWhile(_ != null)) {
m.toByteArray() shouldBe inputData.slice(cursor, cursor + m.size())
cursor += m.size()
}
cursor shouldBe inputData.length
-
}
-
"MessageBufferInput" should {
"support byte arrays" in {
- runTest(new ArrayBufferInput(_))
- }
-
- "support ByteBuffers" in {
- runTest(b => new ByteBufferInput(b.toByteBuffer))
+ runTest(new
+ ArrayBufferInput(_))
}
- "support InputStreams" taggedAs("is") in {
- runTest(b =>
- new InputStreamBufferInput(
- new GZIPInputStream(new ByteArrayInputStream(b.compress)))
+ "support InputStreams" taggedAs ("is") in {
+ runTest(b =>
+ new
+ InputStreamBufferInput(
+ new
+ GZIPInputStream(new
+ ByteArrayInputStream(b.compress)))
)
}
- "support file input channel" taggedAs("fc") in {
+ "support file input channel" taggedAs ("fc") in {
runTest { b =>
val tmp = b.saveToTmpFile
try {
- InputStreamBufferInput.newBufferInput(new FileInputStream(tmp))
+ InputStreamBufferInput
+ .newBufferInput(new
+ FileInputStream(tmp))
}
finally {
tmp.delete()
}
}
}
-
}
def createTempFile = {
@@ -109,8 +128,9 @@ class MessageBufferInputTest extends MessagePackSpec {
def createTempFileWithInputStream = {
val f = createTempFile
val out = new FileOutputStream(f)
- new MessagePack().newPacker(out).packInt(42).close
- val in = new FileInputStream(f)
+ MessagePack.newDefaultPacker(out).packInt(42).close
+ val in = new
+ FileInputStream(f)
(f, in)
}
@@ -120,27 +140,56 @@ class MessageBufferInputTest extends MessagePackSpec {
(f, ch)
}
- def readInt(buf:MessageBufferInput) : Int = {
- val unpacker = new MessageUnpacker(buf)
+ def readInt(buf: MessageBufferInput): Int = {
+ val unpacker = MessagePack.newDefaultUnpacker(buf)
unpacker.unpackInt
}
"InputStreamBufferInput" should {
"reset buffer" in {
val (f0, in0) = createTempFileWithInputStream
- val buf = new InputStreamBufferInput(in0)
+ val buf = new
+ InputStreamBufferInput(in0)
readInt(buf) shouldBe 42
val (f1, in1) = createTempFileWithInputStream
buf.reset(in1)
readInt(buf) shouldBe 42
}
+
+ "be non-blocking" taggedAs ("non-blocking") in {
+
+ withResource(new
+ PipedOutputStream()) { pipedOutputStream =>
+ withResource(new
+ PipedInputStream()) { pipedInputStream =>
+ pipedInputStream.connect(pipedOutputStream)
+
+ val packer = MessagePack.newDefaultPacker(pipedOutputStream)
+ .packArrayHeader(2)
+ .packLong(42)
+ .packString("hello world")
+
+ packer.flush
+
+ val unpacker = MessagePack.newDefaultUnpacker(pipedInputStream)
+ unpacker.hasNext() shouldBe true
+ unpacker.unpackArrayHeader() shouldBe 2
+ unpacker.unpackLong() shouldBe 42L
+ unpacker.unpackString() shouldBe "hello world"
+
+ packer.close
+ unpacker.close
+ }
+ }
+ }
}
"ChannelBufferInput" should {
"reset buffer" in {
val (f0, in0) = createTempFileWithChannel
- val buf = new ChannelBufferInput(in0)
+ val buf = new
+ ChannelBufferInput(in0)
readInt(buf) shouldBe 42
val (f1, in1) = createTempFileWithChannel
@@ -148,5 +197,4 @@ class MessageBufferInputTest extends MessagePackSpec {
readInt(buf) shouldBe 42
}
}
-
}
diff --git a/msgpack-core/src/test/scala/org/msgpack/core/buffer/MessageBufferOutputTest.scala b/msgpack-core/src/test/scala/org/msgpack/core/buffer/MessageBufferOutputTest.scala
index 7d8940dc6..1869f2aad 100644
--- a/msgpack-core/src/test/scala/org/msgpack/core/buffer/MessageBufferOutputTest.scala
+++ b/msgpack-core/src/test/scala/org/msgpack/core/buffer/MessageBufferOutputTest.scala
@@ -1,9 +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.core.buffer
-import org.msgpack.core.MessagePackSpec
import java.io._
-class MessageBufferOutputTest extends MessagePackSpec {
+import org.msgpack.core.MessagePackSpec
+
+class MessageBufferOutputTest
+ extends MessagePackSpec {
def createTempFile = {
val f = File.createTempFile("msgpackTest", "msgpack")
@@ -13,7 +30,8 @@ class MessageBufferOutputTest extends MessagePackSpec {
def createTempFileWithOutputStream = {
val f = createTempFile
- val out = new FileOutputStream(f)
+ val out = new
+ FileOutputStream(f)
(f, out)
}
@@ -23,17 +41,18 @@ class MessageBufferOutputTest extends MessagePackSpec {
(f, ch)
}
- def writeIntToBuf(buf:MessageBufferOutput) = {
+ def writeIntToBuf(buf: MessageBufferOutput) = {
val mb0 = buf.next(8)
mb0.putInt(0, 42)
- buf.flush(mb0)
+ buf.writeBuffer(4)
buf.close
}
"OutputStreamBufferOutput" should {
"reset buffer" in {
val (f0, out0) = createTempFileWithOutputStream
- val buf = new OutputStreamBufferOutput(out0)
+ val buf = new
+ OutputStreamBufferOutput(out0)
writeIntToBuf(buf)
f0.length.toInt should be > 0
@@ -47,7 +66,8 @@ class MessageBufferOutputTest extends MessagePackSpec {
"ChannelBufferOutput" should {
"reset buffer" in {
val (f0, ch0) = createTempFileWithChannel
- val buf = new ChannelBufferOutput(ch0)
+ val buf = new
+ ChannelBufferOutput(ch0)
writeIntToBuf(buf)
f0.length.toInt should be > 0
@@ -57,5 +77,4 @@ class MessageBufferOutputTest extends MessagePackSpec {
f1.length.toInt should be > 0
}
}
-
}
diff --git a/msgpack-core/src/test/scala/org/msgpack/core/buffer/MessageBufferTest.scala b/msgpack-core/src/test/scala/org/msgpack/core/buffer/MessageBufferTest.scala
index 505dbd312..75ef00a11 100644
--- a/msgpack-core/src/test/scala/org/msgpack/core/buffer/MessageBufferTest.scala
+++ b/msgpack-core/src/test/scala/org/msgpack/core/buffer/MessageBufferTest.scala
@@ -1,20 +1,42 @@
+//
+// 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.buffer
import java.nio.ByteBuffer
-import scala.util.Random
+
import org.msgpack.core.MessagePackSpec
+import scala.util.Random
+
/**
* Created on 2014/05/01.
*/
-class MessageBufferTest extends MessagePackSpec {
+class MessageBufferTest
+ extends MessagePackSpec {
"MessageBuffer" should {
- "wrap ByteBuffer considering position and remaining values" taggedAs("wrap-bb") in {
- val d = Array[Byte](10,11,12,13,14,15,16,17,18,19)
- val subset = ByteBuffer.wrap(d, 2, 2)
- val mb = MessageBuffer.wrap(subset)
+ "check buffer type" in {
+ val b = MessageBuffer.allocate(0)
+ info(s"MessageBuffer type: ${b.getClass.getName}")
+ }
+
+ "wrap ByteBuffer considering position and remaining values" taggedAs ("wrap-bb") in {
+ val d = Array[Byte](10, 11, 12, 13, 14, 15, 16, 17, 18, 19)
+ val mb = MessageBuffer.wrap(d, 2, 2)
mb.getByte(0) shouldBe 12
mb.size() shouldBe 2
}
@@ -24,25 +46,26 @@ class MessageBufferTest extends MessagePackSpec {
val N = 1000000
val M = 64 * 1024 * 1024
- val ub = MessageBuffer.newBuffer(M)
- val ud = MessageBuffer.newDirectBuffer(M)
+ val ub = MessageBuffer.allocate(M)
val hb = ByteBuffer.allocate(M)
val db = ByteBuffer.allocateDirect(M)
def bench(f: Int => Unit) {
var i = 0
- while(i < N) {
+ while (i < N) {
f((i * 4) % M)
i += 1
}
}
- val r = new Random(0)
- val rs = new Array[Int](N)
+ val r = new
+ Random(0)
+ val rs = new
+ Array[Int](N)
(0 until N).map(i => rs(i) = r.nextInt(N))
def randomBench(f: Int => Unit) {
var i = 0
- while(i < N) {
+ while (i < N) {
f((rs(i) * 4) % M)
i += 1
}
@@ -53,23 +76,15 @@ class MessageBufferTest extends MessagePackSpec {
time("sequential getInt", repeat = rep) {
block("unsafe array") {
var i = 0
- while(i < N) {
+ while (i < N) {
ub.getInt((i * 4) % M)
i += 1
}
}
- block("unsafe direct") {
- var i = 0
- while(i < N) {
- ud.getInt((i * 4) % M)
- i += 1
- }
- }
-
block("allocate") {
var i = 0
- while(i < N) {
+ while (i < N) {
hb.getInt((i * 4) % M)
i += 1
}
@@ -77,7 +92,7 @@ class MessageBufferTest extends MessagePackSpec {
block("allocateDirect") {
var i = 0
- while(i < N) {
+ while (i < N) {
db.getInt((i * 4) % M)
i += 1
}
@@ -87,23 +102,15 @@ class MessageBufferTest extends MessagePackSpec {
time("random getInt", repeat = rep) {
block("unsafe array") {
var i = 0
- while(i < N) {
+ while (i < N) {
ub.getInt((rs(i) * 4) % M)
i += 1
}
}
- block("unsafe direct") {
- var i = 0
- while(i < N) {
- ud.getInt((rs(i) * 4) % M)
- i += 1
- }
- }
-
block("allocate") {
var i = 0
- while(i < N) {
+ while (i < N) {
hb.getInt((rs(i) * 4) % M)
i += 1
}
@@ -111,29 +118,81 @@ class MessageBufferTest extends MessagePackSpec {
block("allocateDirect") {
var i = 0
- while(i < N) {
+ while (i < N) {
db.getInt((rs(i) * 4) % M)
i += 1
}
}
}
-
}
"convert to ByteBuffer" in {
for (t <- Seq(
- MessageBuffer.newBuffer(10),
- MessageBuffer.newDirectBuffer(10),
- MessageBuffer.newOffHeapBuffer(10))
+ MessageBuffer.allocate(10))
) {
- val bb = t.toByteBuffer
+ val bb = t.sliceAsByteBuffer
bb.position shouldBe 0
bb.limit shouldBe 10
bb.capacity shouldBe 10
}
}
- }
+ "put ByteBuffer on itself" in {
+ for (t <- Seq(
+ MessageBuffer.allocate(10))
+ ) {
+ val b = Array[Byte](0x02, 0x03)
+ val srcArray = ByteBuffer.wrap(b)
+ val srcHeap = ByteBuffer.allocate(b.length)
+ srcHeap.put(b).flip
+ val srcOffHeap = ByteBuffer.allocateDirect(b.length)
+ srcOffHeap.put(b).flip
+
+ for (src <- Seq(srcArray, srcHeap, srcOffHeap)) {
+ // Write header bytes
+ val header = Array[Byte](0x00, 0x01)
+ t.putBytes(0, header, 0, header.length)
+ // Write src after the header
+ t.putByteBuffer(header.length, src, header.length)
+
+ t.getByte(0) shouldBe 0x00
+ t.getByte(1) shouldBe 0x01
+ t.getByte(2) shouldBe 0x02
+ t.getByte(3) shouldBe 0x03
+ }
+ }
+ }
+
+ "copy sliced buffer" in {
+ def prepareBytes : Array[Byte] = {
+ Array[Byte](0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07)
+ }
+
+ def checkSliceAndCopyTo(srcBuffer: MessageBuffer, dstBuffer: MessageBuffer) = {
+ val sliced = srcBuffer.slice(2, 5)
+
+ sliced.size() shouldBe 5
+ sliced.getByte(0) shouldBe 0x02
+ sliced.getByte(1) shouldBe 0x03
+ sliced.getByte(2) shouldBe 0x04
+ sliced.getByte(3) shouldBe 0x05
+ sliced.getByte(4) shouldBe 0x06
+
+ sliced.copyTo(3, dstBuffer, 1, 2) // copy 0x05 and 0x06 to dstBuffer[1] and [2]
+
+ dstBuffer.getByte(0) shouldBe 0x00
+ dstBuffer.getByte(1) shouldBe 0x05 // copied by sliced.getByte(3)
+ dstBuffer.getByte(2) shouldBe 0x06 // copied by sliced.getByte(4)
+ dstBuffer.getByte(3) shouldBe 0x03
+ dstBuffer.getByte(4) shouldBe 0x04
+ dstBuffer.getByte(5) shouldBe 0x05
+ dstBuffer.getByte(6) shouldBe 0x06
+ dstBuffer.getByte(7) shouldBe 0x07
+ }
+
+ checkSliceAndCopyTo(MessageBuffer.wrap(prepareBytes), MessageBuffer.wrap(prepareBytes))
+ }
+ }
}
diff --git a/msgpack-core/src/test/scala/org/msgpack/core/example/MessagePackExampleTest.scala b/msgpack-core/src/test/scala/org/msgpack/core/example/MessagePackExampleTest.scala
index 21c1d8334..bacf39ed4 100644
--- a/msgpack-core/src/test/scala/org/msgpack/core/example/MessagePackExampleTest.scala
+++ b/msgpack-core/src/test/scala/org/msgpack/core/example/MessagePackExampleTest.scala
@@ -1,3 +1,18 @@
+//
+// 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.example
import org.msgpack.core.MessagePackSpec
@@ -5,7 +20,8 @@ import org.msgpack.core.MessagePackSpec
/**
*
*/
-class MessagePackExampleTest extends MessagePackSpec {
+class MessagePackExampleTest
+ extends MessagePackSpec {
"example" should {
@@ -24,6 +40,5 @@ class MessagePackExampleTest extends MessagePackSpec {
"have configuration example" in {
MessagePackExample.configuration();
}
-
}
}
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..e545d7d2a 100644
--- a/msgpack-core/src/test/scala/org/msgpack/value/RawStringValueImplTest.scala
+++ b/msgpack-core/src/test/scala/org/msgpack/value/RawStringValueImplTest.scala
@@ -1,13 +1,29 @@
+//
+// 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.MessagePackSpec
-class RawStringValueImplTest extends MessagePackSpec {
+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..a8d996376 100644
--- a/msgpack-core/src/test/scala/org/msgpack/value/ValueFactoryTest.scala
+++ b/msgpack-core/src/test/scala/org/msgpack/value/ValueFactoryTest.scala
@@ -1,53 +1,69 @@
+//
+// 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.scalatest.FunSuite
import org.msgpack.core.MessagePackSpec
/**
- * Created on 6/13/14.
+ *
*/
-class ValueFactoryTest extends MessagePackSpec {
+class ValueFactoryTest
+ extends MessagePackSpec {
- def isValid(v:Value,
- expected:ValueType,
+ def isValid(v: Value,
+ expected: ValueType,
isNil: Boolean = false,
isBoolean: Boolean = false,
isInteger: Boolean = false,
- isString : Boolean = false,
+ isString: Boolean = false,
isFloat: Boolean = false,
isBinary: Boolean = false,
isArray: Boolean = false,
isMap: Boolean = false,
- isExtended : Boolean = false,
- isRaw : Boolean = false,
- isNumber : 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)
- 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: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)}
+ 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.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.newExtension(0, v), expected = ValueType
+ .EXTENSION, isExtension = true, isRaw = true)
+ }
}
-
}
}
diff --git a/msgpack-core/src/test/scala/org/msgpack/value/ValueTest.scala b/msgpack-core/src/test/scala/org/msgpack/value/ValueTest.scala
new file mode 100644
index 000000000..6cb7af603
--- /dev/null
+++ b/msgpack-core/src/test/scala/org/msgpack/value/ValueTest.scala
@@ -0,0 +1,130 @@
+//
+// 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._
+
+import scala.util.parsing.json.JSON
+
+class ValueTest extends MessagePackSpec
+{
+ def checkSuccinctType(pack:MessagePacker => Unit, expectedAtMost:MessageFormat) {
+ val b = createMessagePackData(pack)
+ val v1 = MessagePack.newDefaultUnpacker(b).unpackValue()
+ val mf = v1.asIntegerValue().mostSuccinctMessageFormat()
+ mf.getValueType shouldBe ValueType.INTEGER
+ mf.ordinal() shouldBe <= (expectedAtMost.ordinal())
+
+ val v2 = new Variable
+ MessagePack.newDefaultUnpacker(b).unpackValue(v2)
+ val mf2 = v2.asIntegerValue().mostSuccinctMessageFormat()
+ mf2.getValueType shouldBe ValueType.INTEGER
+ mf2.ordinal() shouldBe <= (expectedAtMost.ordinal())
+ }
+
+ "Value" should {
+ "tell most succinct integer type" in {
+ forAll { (v: Byte) => checkSuccinctType(_.packByte(v), MessageFormat.INT8) }
+ forAll { (v: Short) => checkSuccinctType(_.packShort(v), MessageFormat.INT16) }
+ forAll { (v: Int) => checkSuccinctType(_.packInt(v), MessageFormat.INT32) }
+ forAll { (v: Long) => checkSuccinctType(_.packLong(v), MessageFormat.INT64) }
+ forAll { (v: Long) => checkSuccinctType(_.packBigInteger(BigInteger.valueOf(v)), MessageFormat.INT64) }
+ forAll { (v: Long) =>
+ whenever(v > 0) {
+ // Create value between 2^63-1 < v <= 2^64-1
+ checkSuccinctType(_.packBigInteger(BigInteger.valueOf(Long.MaxValue).add(BigInteger.valueOf(v))), MessageFormat.UINT64)
+ }
+ }
+ }
+
+ "produce json strings" in {
+
+ import ValueFactory._
+
+ newNil().toJson shouldBe "null"
+ newNil().toString shouldBe "null"
+
+ newBoolean(true).toJson shouldBe "true"
+ newBoolean(false).toJson shouldBe "false"
+ newBoolean(true).toString shouldBe "true"
+ newBoolean(false).toString shouldBe "false"
+
+ newInteger(3).toJson shouldBe "3"
+ newInteger(3).toString shouldBe "3"
+ newInteger(BigInteger.valueOf(1324134134134L)).toJson shouldBe "1324134134134"
+ newInteger(BigInteger.valueOf(1324134134134L)).toString shouldBe "1324134134134"
+
+ newFloat(0.1).toJson shouldBe "0.1"
+ newFloat(0.1).toString shouldBe "0.1"
+
+ newArray(newInteger(0), newString("hello")).toJson shouldBe "[0,\"hello\"]"
+ newArray(newInteger(0), newString("hello")).toString shouldBe "[0,\"hello\"]"
+ newArray(newArray(newString("Apple"), newFloat(0.2)), newNil()).toJson shouldBe """[["Apple",0.2],null]"""
+
+ // Map value
+ val m = newMapBuilder()
+ .put(newString("id"), newInteger(1001))
+ .put(newString("name"), newString("leo"))
+ .put(newString("address"), newArray(newString("xxx-xxxx"), newString("yyy-yyyy")))
+ .put(newString("name"), newString("mitsu"))
+ .build()
+ val i1 = JSON.parseFull(m.toJson)
+ val i2 = JSON.parseFull(m.toString) // expect json value
+ val a1 = JSON.parseFull("""{"id":1001,"name":"mitsu","address":["xxx-xxxx","yyy-yyyy"]}""")
+ // Equals as JSON map
+ i1 shouldBe a1
+ i2 shouldBe a1
+
+ // toJson should quote strings
+ newString("1").toJson shouldBe "\"1\""
+ // toString is for extracting string values
+ newString("1").toString shouldBe "1"
+
+ }
+
+ "check appropriate range for integers" in {
+ import ValueFactory._
+ import java.lang.Byte
+ import java.lang.Short
+
+ newInteger(Byte.MAX_VALUE).asByte() shouldBe Byte.MAX_VALUE
+ newInteger(Byte.MIN_VALUE).asByte() shouldBe Byte.MIN_VALUE
+ newInteger(Short.MAX_VALUE).asShort() shouldBe Short.MAX_VALUE
+ newInteger(Short.MIN_VALUE).asShort() shouldBe Short.MIN_VALUE
+ newInteger(Integer.MAX_VALUE).asInt() shouldBe Integer.MAX_VALUE
+ newInteger(Integer.MIN_VALUE).asInt() shouldBe Integer.MIN_VALUE
+ intercept[MessageIntegerOverflowException] {
+ newInteger(Byte.MAX_VALUE+1).asByte()
+ }
+ intercept[MessageIntegerOverflowException] {
+ newInteger(Byte.MIN_VALUE-1).asByte()
+ }
+ intercept[MessageIntegerOverflowException] {
+ newInteger(Short.MAX_VALUE+1).asShort()
+ }
+ intercept[MessageIntegerOverflowException] {
+ newInteger(Short.MIN_VALUE-1).asShort()
+ }
+ intercept[MessageIntegerOverflowException] {
+ newInteger(Integer.MAX_VALUE+1.toLong).asInt()
+ }
+ intercept[MessageIntegerOverflowException] {
+ newInteger(Integer.MIN_VALUE-1.toLong).asInt()
+ }
+ }
+ }
+}
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..979c33c9b 100644
--- a/msgpack-core/src/test/scala/org/msgpack/value/ValueTypeTest.scala
+++ b/msgpack-core/src/test/scala/org/msgpack/value/ValueTypeTest.scala
@@ -1,109 +1,92 @@
+//
+// 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 scala.util.Random
-import org.msgpack.core.MessagePack.Code
-import org.msgpack.core.{MessageFormat, MessageFormatException, MessagePackSpec}
import org.msgpack.core.MessagePack.Code._
-
+import org.msgpack.core.{MessageFormat, MessageFormatException, MessagePackSpec}
/**
- * Created on 2014/05/06.
- */
-class ValueTypeTest extends MessagePackSpec {
+ * Created on 2014/05/06.
+ */
+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))
- check(t, ValueType.ARRAY)
-
- 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
- }
- }
-
+ for (t <- Seq(ARRAY16, ARRAY32)) {
+ check(t, ValueType.ARRAY)
}
- }
-
- "support isTypeOf" in {
- for(v <- ValueType.values()) {
- v.isTypeOf(v.getBitMask) shouldBe true
+ for (i <- 0xe0 until 0xff) {
+ check(i.toByte, ValueType.INTEGER)
}
}
-
-
}
}
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/README.md b/msgpack-jackson/README.md
index a10b2c6aa..51435b401 100644
--- a/msgpack-jackson/README.md
+++ b/msgpack-jackson/README.md
@@ -1,26 +1,38 @@
# jackson-dataformat-msgpack
This Jackson extension library handles reading and writing of data encoded in [MessagePack](http://msgpack.org/) data format.
-It extends standard Jackson streaming API (`JsonFactory`, `JsonParser`, `JsonGenerator`), and as such works seamlessly with all the higher level data abstractions (data binding, tree model, and pluggable extensions).
+It extends standard Jackson streaming API (`JsonFactory`, `JsonParser`, `JsonGenerator`), and as such works seamlessly with all the higher level data abstractions (data binding, tree model, and pluggable extensions). For the details of Jackson-annotations, please see https://github.com/FasterXML/jackson-annotations.
-## Maven dependency
+## Install
-To use this module on Maven-based projects, use following dependency:
+### Maven
```
org.msgpack
jackson-dataformat-msgpack
- 0.7.0-p5
+ 0.7.1
```
+### Gradle
+```
+repositories {
+ mavenCentral()
+}
+
+dependencies {
+ compile 'org.msgpack:jackson-dataformat-msgpack:0.7.1'
+}
+```
+
+
## Usage
-Only thing you need to do is to instantiate MessagePackFactory and pass it to the constructor of ObjectMapper.
+Only thing you need to do is to instantiate MessagePackFormatFactory and pass it to the constructor of ObjectMapper.
```
- ObjectMapper objectMapper = new ObjectMapper(new MessagePackFactory());
+ ObjectMapper objectMapper = new ObjectMapper(new MessagePackFormatFactory());
ExamplePojo orig = new ExamplePojo("komamitsu");
byte[] bytes = objectMapper.writeValueAsBytes(orig);
ExamplePojo value = objectMapper.readValue(bytes, ExamplePojo.class);
diff --git a/msgpack-jackson/src/main/java/org/msgpack/jackson/dataformat/MessagePackExtensionType.java b/msgpack-jackson/src/main/java/org/msgpack/jackson/dataformat/MessagePackExtensionType.java
new file mode 100644
index 000000000..1906757f5
--- /dev/null
+++ b/msgpack-jackson/src/main/java/org/msgpack/jackson/dataformat/MessagePackExtensionType.java
@@ -0,0 +1,48 @@
+package org.msgpack.jackson.dataformat;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+
+import java.io.IOException;
+
+@JsonSerialize(using = MessagePackExtensionType.Serializer.class)
+public class MessagePackExtensionType
+{
+ private final byte type;
+ private final byte[] data;
+
+ public MessagePackExtensionType(byte type, byte[] data)
+ {
+ this.type = type;
+ this.data = data;
+ }
+
+ public byte getType()
+ {
+ return type;
+ }
+
+ public byte[] getData()
+ {
+ return data;
+ }
+
+ public static class Serializer extends JsonSerializer
+ {
+ @Override
+ public void serialize(MessagePackExtensionType value, JsonGenerator gen, SerializerProvider serializers)
+ throws IOException, JsonProcessingException
+ {
+ if (gen instanceof MessagePackGenerator) {
+ MessagePackGenerator msgpackGenerator = (MessagePackGenerator) gen;
+ msgpackGenerator.writeExtensionType(value);
+ }
+ else {
+ throw new IllegalStateException("'gen' is expected to be MessagePackGenerator but it's " + gen.getClass());
+ }
+ }
+ }
+}
diff --git a/msgpack-jackson/src/main/java/org/msgpack/jackson/dataformat/MessagePackFactory.java b/msgpack-jackson/src/main/java/org/msgpack/jackson/dataformat/MessagePackFactory.java
index 3d63f22a2..ff7aa373f 100644
--- a/msgpack-jackson/src/main/java/org/msgpack/jackson/dataformat/MessagePackFactory.java
+++ b/msgpack-jackson/src/main/java/org/msgpack/jackson/dataformat/MessagePackFactory.java
@@ -15,56 +15,79 @@
//
package org.msgpack.jackson.dataformat;
-import com.fasterxml.jackson.core.*;
+import com.fasterxml.jackson.core.JsonEncoding;
+import com.fasterxml.jackson.core.JsonFactory;
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.core.JsonParseException;
+import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.io.IOContext;
-import java.io.*;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.Writer;
import java.util.Arrays;
-public class MessagePackFactory extends JsonFactory {
+public class MessagePackFactory
+ extends JsonFactory
+{
private static final long serialVersionUID = 2578263992015504347L;
- protected int messagePackGeneratorFeature = 0;
- protected int messagePackParserFeature = 0;
@Override
- public JsonGenerator createGenerator(OutputStream out, JsonEncoding enc) throws IOException {
- return new MessagePackGenerator(messagePackGeneratorFeature, _objectCodec, out);
+ public JsonGenerator createGenerator(OutputStream out, JsonEncoding enc)
+ throws IOException
+ {
+ return new MessagePackGenerator(_generatorFeatures, _objectCodec, out);
}
@Override
- public JsonGenerator createGenerator(File f, JsonEncoding enc) throws IOException {
+ public JsonGenerator createGenerator(File f, JsonEncoding enc)
+ throws IOException
+ {
return createGenerator(new FileOutputStream(f), enc);
}
@Override
- public JsonGenerator createGenerator(Writer w) throws IOException {
+ public JsonGenerator createGenerator(Writer w)
+ throws IOException
+ {
throw new UnsupportedOperationException();
}
@Override
- public JsonParser createParser(byte[] data) throws IOException, JsonParseException {
+ public JsonParser createParser(byte[] data)
+ throws IOException, JsonParseException
+ {
IOContext ioContext = _createContext(data, false);
return _createParser(data, 0, data.length, ioContext);
}
@Override
- public JsonParser createParser(InputStream in) throws IOException, JsonParseException {
+ public JsonParser createParser(InputStream in)
+ throws IOException, JsonParseException
+ {
IOContext ioContext = _createContext(in, false);
return _createParser(in, ioContext);
}
@Override
- protected MessagePackParser _createParser(InputStream in, IOContext ctxt) throws IOException {
- MessagePackParser parser = new MessagePackParser(ctxt, messagePackParserFeature, in);
+ protected MessagePackParser _createParser(InputStream in, IOContext ctxt)
+ throws IOException
+ {
+ MessagePackParser parser = new MessagePackParser(ctxt, _parserFeatures, _objectCodec, in);
return parser;
}
@Override
- protected JsonParser _createParser(byte[] data, int offset, int len, IOContext ctxt) throws IOException, JsonParseException {
+ protected JsonParser _createParser(byte[] data, int offset, int len, IOContext ctxt)
+ throws IOException, JsonParseException
+ {
if (offset != 0 || len != data.length) {
data = Arrays.copyOfRange(data, offset, offset + len);
}
- MessagePackParser parser = new MessagePackParser(ctxt, messagePackParserFeature, data);
+ MessagePackParser parser = new MessagePackParser(ctxt, _parserFeatures, _objectCodec, data);
return parser;
}
}
diff --git a/msgpack-jackson/src/main/java/org/msgpack/jackson/dataformat/MessagePackGenerator.java b/msgpack-jackson/src/main/java/org/msgpack/jackson/dataformat/MessagePackGenerator.java
index 7e21ff58b..e62528a75 100644
--- a/msgpack-jackson/src/main/java/org/msgpack/jackson/dataformat/MessagePackGenerator.java
+++ b/msgpack-jackson/src/main/java/org/msgpack/jackson/dataformat/MessagePackGenerator.java
@@ -1,3 +1,18 @@
+//
+// 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.jackson.dataformat;
import com.fasterxml.jackson.core.Base64Variant;
@@ -5,6 +20,7 @@
import com.fasterxml.jackson.core.ObjectCodec;
import com.fasterxml.jackson.core.base.GeneratorBase;
import com.fasterxml.jackson.core.json.JsonWriteContext;
+import org.msgpack.core.MessagePack;
import org.msgpack.core.MessagePacker;
import org.msgpack.core.buffer.OutputStreamBufferOutput;
@@ -18,56 +34,70 @@
import java.util.LinkedList;
import java.util.List;
-public class MessagePackGenerator extends GeneratorBase {
+public class MessagePackGenerator
+ extends GeneratorBase
+{
private static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
private static ThreadLocal messagePackersHolder = new ThreadLocal();
private static ThreadLocal messageBufferOutputHolder = new ThreadLocal();
private LinkedList stack;
private StackItem rootStackItem;
-
- private static abstract class StackItem {
+ private abstract static class StackItem
+ {
protected List objectKeys = new ArrayList();
protected List objectValues = new ArrayList();
abstract void addKey(String key);
- void addValue(Object value) {
+ void addValue(Object value)
+ {
objectValues.add(value);
}
abstract List getKeys();
- List getValues() {
+ List getValues()
+ {
return objectValues;
}
}
- private static class StackItemForObject extends StackItem {
+ private static class StackItemForObject
+ extends StackItem
+ {
@Override
- void addKey(String key) {
+ void addKey(String key)
+ {
objectKeys.add(key);
}
@Override
- List getKeys() {
+ List getKeys()
+ {
return objectKeys;
}
}
- private static class StackItemForArray extends StackItem {
+ private static class StackItemForArray
+ extends StackItem
+ {
@Override
- void addKey(String key) {
+ void addKey(String key)
+ {
throw new IllegalStateException("This method shouldn't be called");
}
@Override
- List getKeys() {
+ List getKeys()
+ {
throw new IllegalStateException("This method shouldn't be called");
}
}
- public MessagePackGenerator(int features, ObjectCodec codec, OutputStream out) throws IOException {
+ public MessagePackGenerator(int features, ObjectCodec codec, OutputStream out)
+ throws IOException
+ {
super(features, codec);
MessagePacker messagePacker = messagePackersHolder.get();
OutputStreamBufferOutput messageBufferOutput = messageBufferOutputHolder.get();
@@ -80,7 +110,7 @@ public MessagePackGenerator(int features, ObjectCodec codec, OutputStream out) t
messageBufferOutputHolder.set(messageBufferOutput);
if (messagePacker == null) {
- messagePacker = new MessagePacker(messageBufferOutput);
+ messagePacker = MessagePack.newDefaultPacker(messageBufferOutput);
}
else {
messagePacker.reset(messageBufferOutput);
@@ -91,13 +121,17 @@ public MessagePackGenerator(int features, ObjectCodec codec, OutputStream out) t
}
@Override
- public void writeStartArray() throws IOException, JsonGenerationException {
+ public void writeStartArray()
+ throws IOException, JsonGenerationException
+ {
_writeContext = _writeContext.createChildArrayContext();
stack.push(new StackItemForArray());
}
@Override
- public void writeEndArray() throws IOException, JsonGenerationException {
+ public void writeEndArray()
+ throws IOException, JsonGenerationException
+ {
if (!_writeContext.inArray()) {
_reportError("Current context not an array but " + _writeContext.getTypeDesc());
}
@@ -110,13 +144,17 @@ public void writeEndArray() throws IOException, JsonGenerationException {
}
@Override
- public void writeStartObject() throws IOException, JsonGenerationException {
+ public void writeStartObject()
+ throws IOException, JsonGenerationException
+ {
_writeContext = _writeContext.createChildObjectContext();
stack.push(new StackItemForObject());
}
@Override
- public void writeEndObject() throws IOException, JsonGenerationException {
+ public void writeEndObject()
+ throws IOException, JsonGenerationException
+ {
if (!_writeContext.inObject()) {
_reportError("Current context not an object but " + _writeContext.getTypeDesc());
}
@@ -134,7 +172,9 @@ public void writeEndObject() throws IOException, JsonGenerationException {
popStackAndStoreTheItemAsValue();
}
- private void packValue(Object v) throws IOException {
+ private void packValue(Object v)
+ throws IOException
+ {
MessagePacker messagePacker = getMessagePacker();
if (v == null) {
messagePacker.packNil();
@@ -144,8 +184,17 @@ else if (v instanceof Integer) {
}
else if (v instanceof ByteBuffer) {
ByteBuffer bb = (ByteBuffer) v;
- messagePacker.packBinaryHeader(bb.limit());
- messagePacker.writePayload(bb);
+ int len = bb.remaining();
+ if (bb.hasArray()) {
+ messagePacker.packBinaryHeader(len);
+ messagePacker.writePayload(bb.array(), bb.arrayOffset(), len);
+ }
+ else {
+ byte[] data = new byte[len];
+ bb.get(data);
+ messagePacker.packBinaryHeader(len);
+ messagePacker.addPayload(data);
+ }
}
else if (v instanceof String) {
messagePacker.packString((String) v);
@@ -169,18 +218,52 @@ else if (v instanceof BigInteger) {
messagePacker.packBigInteger((BigInteger) v);
}
else if (v instanceof BigDecimal) {
- // TODO
- throw new UnsupportedOperationException("BigDecimal isn't supported yet");
+ packBigDecimal((BigDecimal) v);
}
else if (v instanceof Boolean) {
messagePacker.packBoolean((Boolean) v);
}
+ else if (v instanceof MessagePackExtensionType) {
+ MessagePackExtensionType extensionType = (MessagePackExtensionType) v;
+ byte[] extData = extensionType.getData();
+ messagePacker.packExtensionTypeHeader(extensionType.getType(), extData.length);
+ messagePacker.writePayload(extData);
+ }
else {
throw new IllegalArgumentException(v.toString());
}
}
- private void packObject(StackItemForObject stackItem) throws IOException {
+ private void packBigDecimal(BigDecimal decimal)
+ throws IOException
+ {
+ MessagePacker messagePacker = getMessagePacker();
+ boolean failedToPackAsBI = false;
+ try {
+ //Check to see if this BigDecimal can be converted to BigInteger
+ BigInteger integer = decimal.toBigIntegerExact();
+ messagePacker.packBigInteger(integer);
+ }
+ catch (ArithmeticException e) {
+ failedToPackAsBI = true;
+ }
+ catch (IllegalArgumentException e) {
+ failedToPackAsBI = true;
+ }
+
+ if (failedToPackAsBI) {
+ double doubleValue = decimal.doubleValue();
+ //Check to make sure this BigDecimal can be represented as a double
+ if (!decimal.stripTrailingZeros().toEngineeringString().equals(BigDecimal.valueOf(doubleValue).toEngineeringString())) {
+ throw new IllegalArgumentException("MessagePack cannot serialize a BigDecimal that can't be represented as double. " + decimal);
+ }
+ messagePacker.packDouble(doubleValue);
+ }
+ }
+
+ private void packObject(StackItemForObject stackItem)
+ throws IOException
+ {
List keys = stackItem.getKeys();
List values = stackItem.getValues();
@@ -194,7 +277,9 @@ private void packObject(StackItemForObject stackItem) throws IOException {
}
}
- private void packArray(StackItemForArray stackItem) throws IOException {
+ private void packArray(StackItemForArray stackItem)
+ throws IOException
+ {
List values = stackItem.getValues();
MessagePacker messagePacker = getMessagePacker();
@@ -207,116 +292,163 @@ private void packArray(StackItemForArray stackItem) throws IOException {
}
@Override
- public void writeFieldName(String name) throws IOException, JsonGenerationException {
+ public void writeFieldName(String name)
+ throws IOException, JsonGenerationException
+ {
addKeyToStackTop(name);
}
@Override
- public void writeString(String text) throws IOException, JsonGenerationException {
+ public void writeString(String text)
+ throws IOException, JsonGenerationException
+ {
addValueToStackTop(text);
}
@Override
- public void writeString(char[] text, int offset, int len) throws IOException, JsonGenerationException {
+ public void writeString(char[] text, int offset, int len)
+ throws IOException, JsonGenerationException
+ {
addValueToStackTop(new String(text, offset, len));
}
@Override
- public void writeRawUTF8String(byte[] text, int offset, int length) throws IOException, JsonGenerationException {
+ public void writeRawUTF8String(byte[] text, int offset, int length)
+ throws IOException, JsonGenerationException
+ {
addValueToStackTop(new String(text, offset, length, DEFAULT_CHARSET));
}
@Override
- public void writeUTF8String(byte[] text, int offset, int length) throws IOException, JsonGenerationException {
+ public void writeUTF8String(byte[] text, int offset, int length)
+ throws IOException, JsonGenerationException
+ {
addValueToStackTop(new String(text, offset, length, DEFAULT_CHARSET));
}
@Override
- public void writeRaw(String text) throws IOException, JsonGenerationException {
+ public void writeRaw(String text)
+ throws IOException, JsonGenerationException
+ {
addValueToStackTop(text);
}
@Override
- public void writeRaw(String text, int offset, int len) throws IOException, JsonGenerationException {
+ public void writeRaw(String text, int offset, int len)
+ throws IOException, JsonGenerationException
+ {
addValueToStackTop(text.substring(0, len));
}
@Override
- public void writeRaw(char[] text, int offset, int len) throws IOException, JsonGenerationException {
+ public void writeRaw(char[] text, int offset, int len)
+ throws IOException, JsonGenerationException
+ {
addValueToStackTop(new String(text, offset, len));
}
@Override
- public void writeRaw(char c) throws IOException, JsonGenerationException {
+ public void writeRaw(char c)
+ throws IOException, JsonGenerationException
+ {
addValueToStackTop(String.valueOf(c));
}
@Override
- public void writeBinary(Base64Variant b64variant, byte[] data, int offset, int len) throws IOException, JsonGenerationException {
+ public void writeBinary(Base64Variant b64variant, byte[] data, int offset, int len)
+ throws IOException, JsonGenerationException
+ {
addValueToStackTop(ByteBuffer.wrap(data, offset, len));
}
@Override
- public void writeNumber(int v) throws IOException, JsonGenerationException {
+ public void writeNumber(int v)
+ throws IOException, JsonGenerationException
+ {
addValueToStackTop(Integer.valueOf(v));
}
@Override
- public void writeNumber(long v) throws IOException, JsonGenerationException {
+ public void writeNumber(long v)
+ throws IOException, JsonGenerationException
+ {
addValueToStackTop(Long.valueOf(v));
}
@Override
- public void writeNumber(BigInteger v) throws IOException, JsonGenerationException {
+ public void writeNumber(BigInteger v)
+ throws IOException, JsonGenerationException
+ {
addValueToStackTop(v);
}
@Override
- public void writeNumber(double d) throws IOException, JsonGenerationException {
+ public void writeNumber(double d)
+ throws IOException, JsonGenerationException
+ {
addValueToStackTop(Double.valueOf(d));
}
@Override
- public void writeNumber(float f) throws IOException, JsonGenerationException {
+ public void writeNumber(float f)
+ throws IOException, JsonGenerationException
+ {
addValueToStackTop(Float.valueOf(f));
}
@Override
- public void writeNumber(BigDecimal dec) throws IOException, JsonGenerationException {
+ public void writeNumber(BigDecimal dec)
+ throws IOException, JsonGenerationException
+ {
addValueToStackTop(dec);
}
@Override
- public void writeNumber(String encodedValue) throws IOException, JsonGenerationException, UnsupportedOperationException {
+ public void writeNumber(String encodedValue)
+ throws IOException, JsonGenerationException, UnsupportedOperationException
+ {
throw new UnsupportedOperationException("writeNumber(String encodedValue) isn't supported yet");
}
@Override
- public void writeBoolean(boolean state) throws IOException, JsonGenerationException {
+ public void writeBoolean(boolean state)
+ throws IOException, JsonGenerationException
+ {
addValueToStackTop(Boolean.valueOf(state));
}
@Override
- public void writeNull() throws IOException, JsonGenerationException {
+ public void writeNull()
+ throws IOException, JsonGenerationException
+ {
addValueToStackTop(null);
}
+ public void writeExtensionType(MessagePackExtensionType extensionType)
+ throws IOException
+ {
+ addValueToStackTop(extensionType);
+ }
+
@Override
- public void close() throws IOException {
+ public void close()
+ throws IOException
+ {
try {
flush();
}
- catch (Exception e) {
- e.printStackTrace();
- }
finally {
- MessagePacker messagePacker = getMessagePacker();
- messagePacker.close();
+ if (isEnabled(Feature.AUTO_CLOSE_TARGET)) {
+ MessagePacker messagePacker = getMessagePacker();
+ messagePacker.close();
+ }
}
}
@Override
- public void flush() throws IOException {
+ public void flush()
+ throws IOException
+ {
if (rootStackItem != null) {
if (rootStackItem instanceof StackItemForObject) {
packObject((StackItemForObject) rootStackItem);
@@ -328,32 +460,42 @@ else if (rootStackItem instanceof StackItemForArray) {
throw new IllegalStateException("Unexpected rootStackItem: " + rootStackItem);
}
rootStackItem = null;
- MessagePacker messagePacker = getMessagePacker();
- messagePacker.flush();
+ flushMessagePacker();
}
}
- @Override
- protected void _releaseBuffers() {
+ private void flushMessagePacker()
+ throws IOException
+ {
+ MessagePacker messagePacker = getMessagePacker();
+ messagePacker.flush();
+ }
+ @Override
+ protected void _releaseBuffers()
+ {
}
@Override
- protected void _verifyValueWrite(String typeMsg) throws IOException, JsonGenerationException {
+ protected void _verifyValueWrite(String typeMsg)
+ throws IOException, JsonGenerationException
+ {
int status = _writeContext.writeValue();
if (status == JsonWriteContext.STATUS_EXPECT_NAME) {
- _reportError("Can not "+typeMsg+", expecting field name");
+ _reportError("Can not " + typeMsg + ", expecting field name");
}
}
- private StackItem getStackTop() {
+ private StackItem getStackTop()
+ {
if (stack.isEmpty()) {
throw new IllegalStateException("The stack is empty");
}
return stack.getFirst();
}
- private StackItemForObject getStackTopForObject() {
+ private StackItemForObject getStackTopForObject()
+ {
StackItem stackTop = getStackTop();
if (!(stackTop instanceof StackItemForObject)) {
throw new IllegalStateException("The stack top should be Object: " + stackTop);
@@ -361,7 +503,8 @@ private StackItemForObject getStackTopForObject() {
return (StackItemForObject) stackTop;
}
- private StackItemForArray getStackTopForArray() {
+ private StackItemForArray getStackTopForArray()
+ {
StackItem stackTop = getStackTop();
if (!(stackTop instanceof StackItemForArray)) {
throw new IllegalStateException("The stack top should be Array: " + stackTop);
@@ -369,15 +512,26 @@ private StackItemForArray getStackTopForArray() {
return (StackItemForArray) stackTop;
}
- private void addKeyToStackTop(String key) {
+ private void addKeyToStackTop(String key)
+ {
getStackTop().addKey(key);
}
- private void addValueToStackTop(Object value) {
- getStackTop().addValue(value);
+ private void addValueToStackTop(Object value)
+ throws IOException
+ {
+ if (stack.isEmpty()) {
+ packValue(value);
+ flushMessagePacker();
+ }
+ else {
+ getStackTop().addValue(value);
+ }
}
- private void popStackAndStoreTheItemAsValue() {
+ private void popStackAndStoreTheItemAsValue()
+ throws IOException
+ {
StackItem child = stack.pop();
if (stack.size() > 0) {
addValueToStackTop(child);
@@ -392,7 +546,8 @@ private void popStackAndStoreTheItemAsValue() {
}
}
- private MessagePacker getMessagePacker() {
+ private MessagePacker getMessagePacker()
+ {
MessagePacker messagePacker = messagePackersHolder.get();
if (messagePacker == null) {
throw new IllegalStateException("messagePacker is null");
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 926b5691b..e85ff7cd6 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
@@ -1,18 +1,44 @@
+//
+// 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.jackson.dataformat;
-import com.fasterxml.jackson.core.*;
+import com.fasterxml.jackson.core.Base64Variant;
+import com.fasterxml.jackson.core.JsonLocation;
+import com.fasterxml.jackson.core.JsonParseException;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.core.JsonStreamContext;
+import com.fasterxml.jackson.core.JsonToken;
+import com.fasterxml.jackson.core.ObjectCodec;
+import com.fasterxml.jackson.core.Version;
import com.fasterxml.jackson.core.base.ParserMinimalBase;
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.MessagePack;
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.NumberValue;
+import org.msgpack.value.ExtensionValue;
+import org.msgpack.value.IntegerValue;
+import org.msgpack.value.Value;
+import org.msgpack.value.ValueFactory;
import org.msgpack.value.ValueType;
-import org.msgpack.value.holder.ValueHolder;
+import org.msgpack.value.Variable;
import java.io.IOException;
import java.io.InputStream;
@@ -20,88 +46,124 @@
import java.math.BigInteger;
import java.util.LinkedList;
-public class MessagePackParser extends ParserMinimalBase {
- private static final ThreadLocal messageUnpackerHolder = new ThreadLocal();
+public class MessagePackParser
+ extends ParserMinimalBase
+{
+ private static final ThreadLocal> messageUnpackerHolder =
+ new ThreadLocal>();
private ObjectCodec codec;
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;
private final IOContext ioContext;
- private static abstract class StackItem {
+ private abstract static class StackItem
+ {
private long numOfElements;
- protected StackItem(long numOfElements) {
+ protected StackItem(long numOfElements)
+ {
this.numOfElements = numOfElements;
}
- public void consume() {
- numOfElements--;
+ public void consume()
+ {
+ numOfElements--;
}
- public boolean isEmpty() {
+ public boolean isEmpty()
+ {
return numOfElements == 0;
}
}
- private static class StackItemForObject extends StackItem {
- StackItemForObject(long numOfElements) {
+ private static class StackItemForObject
+ extends StackItem
+ {
+ StackItemForObject(long numOfElements)
+ {
super(numOfElements);
}
}
- private static class StackItemForArray extends StackItem {
- StackItemForArray(long numOfElements) {
+ private static class StackItemForArray
+ extends StackItem
+ {
+ StackItemForArray(long numOfElements)
+ {
super(numOfElements);
}
}
- public MessagePackParser(IOContext ctxt, int features, InputStream in) throws IOException {
- this(ctxt, features, new InputStreamBufferInput(in));
+ public MessagePackParser(IOContext ctxt, int features, ObjectCodec objectCodec, InputStream in)
+ throws IOException
+ {
+ this(ctxt, features, new InputStreamBufferInput(in), objectCodec, in);
}
- public MessagePackParser(IOContext ctxt, int features, byte[] bytes) throws IOException {
- this(ctxt, features, new ArrayBufferInput(bytes));
+ public MessagePackParser(IOContext ctxt, int features, ObjectCodec objectCodec, byte[] bytes)
+ throws IOException
+ {
+ this(ctxt, features, new ArrayBufferInput(bytes), objectCodec, bytes);
}
- private MessagePackParser(IOContext ctxt, int features, MessageBufferInput input) throws IOException {
+ private MessagePackParser(IOContext ctxt, int features, MessageBufferInput input, ObjectCodec objectCodec, Object src)
+ throws IOException
+ {
+ super(features);
+
+ this.codec = objectCodec;
ioContext = ctxt;
DupDetector dups = Feature.STRICT_DUPLICATE_DETECTION.enabledIn(features)
? DupDetector.rootDetector(this) : null;
parsingContext = JsonReadContext.createRootContext(dups);
- MessageUnpacker messageUnpacker = messageUnpackerHolder.get();
- if (messageUnpacker == null) {
- messageUnpacker = new MessageUnpacker(input);
+ MessageUnpacker messageUnpacker;
+ Tuple messageUnpackerTuple = messageUnpackerHolder.get();
+ if (messageUnpackerTuple == null) {
+ messageUnpacker = MessagePack.newDefaultUnpacker(input);
}
else {
- messageUnpacker.reset(input);
+ // Considering to reuse InputStream with JsonParser.Feature.AUTO_CLOSE_SOURCE,
+ // MessagePackParser needs to use the MessageUnpacker that has the same InputStream
+ // since it has buffer which has loaded the InputStream data ahead.
+ // However, it needs to call MessageUnpacker#reset when the source is different from the previous one.
+ if (isEnabled(JsonParser.Feature.AUTO_CLOSE_SOURCE) || messageUnpackerTuple.first() != src) {
+ messageUnpackerTuple.second().reset(input);
+ }
+ messageUnpacker = messageUnpackerTuple.second();
}
- messageUnpackerHolder.set(messageUnpacker);
+ messageUnpackerHolder.set(new Tuple(src, messageUnpacker));
}
@Override
- public ObjectCodec getCodec() {
+ public ObjectCodec getCodec()
+ {
return codec;
}
@Override
- public void setCodec(ObjectCodec c) {
+ public void setCodec(ObjectCodec c)
+ {
codec = c;
}
@Override
- public Version version() {
+ public Version version()
+ {
return null;
}
@Override
- public JsonToken nextToken() throws IOException, JsonParseException {
+ public JsonToken nextToken()
+ throws IOException, JsonParseException
+ {
MessageUnpacker messageUnpacker = getMessageUnpacker();
tokenPosition = messageUnpacker.getTotalReadBytes();
@@ -116,33 +178,56 @@ public JsonToken nextToken() throws IOException, JsonParseException {
}
}
- MessageFormat nextFormat = messageUnpacker.getNextFormat();
- ValueType valueType = nextFormat.getValueType();
+ if (!messageUnpacker.hasNext()) {
+ return null;
+ }
+
+ 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();
- nextToken = b ? JsonToken.VALUE_TRUE : JsonToken.VALUE_FALSE;
+ value = ValueFactory.newNil();
+ if (parsingContext.inObject() && _currToken != JsonToken.FIELD_NAME) {
+ parsingContext.setCurrentName(Boolean.toString(b));
+ nextToken = JsonToken.FIELD_NAME;
+ }
+ else {
+ nextToken = b ? JsonToken.VALUE_TRUE : JsonToken.VALUE_FALSE;
+ }
break;
case INTEGER:
- messageUnpacker.unpackValue(valueHolder);
- nextToken = JsonToken.VALUE_NUMBER_INT;
+ value = messageUnpacker.unpackValue(var);
+ if (parsingContext.inObject() && _currToken != JsonToken.FIELD_NAME) {
+ parsingContext.setCurrentName(value.asIntegerValue().toString());
+ nextToken = JsonToken.FIELD_NAME;
+ }
+ else {
+ nextToken = JsonToken.VALUE_NUMBER_INT;
+ }
break;
case FLOAT:
- messageUnpacker.unpackValue(valueHolder);
- nextToken = JsonToken.VALUE_NUMBER_FLOAT;
+ value = messageUnpacker.unpackValue(var);
+ if (parsingContext.inObject() && _currToken != JsonToken.FIELD_NAME) {
+ parsingContext.setCurrentName(value.asFloatValue().toString());
+ nextToken = JsonToken.FIELD_NAME;
+ }
+ else {
+ 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().toString());
nextToken = JsonToken.FIELD_NAME;
}
else {
@@ -150,17 +235,27 @@ 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().toString());
+ 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:
- throw new UnsupportedOperationException();
+ case EXTENSION:
+ value = messageUnpacker.unpackValue(var);
+ nextToken = JsonToken.VALUE_EMBEDDED_OBJECT;
+ break;
default:
throw new IllegalStateException("Shouldn't reach here");
}
@@ -187,110 +282,183 @@ else if (newStack instanceof StackItemForObject) {
}
@Override
- protected void _handleEOF() throws JsonParseException {}
+ protected void _handleEOF()
+ throws JsonParseException
+ {
+ }
@Override
- public String getText() throws IOException, JsonParseException {
+ 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().toString();
+ }
+ else {
+ return value.toString();
+ }
}
@Override
- public char[] getTextCharacters() throws IOException, JsonParseException {
+ public char[] getTextCharacters()
+ throws IOException, JsonParseException
+ {
return getText().toCharArray();
}
@Override
- public boolean hasTextCharacters() {
+ public boolean hasTextCharacters()
+ {
return false;
}
@Override
- public int getTextLength() throws IOException, JsonParseException {
+ public int getTextLength()
+ throws IOException, JsonParseException
+ {
return getText().length();
}
@Override
- public int getTextOffset() throws IOException, JsonParseException {
+ public int getTextOffset()
+ throws IOException, JsonParseException
+ {
return 0;
}
@Override
- public byte[] getBinaryValue(Base64Variant b64variant) throws IOException, JsonParseException {
- return valueHolder.getRef().asBinary().toByteArray();
+ public byte[] getBinaryValue(Base64Variant b64variant)
+ throws IOException, JsonParseException
+ {
+ return value.asRawValue().asByteArray();
}
@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();
+ public Number getNumberValue()
+ throws IOException, JsonParseException
+ {
+ if (value.isIntegerValue()) {
+ IntegerValue integerValue = value.asIntegerValue();
+ if (integerValue.isInIntRange()) {
+ return integerValue.toInt();
+ }
+ else if (integerValue.isInLongRange()) {
+ return integerValue.toLong();
+ }
+ else {
+ return integerValue.toBigInteger();
+ }
}
else {
- return numberValue.toBigInteger();
+ return value.asNumberValue().toDouble();
}
}
@Override
- public int getIntValue() throws IOException, JsonParseException {
- return valueHolder.getRef().asNumber().toInt();
+ public int getIntValue()
+ throws IOException, JsonParseException
+ {
+ return value.asNumberValue().toInt();
}
@Override
- public long getLongValue() throws IOException, JsonParseException {
- return valueHolder.getRef().asNumber().toLong();
+ public long getLongValue()
+ throws IOException, JsonParseException
+ {
+ return value.asNumberValue().toLong();
}
@Override
- public BigInteger getBigIntegerValue() throws IOException, JsonParseException {
- return valueHolder.getRef().asNumber().toBigInteger();
+ public BigInteger getBigIntegerValue()
+ throws IOException, JsonParseException
+ {
+ return value.asNumberValue().toBigInteger();
}
@Override
- public float getFloatValue() throws IOException, JsonParseException {
- return valueHolder.getRef().asFloat().toFloat();
+ public float getFloatValue()
+ throws IOException, JsonParseException
+ {
+ return value.asNumberValue().toFloat();
}
@Override
- public double getDoubleValue() throws IOException, JsonParseException {
- return valueHolder.getRef().asFloat().toDouble();
+ public double getDoubleValue()
+ throws IOException, JsonParseException
+ {
+ return value.asNumberValue().toDouble();
}
@Override
- public BigDecimal getDecimalValue() throws IOException {
- return null;
+ public BigDecimal getDecimalValue()
+ throws IOException
+ {
+ if (value.isIntegerValue()) {
+ IntegerValue number = value.asIntegerValue();
+ //optimization to not convert the value to BigInteger unnecessarily
+ if (number.isInLongRange()) {
+ return BigDecimal.valueOf(number.toLong());
+ }
+ else {
+ return new BigDecimal(number.toBigInteger());
+ }
+ }
+ else if (value.isFloatValue()) {
+ return BigDecimal.valueOf(value.asFloatValue().toDouble());
+ }
+ else {
+ throw new UnsupportedOperationException("Couldn't parse value as BigDecimal. " + value);
+ }
}
@Override
- public Object getEmbeddedObject() throws IOException, JsonParseException {
- return valueHolder.getRef().asBinary().toByteArray();
+ public Object getEmbeddedObject()
+ throws IOException, JsonParseException
+ {
+ if (value.isBinaryValue()) {
+ return value.asBinaryValue().asByteArray();
+ }
+ else if (value.isExtensionValue()) {
+ ExtensionValue extensionValue = value.asExtensionValue();
+ return new MessagePackExtensionType(extensionValue.getType(), extensionValue.getData());
+ }
+ else {
+ throw new UnsupportedOperationException();
+ }
}
@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;
+ public NumberType getNumberType()
+ throws IOException, JsonParseException
+ {
+ 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 {
- return NumberType.BIG_INTEGER;
+ value.asNumberValue();
+ return NumberType.DOUBLE;
}
}
@Override
- public void close() throws IOException {
+ public void close()
+ throws IOException
+ {
try {
- MessageUnpacker messageUnpacker = getMessageUnpacker();
- messageUnpacker.close();
- }
- catch (Exception e) {
- e.printStackTrace();
+ if (isEnabled(JsonParser.Feature.AUTO_CLOSE_SOURCE)) {
+ MessageUnpacker messageUnpacker = getMessageUnpacker();
+ messageUnpacker.close();
+ }
}
finally {
isClosed = true;
@@ -298,27 +466,32 @@ public void close() throws IOException {
}
@Override
- public boolean isClosed() {
+ public boolean isClosed()
+ {
return isClosed;
}
@Override
- public JsonStreamContext getParsingContext() {
+ public JsonStreamContext getParsingContext()
+ {
return parsingContext;
}
@Override
- public JsonLocation getTokenLocation() {
+ public JsonLocation getTokenLocation()
+ {
return new JsonLocation(ioContext.getSourceReference(), tokenPosition, -1, -1, (int) tokenPosition);
}
@Override
- public JsonLocation getCurrentLocation() {
+ public JsonLocation getCurrentLocation()
+ {
return new JsonLocation(ioContext.getSourceReference(), currentPosition, -1, -1, (int) currentPosition);
}
@Override
- public void overrideCurrentName(String name) {
+ public void overrideCurrentName(String name)
+ {
try {
if (_currToken == JsonToken.START_OBJECT || _currToken == JsonToken.START_ARRAY) {
JsonReadContext parent = parsingContext.getParent();
@@ -327,12 +500,16 @@ public void overrideCurrentName(String name) {
else {
parsingContext.setCurrentName(name);
}
- } catch (JsonProcessingException e) {
+ }
+ catch (JsonProcessingException e) {
throw new IllegalStateException(e);
}
}
- @Override public String getCurrentName() throws IOException {
+ @Override
+ public String getCurrentName()
+ throws IOException
+ {
if (_currToken == JsonToken.START_OBJECT || _currToken == JsonToken.START_ARRAY) {
JsonReadContext parent = parsingContext.getParent();
return parent.getCurrentName();
@@ -340,11 +517,12 @@ public void overrideCurrentName(String name) {
return parsingContext.getCurrentName();
}
- private MessageUnpacker getMessageUnpacker() {
- MessageUnpacker messageUnpacker = messageUnpackerHolder.get();
- if (messageUnpacker == null) {
+ private MessageUnpacker getMessageUnpacker()
+ {
+ Tuple messageUnpackerTuple = messageUnpackerHolder.get();
+ if (messageUnpackerTuple == null) {
throw new IllegalStateException("messageUnpacker is null");
}
- return messageUnpacker;
+ return messageUnpackerTuple.second();
}
}
diff --git a/msgpack-jackson/src/main/java/org/msgpack/jackson/dataformat/Tuple.java b/msgpack-jackson/src/main/java/org/msgpack/jackson/dataformat/Tuple.java
new file mode 100644
index 000000000..1a252739f
--- /dev/null
+++ b/msgpack-jackson/src/main/java/org/msgpack/jackson/dataformat/Tuple.java
@@ -0,0 +1,41 @@
+//
+// 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.jackson.dataformat;
+
+/**
+ * Created by komamitsu on 5/28/15.
+ */
+public class Tuple
+{
+ private final F first;
+ private final S second;
+
+ public Tuple(F first, S second)
+ {
+ this.first = first;
+ this.second = second;
+ }
+
+ public F first()
+ {
+ return first;
+ }
+
+ public S second()
+ {
+ return second;
+ }
+}
diff --git a/msgpack-jackson/src/test/java/org/msgpack/jackson/dataformat/ExampleOfTypeInformationSerDe.java b/msgpack-jackson/src/test/java/org/msgpack/jackson/dataformat/ExampleOfTypeInformationSerDe.java
new file mode 100644
index 000000000..5414b0bdc
--- /dev/null
+++ b/msgpack-jackson/src/test/java/org/msgpack/jackson/dataformat/ExampleOfTypeInformationSerDe.java
@@ -0,0 +1,167 @@
+//
+// 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.jackson.dataformat;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.core.TreeNode;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+
+public class ExampleOfTypeInformationSerDe
+ extends MessagePackDataformatTestBase
+{
+ static class A
+ {
+ private List list = new ArrayList();
+
+ public List getList()
+ {
+ return list;
+ }
+
+ public void setList(List list)
+ {
+ this.list = list;
+ }
+ }
+
+ static class B
+ {
+ private String str;
+
+ public String getStr()
+ {
+ return str;
+ }
+
+ public void setStr(String str)
+ {
+ this.str = str;
+ }
+ }
+
+ @JsonSerialize(using = ObjectContainerSerializer.class)
+ @JsonDeserialize(using = ObjectContainerDeserializer.class)
+ static class ObjectContainer
+ {
+ private final Map objects;
+
+ public ObjectContainer(Map objects)
+ {
+ this.objects = objects;
+ }
+
+ public Map getObjects()
+ {
+ return objects;
+ }
+ }
+
+ static class ObjectContainerSerializer
+ extends JsonSerializer
+ {
+ @Override
+ public void serialize(ObjectContainer value, JsonGenerator gen, SerializerProvider serializers)
+ throws IOException, JsonProcessingException
+ {
+ gen.writeStartObject();
+ HashMap metadata = new HashMap();
+ for (Map.Entry entry : value.getObjects().entrySet()) {
+ metadata.put(entry.getKey(), entry.getValue().getClass().getName());
+ }
+ gen.writeObjectField("__metadata", metadata);
+ gen.writeObjectField("objects", value.getObjects());
+ gen.writeEndObject();
+ }
+ }
+
+ static class ObjectContainerDeserializer
+ extends JsonDeserializer
+ {
+ @Override
+ public ObjectContainer deserialize(JsonParser p, DeserializationContext ctxt)
+ throws IOException, JsonProcessingException
+ {
+ ObjectContainer objectContainer = new ObjectContainer(new HashMap());
+ TreeNode treeNode = p.readValueAsTree();
+
+ Map metadata = treeNode.get("__metadata").traverse(p.getCodec()).readValueAs(new TypeReference>() {});
+ TreeNode dataMapTree = treeNode.get("objects");
+ for (Map.Entry entry : metadata.entrySet()) {
+ try {
+ Object o = dataMapTree.get(entry.getKey()).traverse(p.getCodec()).readValueAs(Class.forName(entry.getValue()));
+ objectContainer.getObjects().put(entry.getKey(), o);
+ }
+ catch (ClassNotFoundException e) {
+ throw new RuntimeException("Failed to deserialize: " + entry, e);
+ }
+ }
+
+ return objectContainer;
+ }
+ }
+
+ @Test
+ public void test()
+ throws IOException
+ {
+ ObjectContainer objectContainer = new ObjectContainer(new HashMap());
+ {
+ A a = new A();
+ a.setList(Arrays.asList("first", "second", "third"));
+ objectContainer.getObjects().put("a", a);
+
+ B b = new B();
+ b.setStr("hello world");
+ objectContainer.getObjects().put("b", b);
+
+ Double pi = 3.14;
+ objectContainer.getObjects().put("pi", pi);
+ }
+
+ ObjectMapper objectMapper = new ObjectMapper(new MessagePackFactory());
+ byte[] bytes = objectMapper.writeValueAsBytes(objectContainer);
+ ObjectContainer restored = objectMapper.readValue(bytes, ObjectContainer.class);
+
+ {
+ assertEquals(3, restored.getObjects().size());
+ A a = (A) restored.getObjects().get("a");
+ assertArrayEquals(new String[] {"first", "second", "third"}, a.getList().toArray());
+ B b = (B) restored.getObjects().get("b");
+ assertEquals("hello world", b.getStr());
+ assertEquals(3.14, restored.getObjects().get("pi"));
+ }
+ }
+}
diff --git a/msgpack-jackson/src/test/java/org/msgpack/jackson/dataformat/MessagePackDataformatForPojoTest.java b/msgpack-jackson/src/test/java/org/msgpack/jackson/dataformat/MessagePackDataformatForPojoTest.java
index a27bc27fa..5c1559770 100644
--- a/msgpack-jackson/src/test/java/org/msgpack/jackson/dataformat/MessagePackDataformatForPojoTest.java
+++ b/msgpack-jackson/src/test/java/org/msgpack/jackson/dataformat/MessagePackDataformatForPojoTest.java
@@ -1,3 +1,18 @@
+//
+// 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.jackson.dataformat;
import org.junit.Test;
@@ -8,9 +23,13 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
-public class MessagePackDataformatForPojoTest extends MessagePackDataformatTestBase {
+public class MessagePackDataformatForPojoTest
+ extends MessagePackDataformatTestBase
+{
@Test
- public void testNormal() throws IOException {
+ public void testNormal()
+ throws IOException
+ {
byte[] bytes = objectMapper.writeValueAsBytes(normalPojo);
NormalPojo value = objectMapper.readValue(bytes, NormalPojo.class);
assertEquals(normalPojo.s, value.getS());
@@ -25,7 +44,9 @@ public void testNormal() throws IOException {
}
@Test
- public void testNestedList() throws IOException {
+ public void testNestedList()
+ throws IOException
+ {
byte[] bytes = objectMapper.writeValueAsBytes(nestedListPojo);
NestedListPojo value = objectMapper.readValue(bytes, NestedListPojo.class);
assertEquals(nestedListPojo.s, value.s);
@@ -33,7 +54,9 @@ public void testNestedList() throws IOException {
}
@Test
- public void testNestedListComplex() throws IOException {
+ public void testNestedListComplex()
+ throws IOException
+ {
byte[] bytes = objectMapper.writeValueAsBytes(nestedListComplexPojo);
NestedListComplexPojo value = objectMapper.readValue(bytes, NestedListComplexPojo.class);
assertEquals(nestedListPojo.s, value.s);
@@ -41,7 +64,9 @@ public void testNestedListComplex() throws IOException {
}
@Test
- public void testUsingCustomConstructor() throws IOException {
+ public void testUsingCustomConstructor()
+ throws IOException
+ {
UsingCustomConstructorPojo orig = new UsingCustomConstructorPojo("komamitsu", 55);
byte[] bytes = objectMapper.writeValueAsBytes(orig);
UsingCustomConstructorPojo value = objectMapper.readValue(bytes, UsingCustomConstructorPojo.class);
@@ -50,7 +75,9 @@ public void testUsingCustomConstructor() throws IOException {
}
@Test
- public void testIgnoringProperties() throws IOException {
+ public void testIgnoringProperties()
+ throws IOException
+ {
IgnoringPropertiesPojo orig = new IgnoringPropertiesPojo();
orig.internal = "internal";
orig.external = "external";
@@ -63,12 +90,13 @@ public void testIgnoringProperties() throws IOException {
}
@Test
- public void testChangingPropertyNames() throws IOException {
+ public void testChangingPropertyNames()
+ throws IOException
+ {
ChangingPropertyNamesPojo orig = new ChangingPropertyNamesPojo();
orig.setTheName("komamitsu");
byte[] bytes = objectMapper.writeValueAsBytes(orig);
ChangingPropertyNamesPojo value = objectMapper.readValue(bytes, ChangingPropertyNamesPojo.class);
assertEquals("komamitsu", value.getTheName());
}
-
}
diff --git a/msgpack-jackson/src/test/java/org/msgpack/jackson/dataformat/MessagePackDataformatTestBase.java b/msgpack-jackson/src/test/java/org/msgpack/jackson/dataformat/MessagePackDataformatTestBase.java
index 27a5dfd12..1d5156adc 100644
--- a/msgpack-jackson/src/test/java/org/msgpack/jackson/dataformat/MessagePackDataformatTestBase.java
+++ b/msgpack-jackson/src/test/java/org/msgpack/jackson/dataformat/MessagePackDataformatTestBase.java
@@ -1,23 +1,40 @@
+//
+// 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.jackson.dataformat;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.ObjectMapper;
-import org.apache.commons.math3.stat.StatUtils;
-import org.apache.commons.math3.stat.descriptive.moment.StandardDeviation;
import org.junit.After;
import org.junit.Before;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
import java.io.IOException;
+import java.io.OutputStream;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
-public class MessagePackDataformatTestBase {
+public class MessagePackDataformatTestBase
+{
protected MessagePackFactory factory;
protected ByteArrayOutputStream out;
protected ByteArrayInputStream in;
@@ -28,7 +45,8 @@ public class MessagePackDataformatTestBase {
protected TinyPojo tinyPojo;
@Before
- public void setup() {
+ public void setup()
+ {
factory = new MessagePackFactory();
objectMapper = new ObjectMapper(factory);
out = new ByteArrayOutputStream();
@@ -58,11 +76,13 @@ public void setup() {
}
@After
- public void teardown() {
+ public void teardown()
+ {
if (in != null) {
try {
in.close();
- } catch (IOException e) {
+ }
+ catch (IOException e) {
e.printStackTrace();
}
}
@@ -70,41 +90,37 @@ public void teardown() {
if (out != null) {
try {
out.close();
- } catch (IOException e) {
+ }
+ catch (IOException e) {
e.printStackTrace();
}
}
}
- protected void printStat(String label, double[] values) {
- StandardDeviation standardDeviation = new StandardDeviation();
- System.out.println(label + ":");
- System.out.println(String.format(" mean : %.2f", StatUtils.mean(values)));
- System.out.println(String.format(" min : %.2f", StatUtils.min(values)));
- System.out.println(String.format(" max : %.2f", StatUtils.max(values)));
- System.out.println(String.format(" stdev: %.2f", standardDeviation.evaluate(values)));
- System.out.println("");
- }
-
- public enum Suit {
+ public enum Suit
+ {
SPADE, HEART, DIAMOND, CLUB;
}
- public static class NestedListPojo {
+ public static class NestedListPojo
+ {
public String s;
public List strs;
}
- public static class TinyPojo {
+ public static class TinyPojo
+ {
public String t;
}
- public static class NestedListComplexPojo {
+ public static class NestedListComplexPojo
+ {
public String s;
public List foos;
}
- public static class NormalPojo {
+ public static class NormalPojo
+ {
String s;
public boolean bool;
public int i;
@@ -115,11 +131,13 @@ public static class NormalPojo {
public BigInteger bi;
public Suit suit;
- public String getS() {
+ public String getS()
+ {
return s;
}
- public void setS(String s) {
+ public void setS(String s)
+ {
this.s = s;
}
}
@@ -135,19 +153,21 @@ public UsingCustomConstructorPojo(@JsonProperty("name") String name, @JsonProper
this.age = age;
}
- public String getName() {
+ public String getName()
+ {
return name;
}
- public int getAge() {
+ public int getAge()
+ {
return age;
}
}
- @JsonIgnoreProperties({ "foo", "bar" })
+ @JsonIgnoreProperties({"foo", "bar"})
public static class IgnoringPropertiesPojo
{
- int _code;
+ int code;
// will not be written as JSON; nor assigned from JSON:
@JsonIgnore
@@ -157,22 +177,65 @@ public static class IgnoringPropertiesPojo
public String external;
@JsonIgnore
- public void setCode(int c) { _code = c; }
+ public void setCode(int c)
+ {
+ code = c;
+ }
// note: will also be ignored because setter has annotation!
- public int getCode() { return _code; }
+ public int getCode()
+ {
+ return code;
+ }
}
- public static class ChangingPropertyNamesPojo {
- String _name;
+ public static class ChangingPropertyNamesPojo
+ {
+ String name;
// without annotation, we'd get "theName", but we want "name":
@JsonProperty("name")
- public String getTheName() { return _name; }
+ public String getTheName()
+ {
+ return name;
+ }
// note: it is enough to add annotation on just getter OR setter;
// so we can omit it here
- public void setTheName(String n) { _name = n; }
+ public void setTheName(String n)
+ {
+ name = n;
+ }
+ }
+
+ protected interface FileSetup
+ {
+ void setup(File f)
+ throws Exception;
}
+ protected File createTempFile()
+ throws Exception
+ {
+ return createTempFile(null);
+ }
+
+ protected File createTempFile(FileSetup fileSetup)
+ throws Exception
+ {
+ File tempFile = File.createTempFile("test", "msgpack");
+ tempFile.deleteOnExit();
+ if (fileSetup != null) {
+ fileSetup.setup(tempFile);
+ }
+ return tempFile;
+ }
+
+ protected OutputStream createTempFileOutputStream()
+ throws IOException
+ {
+ File tempFile = File.createTempFile("test", "msgpack");
+ tempFile.deleteOnExit();
+ return new FileOutputStream(tempFile);
+ }
}
diff --git a/msgpack-jackson/src/test/java/org/msgpack/jackson/dataformat/MessagePackFactoryTest.java b/msgpack-jackson/src/test/java/org/msgpack/jackson/dataformat/MessagePackFactoryTest.java
index 867229518..25180f784 100644
--- a/msgpack-jackson/src/test/java/org/msgpack/jackson/dataformat/MessagePackFactoryTest.java
+++ b/msgpack-jackson/src/test/java/org/msgpack/jackson/dataformat/MessagePackFactoryTest.java
@@ -1,3 +1,18 @@
+//
+// 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.jackson.dataformat;
import com.fasterxml.jackson.core.JsonEncoding;
@@ -9,16 +24,22 @@
import static org.junit.Assert.assertEquals;
-public class MessagePackFactoryTest extends MessagePackDataformatTestBase {
+public class MessagePackFactoryTest
+ extends MessagePackDataformatTestBase
+{
@Test
- public void testCreateGenerator() throws IOException {
+ public void testCreateGenerator()
+ throws IOException
+ {
JsonEncoding enc = JsonEncoding.UTF8;
JsonGenerator generator = factory.createGenerator(out, enc);
assertEquals(MessagePackGenerator.class, generator.getClass());
}
@Test
- public void testCreateParser() throws IOException {
+ public void testCreateParser()
+ throws IOException
+ {
JsonParser parser = factory.createParser(in);
assertEquals(MessagePackParser.class, parser.getClass());
}
diff --git a/msgpack-jackson/src/test/java/org/msgpack/jackson/dataformat/MessagePackGeneratorTest.java b/msgpack-jackson/src/test/java/org/msgpack/jackson/dataformat/MessagePackGeneratorTest.java
index 8126fa64a..fd2ea313f 100644
--- a/msgpack-jackson/src/test/java/org/msgpack/jackson/dataformat/MessagePackGeneratorTest.java
+++ b/msgpack-jackson/src/test/java/org/msgpack/jackson/dataformat/MessagePackGeneratorTest.java
@@ -17,26 +17,44 @@
import com.fasterxml.jackson.core.JsonEncoding;
import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Test;
+import org.msgpack.core.ExtensionTypeHeader;
import org.msgpack.core.MessagePack;
import org.msgpack.core.MessageUnpacker;
import org.msgpack.core.buffer.ArrayBufferInput;
+import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
+import java.io.FileOutputStream;
import java.io.IOException;
+import java.io.OutputStream;
+import java.math.BigDecimal;
+import java.nio.ByteBuffer;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
-public class MessagePackGeneratorTest extends MessagePackDataformatTestBase {
+public class MessagePackGeneratorTest
+ extends MessagePackDataformatTestBase
+{
@Test
- public void testGeneratorShouldWriteObject() throws IOException {
+ public void testGeneratorShouldWriteObject()
+ throws IOException
+ {
Map hashMap = new HashMap();
// #1
hashMap.put("str", "komamitsu");
@@ -51,7 +69,7 @@ public void testGeneratorShouldWriteObject() throws IOException {
// #6
hashMap.put("double", 3.14159d);
// #7
- hashMap.put("bin", new byte[]{0x00, 0x01, (byte)0xFE, (byte)0xFF});
+ hashMap.put("bin", new byte[] {0x00, 0x01, (byte) 0xFE, (byte) 0xFF});
// #8
Map childObj = new HashMap();
childObj.put("co_str", "child#0");
@@ -62,10 +80,13 @@ public void testGeneratorShouldWriteObject() throws IOException {
childArray.add("child#1");
childArray.add(1.23f);
hashMap.put("childArray", childArray);
+ // #10
+ byte[] hello = "hello".getBytes("UTF-8");
+ hashMap.put("ext", new MessagePackExtensionType((byte) 17, hello));
long bitmap = 0;
byte[] bytes = objectMapper.writeValueAsBytes(hashMap);
- MessageUnpacker messageUnpacker = new MessageUnpacker(new ArrayBufferInput(bytes));
+ MessageUnpacker messageUnpacker = MessagePack.newDefaultUnpacker(new ArrayBufferInput(bytes));
assertEquals(hashMap.size(), messageUnpacker.unpackMapHeader());
for (int i = 0; i < hashMap.size(); i++) {
String key = messageUnpacker.unpackString();
@@ -101,11 +122,11 @@ else if (key.equals("double")) {
}
else if (key.equals("bin")) {
// #7
- assertEquals(4, messageUnpacker.unpackBinaryHeader());
- assertEquals((byte)0x00, messageUnpacker.unpackByte());
- assertEquals((byte)0x01, messageUnpacker.unpackByte());
- assertEquals((byte)0xFE, messageUnpacker.unpackByte());
- assertEquals((byte)0xFF, messageUnpacker.unpackByte());
+ assertEquals(4, messageUnpacker.unpackBinaryHeader());
+ assertEquals((byte) 0x00, messageUnpacker.unpackByte());
+ assertEquals((byte) 0x01, messageUnpacker.unpackByte());
+ assertEquals((byte) 0xFE, messageUnpacker.unpackByte());
+ assertEquals((byte) 0xFF, messageUnpacker.unpackByte());
bitmap |= 0x1 << 6;
}
else if (key.equals("childObj")) {
@@ -133,15 +154,30 @@ else if (key.equals("childArray")) {
assertEquals(1.23f, messageUnpacker.unpackFloat(), 0.01f);
bitmap |= 0x1 << 9;
}
+ else if (key.equals("ext")) {
+ // #10
+ ExtensionTypeHeader header = messageUnpacker.unpackExtensionTypeHeader();
+ assertEquals(17, header.getType());
+ assertEquals(5, header.getLength());
+ ByteBuffer payload = ByteBuffer.allocate(header.getLength());
+ payload.flip();
+ payload.limit(payload.capacity());
+ messageUnpacker.readPayload(payload);
+ payload.flip();
+ assertArrayEquals("hello".getBytes(), payload.array());
+ bitmap |= 0x1 << 10;
+ }
else {
assertTrue(false);
}
}
- assertEquals(0x03FF, bitmap);
+ assertEquals(0x07FF, bitmap);
}
@Test
- public void testGeneratorShouldWriteArray() throws IOException {
+ public void testGeneratorShouldWriteArray()
+ throws IOException
+ {
List array = new ArrayList();
// #1
array.add("komamitsu");
@@ -163,7 +199,7 @@ public void testGeneratorShouldWriteArray() throws IOException {
long bitmap = 0;
byte[] bytes = objectMapper.writeValueAsBytes(array);
- MessageUnpacker messageUnpacker = new MessageUnpacker(new ArrayBufferInput(bytes));
+ MessageUnpacker messageUnpacker = MessagePack.newDefaultUnpacker(new ArrayBufferInput(bytes));
assertEquals(array.size(), messageUnpacker.unpackArrayHeader());
// #1
assertEquals("komamitsu", messageUnpacker.unpackString());
@@ -197,10 +233,11 @@ else if (key.equals("num")) {
}
@Test
- public void testMessagePackGeneratorDirectly() throws IOException {
+ public void testMessagePackGeneratorDirectly()
+ throws Exception
+ {
MessagePackFactory messagePackFactory = new MessagePackFactory();
- File tempFile = File.createTempFile("msgpackTest", "msgpack");
- tempFile.deleteOnExit();
+ File tempFile = createTempFile();
JsonGenerator generator = messagePackFactory.createGenerator(tempFile, JsonEncoding.UTF8);
assertTrue(generator instanceof MessagePackGenerator);
@@ -221,4 +258,181 @@ public void testMessagePackGeneratorDirectly() throws IOException {
assertEquals(2.0f, unpacker.unpackFloat(), 0.001f);
assertFalse(unpacker.hasNext());
}
+
+ @Test
+ public void testWritePrimitives()
+ throws Exception
+ {
+ MessagePackFactory messagePackFactory = new MessagePackFactory();
+ File tempFile = createTempFile();
+
+ JsonGenerator generator = messagePackFactory.createGenerator(tempFile, JsonEncoding.UTF8);
+ assertTrue(generator instanceof MessagePackGenerator);
+ generator.writeNumber(0);
+ generator.writeString("one");
+ generator.writeNumber(2.0f);
+ generator.flush();
+ generator.close();
+
+ FileInputStream fileInputStream = new FileInputStream(tempFile);
+ MessageUnpacker unpacker = MessagePack.newDefaultUnpacker(fileInputStream);
+ assertEquals(0, unpacker.unpackInt());
+ assertEquals("one", unpacker.unpackString());
+ assertEquals(2.0f, unpacker.unpackFloat(), 0.001f);
+ assertFalse(unpacker.hasNext());
+ }
+
+ @Test
+ public void testBigDecimal()
+ throws IOException
+ {
+ ObjectMapper mapper = new ObjectMapper(new MessagePackFactory());
+
+ {
+ double d0 = 1.23456789;
+ double d1 = 1.23450000000000000000006789;
+ String d2 = "12.30";
+ List bigDecimals = Arrays.asList(
+ BigDecimal.valueOf(d0),
+ BigDecimal.valueOf(d1),
+ new BigDecimal(d2),
+ BigDecimal.valueOf(Double.MIN_VALUE),
+ BigDecimal.valueOf(Double.MAX_VALUE),
+ BigDecimal.valueOf(Double.MIN_NORMAL)
+ );
+
+ byte[] bytes = mapper.writeValueAsBytes(bigDecimals);
+ MessageUnpacker unpacker = MessagePack.newDefaultUnpacker(bytes);
+
+ assertEquals(bigDecimals.size(), unpacker.unpackArrayHeader());
+ assertEquals(d0, unpacker.unpackDouble(), 0.000000000000001);
+ assertEquals(d1, unpacker.unpackDouble(), 0.000000000000001);
+ assertEquals(Double.valueOf(d2), unpacker.unpackDouble(), 0.000000000000001);
+ assertEquals(Double.MIN_VALUE, unpacker.unpackDouble(), 0.000000000000001);
+ assertEquals(Double.MAX_VALUE, unpacker.unpackDouble(), 0.000000000000001);
+ assertEquals(Double.MIN_NORMAL, unpacker.unpackDouble(), 0.000000000000001);
+ }
+
+ {
+ BigDecimal decimal = new BigDecimal("1234.567890123456789012345678901234567890");
+ List bigDecimals = Arrays.asList(
+ decimal
+ );
+
+ try {
+ mapper.writeValueAsBytes(bigDecimals);
+ assertTrue(false);
+ }
+ catch (IllegalArgumentException e) {
+ assertTrue(true);
+ }
+ }
+ }
+
+ @Test(expected = IOException.class)
+ public void testEnableFeatureAutoCloseTarget()
+ throws IOException
+ {
+ OutputStream out = createTempFileOutputStream();
+ MessagePackFactory messagePackFactory = new MessagePackFactory();
+ ObjectMapper objectMapper = new ObjectMapper(messagePackFactory);
+ List integers = Arrays.asList(1);
+ objectMapper.writeValue(out, integers);
+ objectMapper.writeValue(out, integers);
+ }
+
+ @Test
+ public void testDisableFeatureAutoCloseTarget()
+ throws Exception
+ {
+ File tempFile = createTempFile();
+ OutputStream out = new FileOutputStream(tempFile);
+ MessagePackFactory messagePackFactory = new MessagePackFactory();
+ ObjectMapper objectMapper = new ObjectMapper(messagePackFactory);
+ objectMapper.configure(JsonGenerator.Feature.AUTO_CLOSE_TARGET, false);
+ List integers = Arrays.asList(1);
+ objectMapper.writeValue(out, integers);
+ objectMapper.writeValue(out, integers);
+ out.close();
+
+ MessageUnpacker unpacker = MessagePack.newDefaultUnpacker(new FileInputStream(tempFile));
+ assertEquals(1, unpacker.unpackArrayHeader());
+ assertEquals(1, unpacker.unpackInt());
+ assertEquals(1, unpacker.unpackArrayHeader());
+ assertEquals(1, unpacker.unpackInt());
+ }
+
+ @Test
+ public void testWritePrimitiveObjectViaObjectMapper()
+ throws Exception
+ {
+ File tempFile = createTempFile();
+ OutputStream out = new FileOutputStream(tempFile);
+
+ ObjectMapper objectMapper = new ObjectMapper(new MessagePackFactory());
+ objectMapper.configure(JsonGenerator.Feature.AUTO_CLOSE_TARGET, false);
+ objectMapper.writeValue(out, 1);
+ objectMapper.writeValue(out, "two");
+ objectMapper.writeValue(out, 3.14);
+ objectMapper.writeValue(out, Arrays.asList(4));
+ objectMapper.writeValue(out, 5L);
+
+ MessageUnpacker unpacker = MessagePack.newDefaultUnpacker(new FileInputStream(tempFile));
+ assertEquals(1, unpacker.unpackInt());
+ assertEquals("two", unpacker.unpackString());
+ assertEquals(3.14, unpacker.unpackFloat(), 0.0001);
+ assertEquals(1, unpacker.unpackArrayHeader());
+ assertEquals(4, unpacker.unpackInt());
+ assertEquals(5, unpacker.unpackLong());
+ }
+
+ @Test
+ public void testInMultiThreads()
+ throws Exception
+ {
+ int threadCount = 8;
+ final int loopCount = 4000;
+ ExecutorService executorService = Executors.newFixedThreadPool(threadCount);
+ final ObjectMapper objectMapper = new ObjectMapper(new MessagePackFactory());
+ objectMapper.configure(JsonGenerator.Feature.AUTO_CLOSE_TARGET, false);
+ final List buffers = new ArrayList(threadCount);
+ List> results = new ArrayList>();
+
+ for (int ti = 0; ti < threadCount; ti++) {
+ buffers.add(new ByteArrayOutputStream());
+ final int threadIndex = ti;
+ results.add(executorService.submit(new Callable()
+ {
+ @Override
+ public Exception call()
+ throws Exception
+ {
+ try {
+ for (int i = 0; i < loopCount; i++) {
+ objectMapper.writeValue(buffers.get(threadIndex), threadIndex);
+ }
+ return null;
+ }
+ catch (IOException e) {
+ return e;
+ }
+ }
+ }));
+ }
+
+ for (int ti = 0; ti < threadCount; ti++) {
+ Future exceptionFuture = results.get(ti);
+ Exception exception = exceptionFuture.get(20, TimeUnit.SECONDS);
+ if (exception != null) {
+ throw exception;
+ }
+ else {
+ ByteArrayOutputStream outputStream = buffers.get(ti);
+ MessageUnpacker unpacker = MessagePack.newDefaultUnpacker(outputStream.toByteArray());
+ for (int i = 0; i < loopCount; i++) {
+ assertEquals(ti, unpacker.unpackInt());
+ }
+ }
+ }
+ }
}
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 dfba2e25f..112390598 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
@@ -1,27 +1,60 @@
+//
+// 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.jackson.dataformat;
import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.KeyDeserializer;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.module.SimpleModule;
import org.junit.Test;
import org.msgpack.core.MessagePack;
import org.msgpack.core.MessagePacker;
-import org.msgpack.core.buffer.OutputStreamBufferOutput;
-import java.io.*;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.Serializable;
+import java.math.BigDecimal;
import java.math.BigInteger;
+import java.util.ArrayList;
import java.util.Arrays;
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.assertNull;
import static org.junit.Assert.assertTrue;
-public class MessagePackParserTest extends MessagePackDataformatTestBase {
+public class MessagePackParserTest
+ extends MessagePackDataformatTestBase
+{
@Test
- public void testParserShouldReadObject() throws IOException {
- MessagePacker packer = new MessagePacker(new OutputStreamBufferOutput(out));
- packer.packMapHeader(8);
+ public void testParserShouldReadObject()
+ throws IOException
+ {
+ MessagePacker packer = MessagePack.newDefaultPacker(out);
+ packer.packMapHeader(9);
// #1
packer.packString("str");
packer.packString("foobar");
@@ -58,14 +91,19 @@ public void testParserShouldReadObject() throws IOException {
// #8
packer.packString("bool");
packer.packBoolean(false);
+ // #9
+ byte[] extPayload = {-80, -50, -25, -114, -25, 16, 60, 68};
+ packer.packString("ext");
+ packer.packExtensionTypeHeader((byte) 0, extPayload.length);
+ packer.writePayload(extPayload);
packer.flush();
byte[] bytes = out.toByteArray();
- TypeReference> typeReference = new TypeReference>(){};
+ TypeReference> typeReference = new TypeReference>() {};
Map object = objectMapper.readValue(bytes, typeReference);
- assertEquals(8, object.keySet().size());
+ assertEquals(9, object.keySet().size());
int bitmap = 0;
for (Map.Entry entry : object.entrySet()) {
@@ -120,7 +158,7 @@ else if (k.equals("array")) {
// #7
bitmap |= 1 << 8;
@SuppressWarnings("unchecked")
- List extends Serializable> expected = Arrays.asList((double)Float.MIN_VALUE, null, "array_child_str");
+ List extends Serializable> expected = Arrays.asList((double) Float.MIN_VALUE, null, "array_child_str");
assertEquals(expected, v);
}
else if (k.equals("bool")) {
@@ -128,14 +166,23 @@ else if (k.equals("bool")) {
bitmap |= 1 << 9;
assertEquals(false, v);
}
+ else if (k.equals("ext")) {
+ // #9
+ bitmap |= 1 << 10;
+ MessagePackExtensionType extensionType = (MessagePackExtensionType) v;
+ assertEquals(0, extensionType.getType());
+ assertArrayEquals(extPayload, extensionType.getData());
+ }
}
- assertEquals(0x3FF, bitmap);
+ assertEquals(0x7FF, bitmap);
}
@Test
- public void testParserShouldReadArray() throws IOException {
- MessagePacker packer = new MessagePacker(new OutputStreamBufferOutput(out));
- packer.packArrayHeader(10);
+ public void testParserShouldReadArray()
+ throws IOException
+ {
+ MessagePacker packer = MessagePack.newDefaultPacker(out);
+ packer.packArrayHeader(11);
// #1
packer.packArrayHeader(3);
{
@@ -158,7 +205,7 @@ public void testParserShouldReadArray() throws IOException {
bi = bi.add(BigInteger.ONE);
packer.packBigInteger(bi);
// #8
- byte[] bytes = new byte[]{(byte) 0xFF, (byte) 0xFE, 0x01, 0x00};
+ byte[] bytes = new byte[] {(byte) 0xFF, (byte) 0xFE, 0x01, 0x00};
packer.packBinaryHeader(bytes.length);
packer.writePayload(bytes);
// #9
@@ -171,14 +218,18 @@ public void testParserShouldReadArray() throws IOException {
}
// #10
packer.packBoolean(true);
+ // #11
+ byte[] extPayload = {-80, -50, -25, -114, -25, 16, 60, 68};
+ packer.packExtensionTypeHeader((byte) -1, extPayload.length);
+ packer.writePayload(extPayload);
packer.flush();
bytes = out.toByteArray();
- TypeReference> typeReference = new TypeReference>(){};
+ TypeReference> typeReference = new TypeReference>() {};
List array = objectMapper.readValue(bytes, typeReference);
- assertEquals(10, array.size());
+ assertEquals(11, array.size());
int i = 0;
// #1
@SuppressWarnings("unchecked")
@@ -196,18 +247,18 @@ public void testParserShouldReadArray() throws IOException {
// #4
assertEquals(Long.MIN_VALUE, array.get(i++));
// #5
- assertEquals(Float.MAX_VALUE, (Double)array.get(i++), 0.001f);
+ assertEquals(Float.MAX_VALUE, (Double) array.get(i++), 0.001f);
// #6
- assertEquals(Double.MIN_VALUE, (Double)array.get(i++), 0.001f);
+ assertEquals(Double.MIN_VALUE, (Double) array.get(i++), 0.001f);
// #7
assertEquals(bi, array.get(i++));
// #8
byte[] bs = (byte[]) array.get(i++);
assertEquals(4, bs.length);
- assertEquals((byte)0xFF, bs[0]);
- assertEquals((byte)0xFE, bs[1]);
- assertEquals((byte)0x01, bs[2]);
- assertEquals((byte)0x00, bs[3]);
+ assertEquals((byte) 0xFF, bs[0]);
+ assertEquals((byte) 0xFE, bs[1]);
+ assertEquals((byte) 0x01, bs[2]);
+ assertEquals((byte) 0x00, bs[3]);
// #9
@SuppressWarnings("unchecked")
Map childMap = (Map) array.get(i++);
@@ -226,11 +277,17 @@ else if (k.equals("child_map_age")) {
}
// #10
assertEquals(true, array.get(i++));
+ // #11
+ MessagePackExtensionType extensionType = (MessagePackExtensionType) array.get(i++);
+ assertEquals(-1, extensionType.getType());
+ assertArrayEquals(extPayload, extensionType.getData());
}
@Test
- public void testMessagePackParserDirectly() throws IOException {
- MessagePackFactory messagePackFactory = new MessagePackFactory();
+ public void testMessagePackParserDirectly()
+ throws IOException
+ {
+ MessagePackFactory factory = new MessagePackFactory();
File tempFile = File.createTempFile("msgpackTest", "msgpack");
tempFile.deleteOnExit();
@@ -243,7 +300,7 @@ public void testMessagePackParserDirectly() throws IOException {
packer.packFloat(1.0f);
packer.close();
- JsonParser parser = messagePackFactory.createParser(tempFile);
+ JsonParser parser = factory.createParser(tempFile);
assertTrue(parser instanceof MessagePackParser);
JsonToken jsonToken = parser.nextToken();
@@ -286,14 +343,332 @@ public void testMessagePackParserDirectly() throws IOException {
assertEquals(-1, parser.getCurrentLocation().getLineNr());
assertEquals(16, parser.getCurrentLocation().getColumnNr());
- try {
- parser.nextToken();
- assertTrue(false);
- }
- catch (EOFException e) {
- // Expected
- }
+ assertNull(parser.nextToken());
+
parser.close();
parser.close(); // Intentional
}
+
+ @Test
+ public void testReadPrimitives()
+ throws Exception
+ {
+ MessagePackFactory factory = new MessagePackFactory();
+ File tempFile = createTempFile();
+
+ FileOutputStream out = new FileOutputStream(tempFile);
+ MessagePacker packer = MessagePack.newDefaultPacker(out);
+ packer.packString("foo");
+ packer.packDouble(3.14);
+ packer.packLong(Long.MAX_VALUE);
+ byte[] bytes = {0x00, 0x11, 0x22};
+ packer.packBinaryHeader(bytes.length);
+ packer.writePayload(bytes);
+ packer.close();
+
+ JsonParser parser = factory.createParser(new FileInputStream(tempFile));
+ assertEquals(JsonToken.VALUE_STRING, parser.nextToken());
+ assertEquals("foo", parser.getText());
+ assertEquals(JsonToken.VALUE_NUMBER_FLOAT, parser.nextToken());
+ assertEquals(3.14, parser.getDoubleValue(), 0.0001);
+ assertEquals(JsonToken.VALUE_NUMBER_INT, parser.nextToken());
+ assertEquals(Long.MAX_VALUE, parser.getLongValue());
+ assertEquals(JsonToken.VALUE_EMBEDDED_OBJECT, parser.nextToken());
+ assertEquals(bytes.length, parser.getBinaryValue().length);
+ assertEquals(bytes[0], parser.getBinaryValue()[0]);
+ assertEquals(bytes[1], parser.getBinaryValue()[1]);
+ assertEquals(bytes[2], parser.getBinaryValue()[2]);
+ }
+
+ @Test
+ public void testBigDecimal()
+ throws IOException
+ {
+ double d0 = 1.23456789;
+ double d1 = 1.23450000000000000000006789;
+ MessagePacker packer = MessagePack.newDefaultPacker(out);
+ packer.packArrayHeader(5);
+ packer.packDouble(d0);
+ packer.packDouble(d1);
+ packer.packDouble(Double.MIN_VALUE);
+ packer.packDouble(Double.MAX_VALUE);
+ packer.packDouble(Double.MIN_NORMAL);
+ packer.flush();
+
+ ObjectMapper mapper = new ObjectMapper(new MessagePackFactory());
+ mapper.configure(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS, true);
+ List objects = mapper.readValue(out.toByteArray(), new TypeReference>() {});
+ assertEquals(5, objects.size());
+ int idx = 0;
+ assertEquals(BigDecimal.valueOf(d0), objects.get(idx++));
+ assertEquals(BigDecimal.valueOf(d1), objects.get(idx++));
+ assertEquals(BigDecimal.valueOf(Double.MIN_VALUE), objects.get(idx++));
+ assertEquals(BigDecimal.valueOf(Double.MAX_VALUE), objects.get(idx++));
+ assertEquals(BigDecimal.valueOf(Double.MIN_NORMAL), objects.get(idx++));
+ }
+
+ private File createTestFile()
+ throws Exception
+ {
+ File tempFile = createTempFile(new FileSetup()
+ {
+ @Override
+ public void setup(File f)
+ throws IOException
+ {
+ MessagePack.newDefaultPacker(new FileOutputStream(f))
+ .packArrayHeader(1).packInt(1)
+ .packArrayHeader(1).packInt(1)
+ .close();
+ }
+ });
+ return tempFile;
+ }
+
+ @Test(expected = IOException.class)
+ public void testEnableFeatureAutoCloseSource()
+ throws Exception
+ {
+ File tempFile = createTestFile();
+ MessagePackFactory factory = new MessagePackFactory();
+ FileInputStream in = new FileInputStream(tempFile);
+ ObjectMapper objectMapper = new ObjectMapper(factory);
+ objectMapper.readValue(in, new TypeReference>() {});
+ objectMapper.readValue(in, new TypeReference>() {});
+ }
+
+ @Test
+ public void testDisableFeatureAutoCloseSource()
+ throws Exception
+ {
+ File tempFile = createTestFile();
+ FileInputStream in = new FileInputStream(tempFile);
+ ObjectMapper objectMapper = new ObjectMapper(new MessagePackFactory());
+ objectMapper.configure(JsonParser.Feature.AUTO_CLOSE_SOURCE, false);
+ objectMapper.readValue(in, new TypeReference>() {});
+ objectMapper.readValue(in, new TypeReference>() {});
+ }
+
+ @Test
+ public void testParseBigDecimal()
+ throws IOException
+ {
+ ArrayList list = new ArrayList();
+ list.add(new BigDecimal(Long.MAX_VALUE));
+ ObjectMapper objectMapper = new ObjectMapper(new MessagePackFactory());
+ byte[] bytes = objectMapper.writeValueAsBytes(list);
+
+ ArrayList result = objectMapper.readValue(
+ bytes, new TypeReference>() {});
+ assertEquals(list, result);
+ }
+
+ @Test
+ public void testReadPrimitiveObjectViaObjectMapper()
+ throws Exception
+ {
+ File tempFile = createTempFile();
+ FileOutputStream out = new FileOutputStream(tempFile);
+
+ MessagePacker packer = MessagePack.newDefaultPacker(out);
+ packer.packString("foo");
+ packer.packLong(Long.MAX_VALUE);
+ packer.packDouble(3.14);
+ byte[] bytes = {0x00, 0x11, 0x22};
+ packer.packBinaryHeader(bytes.length);
+ packer.writePayload(bytes);
+ packer.close();
+
+ FileInputStream in = new FileInputStream(tempFile);
+ ObjectMapper objectMapper = new ObjectMapper(new MessagePackFactory());
+ objectMapper.configure(JsonParser.Feature.AUTO_CLOSE_SOURCE, false);
+ assertEquals("foo", objectMapper.readValue(in, new TypeReference() {}));
+ long l = objectMapper.readValue(in, new TypeReference() {});
+ assertEquals(Long.MAX_VALUE, l);
+ double d = objectMapper.readValue(in, new TypeReference() {});
+ assertEquals(3.14, d, 0.001);
+ byte[] bs = objectMapper.readValue(in, new TypeReference() {});
+ assertEquals(bytes.length, bs.length);
+ assertEquals(bytes[0], bs[0]);
+ assertEquals(bytes[1], bs[1]);
+ assertEquals(bytes[2], bs[2]);
+ }
+
+ @Test
+ public void testBinaryKey()
+ throws Exception
+ {
+ File tempFile = createTempFile();
+ FileOutputStream out = new FileOutputStream(tempFile);
+ MessagePacker packer = MessagePack.newDefaultPacker(out);
+ packer.packMapHeader(2);
+ packer.packString("foo");
+ packer.packDouble(3.14);
+ byte[] bytes = "bar".getBytes();
+ packer.packBinaryHeader(bytes.length);
+ packer.writePayload(bytes);
+ packer.packLong(42);
+ packer.close();
+
+ ObjectMapper mapper = new ObjectMapper(new MessagePackFactory());
+ Map object = mapper.readValue(new FileInputStream(tempFile), new TypeReference>() {});
+ assertEquals(2, object.size());
+ assertEquals(3.14, object.get("foo"));
+ assertEquals(42, object.get("bar"));
+ }
+
+ @Test
+ public void testBinaryKeyInNestedObject()
+ throws Exception
+ {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ MessagePacker packer = MessagePack.newDefaultPacker(out);
+ packer.packArrayHeader(2);
+ packer.packMapHeader(1);
+ byte[] bytes = "bar".getBytes();
+ packer.packBinaryHeader(bytes.length);
+ packer.writePayload(bytes);
+ packer.packInt(12);
+ packer.packInt(1);
+ packer.close();
+
+ ObjectMapper mapper = new ObjectMapper(new MessagePackFactory());
+ List objects = mapper.readValue(out.toByteArray(), new TypeReference>() {});
+ assertEquals(2, objects.size());
+ @SuppressWarnings(value = "unchecked")
+ Map map = (Map) objects.get(0);
+ assertEquals(1, map.size());
+ assertEquals(12, map.get("bar"));
+ assertEquals(1, objects.get(1));
+ }
+
+ @Test
+ public void testByteArrayKey()
+ throws IOException
+ {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ MessagePacker messagePacker = MessagePack.newDefaultPacker(out).packMapHeader(2);
+ byte[] k0 = new byte[] {0};
+ byte[] k1 = new byte[] {1};
+ messagePacker.packBinaryHeader(1).writePayload(k0).packInt(2);
+ messagePacker.packBinaryHeader(1).writePayload(k1).packInt(3);
+ messagePacker.close();
+
+ ObjectMapper objectMapper = new ObjectMapper(new MessagePackFactory());
+ SimpleModule module = new SimpleModule();
+ module.addKeyDeserializer(byte[].class, new KeyDeserializer()
+ {
+ @Override
+ public Object deserializeKey(String key, DeserializationContext ctxt)
+ throws IOException, JsonProcessingException
+ {
+ return key.getBytes();
+ }
+ });
+ objectMapper.registerModule(module);
+
+ Map map = objectMapper.readValue(
+ out.toByteArray(), new TypeReference>() {});
+ assertEquals(2, map.size());
+ for (Map.Entry entry : map.entrySet()) {
+ if (Arrays.equals(entry.getKey(), k0)) {
+ assertEquals((Integer) 2, entry.getValue());
+ }
+ else if (Arrays.equals(entry.getKey(), k1)) {
+ assertEquals((Integer) 3, entry.getValue());
+ }
+ }
+ }
+
+ @Test
+ public void testIntegerKey()
+ throws IOException
+ {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ MessagePacker messagePacker = MessagePack.newDefaultPacker(out).packMapHeader(3);
+ for (int i = 0; i < 2; i++) {
+ messagePacker.packInt(i).packInt(i + 2);
+ }
+ messagePacker.close();
+
+ ObjectMapper objectMapper = new ObjectMapper(new MessagePackFactory());
+ SimpleModule module = new SimpleModule();
+ module.addKeyDeserializer(Integer.class, new KeyDeserializer()
+ {
+ @Override
+ public Object deserializeKey(String key, DeserializationContext ctxt)
+ throws IOException, JsonProcessingException
+ {
+ return Integer.valueOf(key);
+ }
+ });
+ objectMapper.registerModule(module);
+
+ Map map = objectMapper.readValue(
+ out.toByteArray(), new TypeReference>() {});
+ assertEquals(2, map.size());
+ assertEquals((Integer) 2, map.get(0));
+ assertEquals((Integer) 3, map.get(1));
+ }
+
+ @Test
+ public void testFloatKey()
+ throws IOException
+ {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ MessagePacker messagePacker = MessagePack.newDefaultPacker(out).packMapHeader(3);
+ for (int i = 0; i < 2; i++) {
+ messagePacker.packFloat(i).packInt(i + 2);
+ }
+ messagePacker.close();
+
+ ObjectMapper objectMapper = new ObjectMapper(new MessagePackFactory());
+ SimpleModule module = new SimpleModule();
+ module.addKeyDeserializer(Float.class, new KeyDeserializer()
+ {
+ @Override
+ public Object deserializeKey(String key, DeserializationContext ctxt)
+ throws IOException, JsonProcessingException
+ {
+ return Float.valueOf(key);
+ }
+ });
+ objectMapper.registerModule(module);
+
+ Map map = objectMapper.readValue(
+ out.toByteArray(), new TypeReference>() {});
+ assertEquals(2, map.size());
+ assertEquals((Integer) 2, map.get(0f));
+ assertEquals((Integer) 3, map.get(1f));
+ }
+
+ @Test
+ public void testBooleanKey()
+ throws IOException
+ {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ MessagePacker messagePacker = MessagePack.newDefaultPacker(out).packMapHeader(3);
+ messagePacker.packBoolean(true).packInt(2);
+ messagePacker.packBoolean(false).packInt(3);
+ messagePacker.close();
+
+ ObjectMapper objectMapper = new ObjectMapper(new MessagePackFactory());
+ SimpleModule module = new SimpleModule();
+ module.addKeyDeserializer(Boolean.class, new KeyDeserializer()
+ {
+ @Override
+ public Object deserializeKey(String key, DeserializationContext ctxt)
+ throws IOException, JsonProcessingException
+ {
+ return Boolean.valueOf(key);
+ }
+ });
+ objectMapper.registerModule(module);
+
+ Map map = objectMapper.readValue(
+ out.toByteArray(), new TypeReference>() {});
+ assertEquals(2, map.size());
+ assertEquals((Integer) 2, map.get(true));
+ assertEquals((Integer) 3, map.get(false));
+ }
}
diff --git a/msgpack-jackson/src/test/java/org/msgpack/jackson/dataformat/benchmark/Benchmarker.java b/msgpack-jackson/src/test/java/org/msgpack/jackson/dataformat/benchmark/Benchmarker.java
new file mode 100644
index 000000000..980348024
--- /dev/null
+++ b/msgpack-jackson/src/test/java/org/msgpack/jackson/dataformat/benchmark/Benchmarker.java
@@ -0,0 +1,98 @@
+//
+// 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.jackson.dataformat.benchmark;
+
+import org.apache.commons.math3.stat.StatUtils;
+import org.apache.commons.math3.stat.descriptive.moment.StandardDeviation;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class Benchmarker
+{
+ private final List benchmarkableList = new ArrayList();
+
+ public abstract static class Benchmarkable
+ {
+ private final String label;
+
+ protected Benchmarkable(String label)
+ {
+ this.label = label;
+ }
+
+ public abstract void run() throws Exception;
+ }
+
+ public void addBenchmark(Benchmarkable benchmark)
+ {
+ benchmarkableList.add(benchmark);
+ }
+
+ private static class Tuple
+ {
+ F first;
+ S second;
+
+ public Tuple(F first, S second)
+ {
+ this.first = first;
+ this.second = second;
+ }
+ }
+
+ public void run(int count, int warmupCount)
+ throws Exception
+ {
+ List> benchmarksResults = new ArrayList>(benchmarkableList.size());
+ for (Benchmarkable benchmark : benchmarkableList) {
+ benchmarksResults.add(new Tuple(benchmark.label, new double[count]));
+ }
+
+ for (int i = 0; i < count + warmupCount; i++) {
+ for (int bi = 0; bi < benchmarkableList.size(); bi++) {
+ Benchmarkable benchmark = benchmarkableList.get(bi);
+ long currentTimeNanos = System.nanoTime();
+ benchmark.run();
+
+ if (i >= warmupCount) {
+ benchmarksResults.get(bi).second[i - warmupCount] = (System.nanoTime() - currentTimeNanos) / 1000000.0;
+ }
+ }
+ }
+
+ for (Tuple benchmarkResult : benchmarksResults) {
+ printStat(benchmarkResult.first, benchmarkResult.second);
+ }
+ }
+
+ private void printStat(String label, double[] origValues)
+ {
+ double[] values = origValues;
+ Arrays.sort(origValues);
+ if (origValues.length > 2) {
+ values = Arrays.copyOfRange(origValues, 1, origValues.length - 1);
+ }
+ StandardDeviation standardDeviation = new StandardDeviation();
+ System.out.println(label + ":");
+ System.out.println(String.format(" mean : %8.3f", StatUtils.mean(values)));
+ System.out.println(String.format(" min : %8.3f", StatUtils.min(values)));
+ System.out.println(String.format(" max : %8.3f", StatUtils.max(values)));
+ System.out.println(String.format(" stdev: %8.3f", standardDeviation.evaluate(values)));
+ System.out.println("");
+ }
+}
diff --git a/msgpack-jackson/src/test/java/org/msgpack/jackson/dataformat/benchmark/MessagePackDataformatHugeDataBenchmarkTest.java b/msgpack-jackson/src/test/java/org/msgpack/jackson/dataformat/benchmark/MessagePackDataformatHugeDataBenchmarkTest.java
index 504651456..b3a159111 100644
--- a/msgpack-jackson/src/test/java/org/msgpack/jackson/dataformat/benchmark/MessagePackDataformatHugeDataBenchmarkTest.java
+++ b/msgpack-jackson/src/test/java/org/msgpack/jackson/dataformat/benchmark/MessagePackDataformatHugeDataBenchmarkTest.java
@@ -15,31 +15,37 @@
//
package org.msgpack.jackson.dataformat.benchmark;
+import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Test;
-import org.msgpack.jackson.dataformat.MessagePackDataformatTestBase;
import org.msgpack.jackson.dataformat.MessagePackFactory;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
-public class MessagePackDataformatHugeDataBenchmarkTest extends MessagePackDataformatTestBase {
- private static final int ELM_NUM = 1000000;
- private static final int SAMPLING_COUNT = 4;
+public class MessagePackDataformatHugeDataBenchmarkTest
+{
+ private static final int ELM_NUM = 100000;
+ private static final int COUNT = 6;
+ private static final int WARMUP_COUNT = 4;
private final ObjectMapper origObjectMapper = new ObjectMapper();
private final ObjectMapper msgpackObjectMapper = new ObjectMapper(new MessagePackFactory());
private static final List value;
private static final byte[] packedByOriginal;
private static final byte[] packedByMsgPack;
+
static {
value = new ArrayList();
for (int i = 0; i < ELM_NUM; i++) {
- value.add((long)i);
+ value.add((long) i);
}
for (int i = 0; i < ELM_NUM; i++) {
- value.add((double)i);
+ value.add((double) i);
}
for (int i = 0; i < ELM_NUM; i++) {
value.add(String.valueOf(i));
@@ -48,45 +54,83 @@ public class MessagePackDataformatHugeDataBenchmarkTest extends MessagePackDataf
byte[] bytes = null;
try {
bytes = new ObjectMapper().writeValueAsBytes(value);
- } catch (JsonProcessingException e) {
+ }
+ catch (JsonProcessingException e) {
e.printStackTrace();
}
packedByOriginal = bytes;
try {
bytes = new ObjectMapper(new MessagePackFactory()).writeValueAsBytes(value);
- } catch (JsonProcessingException e) {
+ }
+ catch (JsonProcessingException e) {
e.printStackTrace();
}
packedByMsgPack = bytes;
}
+ public MessagePackDataformatHugeDataBenchmarkTest()
+ {
+ origObjectMapper.configure(JsonGenerator.Feature.AUTO_CLOSE_TARGET, false);
+ msgpackObjectMapper.configure(JsonGenerator.Feature.AUTO_CLOSE_TARGET, false);
+ }
+
@Test
- public void testBenchmark() throws Exception {
- double durationOfSerializeWithJson[] = new double[SAMPLING_COUNT];
- double durationOfSerializeWithMsgPack[] = new double[SAMPLING_COUNT];
- double durationOfDeserializeWithJson[] = new double[SAMPLING_COUNT];
- double durationOfDeserializeWithMsgPack[] = new double[SAMPLING_COUNT];
- for (int si = 0; si < SAMPLING_COUNT; si++) {
- long currentTimeMillis = System.currentTimeMillis();
- origObjectMapper.writeValueAsBytes(value);
- durationOfSerializeWithJson[si] = System.currentTimeMillis() - currentTimeMillis;
+ public void testBenchmark()
+ throws Exception
+ {
+ Benchmarker benchmarker = new Benchmarker();
+
+ File tempFileJackson = File.createTempFile("msgpack-jackson-", "-huge-jackson");
+ tempFileJackson.deleteOnExit();
+ final OutputStream outputStreamJackson = new FileOutputStream(tempFileJackson);
- currentTimeMillis = System.currentTimeMillis();
- msgpackObjectMapper.writeValueAsBytes(value);
- durationOfSerializeWithMsgPack[si] = System.currentTimeMillis() - currentTimeMillis;
+ File tempFileMsgpack = File.createTempFile("msgpack-jackson-", "-huge-msgpack");
+ tempFileMsgpack.deleteOnExit();
+ final OutputStream outputStreamMsgpack = new FileOutputStream(tempFileMsgpack);
- currentTimeMillis = System.currentTimeMillis();
- origObjectMapper.readValue(packedByOriginal, new TypeReference>() {});
- durationOfDeserializeWithJson[si] = System.currentTimeMillis() - currentTimeMillis;
+ benchmarker.addBenchmark(new Benchmarker.Benchmarkable("serialize(huge) with JSON") {
+ @Override
+ public void run()
+ throws Exception
+ {
+ origObjectMapper.writeValue(outputStreamJackson, value);
+ }
+ });
- currentTimeMillis = System.currentTimeMillis();
- msgpackObjectMapper.readValue(packedByMsgPack, new TypeReference>() {});
- durationOfDeserializeWithMsgPack[si] = System.currentTimeMillis() - currentTimeMillis;
+ benchmarker.addBenchmark(new Benchmarker.Benchmarkable("serialize(huge) with MessagePack") {
+ @Override
+ public void run()
+ throws Exception
+ {
+ msgpackObjectMapper.writeValue(outputStreamMsgpack, value);
+ }
+ });
+
+ benchmarker.addBenchmark(new Benchmarker.Benchmarkable("deserialize(huge) with JSON") {
+ @Override
+ public void run()
+ throws Exception
+ {
+ origObjectMapper.readValue(packedByOriginal, new TypeReference>() {});
+ }
+ });
+
+ benchmarker.addBenchmark(new Benchmarker.Benchmarkable("deserialize(huge) with MessagePack") {
+ @Override
+ public void run()
+ throws Exception
+ {
+ msgpackObjectMapper.readValue(packedByMsgPack, new TypeReference>() {});
+ }
+ });
+
+ try {
+ benchmarker.run(COUNT, WARMUP_COUNT);
+ }
+ finally {
+ outputStreamJackson.close();
+ outputStreamMsgpack.close();
}
- printStat("serialize(huge) with JSON", durationOfSerializeWithJson);
- printStat("serialize(huge) with MessagePack", durationOfSerializeWithMsgPack);
- printStat("deserialize(huge) with JSON", durationOfDeserializeWithJson);
- printStat("deserialize(huge) with MessagePack", durationOfDeserializeWithMsgPack);
}
}
diff --git a/msgpack-jackson/src/test/java/org/msgpack/jackson/dataformat/benchmark/MessagePackDataformatPojoBenchmarkTest.java b/msgpack-jackson/src/test/java/org/msgpack/jackson/dataformat/benchmark/MessagePackDataformatPojoBenchmarkTest.java
index d7dedc43e..179b09891 100644
--- a/msgpack-jackson/src/test/java/org/msgpack/jackson/dataformat/benchmark/MessagePackDataformatPojoBenchmarkTest.java
+++ b/msgpack-jackson/src/test/java/org/msgpack/jackson/dataformat/benchmark/MessagePackDataformatPojoBenchmarkTest.java
@@ -15,29 +15,38 @@
//
package org.msgpack.jackson.dataformat.benchmark;
+import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Test;
-import org.msgpack.jackson.dataformat.MessagePackDataformatTestBase;
import org.msgpack.jackson.dataformat.MessagePackFactory;
+import static org.msgpack.jackson.dataformat.MessagePackDataformatTestBase.NormalPojo;
+import static org.msgpack.jackson.dataformat.MessagePackDataformatTestBase.Suit;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.OutputStream;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
-public class MessagePackDataformatPojoBenchmarkTest extends MessagePackDataformatTestBase {
- private static final int LOOP_MAX = 1000;
- private static final int LOOP_FACTOR = 50;
- private static final int SAMPLING_COUNT = 4;
- private static final List pojos = new ArrayList(LOOP_MAX);
- private static final List pojosSerWithOrig = new ArrayList(LOOP_MAX);
- private static final List pojosSerWithMsgPack = new ArrayList(LOOP_MAX);
+public class MessagePackDataformatPojoBenchmarkTest
+{
+ private static final int LOOP_MAX = 200;
+ private static final int LOOP_FACTOR_SER = 40;
+ private static final int LOOP_FACTOR_DESER = 200;
+ private static final int COUNT = 6;
+ private static final int WARMUP_COUNT = 4;
+ private final List pojos = new ArrayList(LOOP_MAX);
+ private final List pojosSerWithOrig = new ArrayList(LOOP_MAX);
+ private final List pojosSerWithMsgPack = new ArrayList(LOOP_MAX);
private final ObjectMapper origObjectMapper = new ObjectMapper();
private final ObjectMapper msgpackObjectMapper = new ObjectMapper(new MessagePackFactory());
- static {
- final ObjectMapper origObjectMapper = new ObjectMapper();
- final ObjectMapper msgpackObjectMapper = new ObjectMapper(new MessagePackFactory());
+ public MessagePackDataformatPojoBenchmarkTest()
+ {
+ origObjectMapper.configure(JsonGenerator.Feature.AUTO_CLOSE_TARGET, false);
+ msgpackObjectMapper.configure(JsonGenerator.Feature.AUTO_CLOSE_TARGET, false);
for (int i = 0; i < LOOP_MAX; i++) {
NormalPojo pojo = new NormalPojo();
@@ -45,7 +54,11 @@ public class MessagePackDataformatPojoBenchmarkTest extends MessagePackDataforma
pojo.l = i;
pojo.f = Float.valueOf(i);
pojo.d = Double.valueOf(i);
- pojo.setS(String.valueOf(i));
+ StringBuilder sb = new StringBuilder();
+ for (int sbi = 0; sbi < i * 50; sbi++) {
+ sb.append("x");
+ }
+ pojo.setS(sb.toString());
pojo.bool = i % 2 == 0;
pojo.bi = BigInteger.valueOf(i);
switch (i % 4) {
@@ -69,58 +82,94 @@ public class MessagePackDataformatPojoBenchmarkTest extends MessagePackDataforma
for (int i = 0; i < LOOP_MAX; i++) {
try {
pojosSerWithOrig.add(origObjectMapper.writeValueAsBytes(pojos.get(i)));
- } catch (JsonProcessingException e) {
- e.printStackTrace();
+ }
+ catch (JsonProcessingException e) {
+ throw new RuntimeException("Failed to create test data");
}
}
for (int i = 0; i < LOOP_MAX; i++) {
try {
pojosSerWithMsgPack.add(msgpackObjectMapper.writeValueAsBytes(pojos.get(i)));
- } catch (JsonProcessingException e) {
- e.printStackTrace();
+ }
+ catch (JsonProcessingException e) {
+ throw new RuntimeException("Failed to create test data");
}
}
}
@Test
- public void testBenchmark() throws Exception {
- double durationOfSerializeWithJson[] = new double[SAMPLING_COUNT];
- double durationOfSerializeWithMsgPack[] = new double[SAMPLING_COUNT];
- double durationOfDeserializeWithJson[] = new double[SAMPLING_COUNT];
- double durationOfDeserializeWithMsgPack[] = new double[SAMPLING_COUNT];
- for (int si = 0; si < SAMPLING_COUNT; si++) {
- long currentTimeMillis = System.currentTimeMillis();
- for (int j = 0; j < LOOP_FACTOR; j++)
- for (int i = 0; i < LOOP_MAX; i++) {
- origObjectMapper.writeValueAsBytes(pojos.get(i));
+ public void testBenchmark()
+ throws Exception
+ {
+ Benchmarker benchmarker = new Benchmarker();
+
+ File tempFileJackson = File.createTempFile("msgpack-jackson-", "-huge-jackson");
+ tempFileJackson.deleteOnExit();
+ final OutputStream outputStreamJackson = new FileOutputStream(tempFileJackson);
+
+ File tempFileMsgpack = File.createTempFile("msgpack-jackson-", "-huge-msgpack");
+ tempFileMsgpack.deleteOnExit();
+ final OutputStream outputStreamMsgpack = new FileOutputStream(tempFileMsgpack);
+
+ benchmarker.addBenchmark(new Benchmarker.Benchmarkable("serialize(pojo) with JSON") {
+ @Override
+ public void run()
+ throws Exception
+ {
+ for (int j = 0; j < LOOP_FACTOR_SER; j++) {
+ for (int i = 0; i < LOOP_MAX; i++) {
+ origObjectMapper.writeValue(outputStreamJackson, pojos.get(i));
+ }
}
- durationOfSerializeWithJson[si] = System.currentTimeMillis() - currentTimeMillis;
+ }
+ });
- currentTimeMillis = System.currentTimeMillis();
- for (int j = 0; j < LOOP_FACTOR; j++)
- for (int i = 0; i < LOOP_MAX; i++) {
- msgpackObjectMapper.writeValueAsBytes(pojos.get(i));
+ benchmarker.addBenchmark(new Benchmarker.Benchmarkable("serialize(pojo) with MessagePack") {
+ @Override
+ public void run()
+ throws Exception
+ {
+ for (int j = 0; j < LOOP_FACTOR_SER; j++) {
+ for (int i = 0; i < LOOP_MAX; i++) {
+ msgpackObjectMapper.writeValue(outputStreamMsgpack, pojos.get(i));
+ }
}
- durationOfSerializeWithMsgPack[si] = System.currentTimeMillis() - currentTimeMillis;
+ }
+ });
- currentTimeMillis = System.currentTimeMillis();
- for (int j = 0; j < LOOP_FACTOR; j++)
- for (int i = 0; i < LOOP_MAX; i++) {
- origObjectMapper.readValue(pojosSerWithOrig.get(i), NormalPojo.class);
+ benchmarker.addBenchmark(new Benchmarker.Benchmarkable("deserialize(pojo) with JSON") {
+ @Override
+ public void run()
+ throws Exception
+ {
+ for (int j = 0; j < LOOP_FACTOR_DESER; j++) {
+ for (int i = 0; i < LOOP_MAX; i++) {
+ origObjectMapper.readValue(pojosSerWithOrig.get(i), NormalPojo.class);
+ }
}
- durationOfDeserializeWithJson[si] = System.currentTimeMillis() - currentTimeMillis;
+ }
+ });
- currentTimeMillis = System.currentTimeMillis();
- for (int j = 0; j < LOOP_FACTOR; j++)
- for (int i = 0; i < LOOP_MAX; i++) {
- msgpackObjectMapper.readValue(pojosSerWithMsgPack.get(i), NormalPojo.class);
+ benchmarker.addBenchmark(new Benchmarker.Benchmarkable("deserialize(pojo) with MessagePack") {
+ @Override
+ public void run()
+ throws Exception
+ {
+ for (int j = 0; j < LOOP_FACTOR_DESER; j++) {
+ for (int i = 0; i < LOOP_MAX; i++) {
+ msgpackObjectMapper.readValue(pojosSerWithMsgPack.get(i), NormalPojo.class);
+ }
}
- durationOfDeserializeWithMsgPack[si] = System.currentTimeMillis() - currentTimeMillis;
+ }
+ });
+
+ try {
+ benchmarker.run(COUNT, WARMUP_COUNT);
+ }
+ finally {
+ outputStreamJackson.close();
+ outputStreamMsgpack.close();
}
- printStat("serialize(pojo) with JSON", durationOfSerializeWithJson);
- printStat("serialize(pojo) with MessagePack", durationOfSerializeWithMsgPack);
- printStat("deserialize(pojo) with JSON", durationOfDeserializeWithJson);
- printStat("deserialize(pojo) with MessagePack", durationOfDeserializeWithMsgPack);
}
}
diff --git a/project/Build.scala b/project/Build.scala
deleted file mode 100644
index fa800c3d7..000000000
--- a/project/Build.scala
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- * Copyright 2012 Taro L. Saito
- *
- * 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.
- */
-
-
-import de.johoop.findbugs4sbt.ReportType
-import sbt._
-import Keys._
-import de.johoop.findbugs4sbt.FindBugs._
-import de.johoop.jacoco4sbt._
-import JacocoPlugin._
-import sbtrelease.ReleasePlugin._
-import scala.util.Properties
-import com.typesafe.sbt.pgp.PgpKeys
-
-object Build extends Build {
-
- val SCALA_VERSION = "2.11.1"
-
- lazy val buildSettings = Defaults.coreDefaultSettings ++
- releaseSettings ++
- findbugsSettings ++
- jacoco.settings ++
- Seq[Setting[_]](
- organization := "org.msgpack",
- organizationName := "MessagePack",
- organizationHomepage := Some(new URL("http://msgpack.org/")),
- description := "MessagePack for Java",
- scalaVersion in Global := SCALA_VERSION,
- ReleaseKeys.publishArtifactsAction := PgpKeys.publishSigned.value,
- logBuffered in Test := false,
- //parallelExecution in Test := false,
- autoScalaLibrary := false,
- crossPaths := false,
- concurrentRestrictions in Global := Seq(
- Tags.limit(Tags.Test, 1)
- ),
- ReleaseKeys.tagName <<= (version in ThisBuild) map (v => v),
- publishTo := {
- val nexus = "https://oss.sonatype.org/"
- if (isSnapshot.value)
- Some("snapshots" at nexus + "content/repositories/snapshots")
- else
- Some("releases" at nexus + "service/local/staging/deploy/maven2")
- },
- parallelExecution in jacoco.Config := false,
- // Since sbt-0.13.2
- incOptions := incOptions.value.withNameHashing(true),
- //resolvers += Resolver.mavenLocal,
- scalacOptions ++= Seq("-encoding", "UTF-8", "-deprecation", "-unchecked", "-target:jvm-1.6", "-feature"),
- javaOptions in Test ++= Seq("-ea"),
- javacOptions in (Compile, compile) ++= Seq("-encoding", "UTF-8", "-Xlint:unchecked", "-Xlint:deprecation", "-source", "1.6", "-target", "1.6"),
- javacOptions in doc := {
- val opts = Seq("-source", "1.6")
- if (Properties.isJavaAtLeast("1.8"))
- opts ++ Seq("-Xdoclint:none")
- else
- opts
- },
- findbugsReportType := Some(ReportType.FancyHtml),
- findbugsReportPath := Some(crossTarget.value / "findbugs" / "report.html"),
- pomExtra := {
- http://msgpack.org/
-
-
- Apache 2
- http://www.apache.org/licenses/LICENSE-2.0.txt
-
-
-
- scm:git:github.com/msgpack/msgpack-java.git
- scm:git:git@github.com:msgpack/msgpack-java.git
- github.com/msgpack/msgpack-java.git
-
-
- UTF-8
-
-
-
- frsyuki
- Sadayuki Furuhashi
- frsyuki@users.sourceforge.jp
-
-
- muga
- Muga Nishizawa
- muga.nishizawa@gmail.com
-
-
- oza
- Tsuyoshi Ozawa
- https://github.com/oza
-
-
- komamitsu
- Mitsunori Komatsu
- komamitsu@gmail.com
-
-
- xerial
- Taro L. Saito
- leo@xerial.org
-
-
- }
- )
-
- import Dependencies._
-
-
- lazy val root = Project(
- id = "msgpack-java",
- base = file("."),
- settings = buildSettings ++ Seq(
- findbugs := {
- // do not run findbugs for the root project
- },
- // Do not publish the root project
- publishArtifact := false,
- publish := {},
- publishLocal := {}
- )
- ) aggregate(msgpackCore, msgpackJackson)
-
-
- lazy val msgpackCore = Project(
- id = "msgpack-core",
- base = file("msgpack-core"),
- settings = buildSettings ++ Seq(
- description := "Core library of the MessagePack for Java",
- libraryDependencies ++= testLib
- )
- )
-
- lazy val msgpackJackson = Project(
- id = "msgpack-jackson",
- base = file("msgpack-jackson"),
- settings = buildSettings ++ Seq(
- name := "jackson-dataformat-msgpack",
- description := "Jackson extension that adds support for MessagePack",
- libraryDependencies ++= jacksonLib,
- testOptions += Tests.Argument(TestFrameworks.JUnit, "-v")
- )
- ).dependsOn(msgpackCore)
-
- object Dependencies {
-
- val testLib = Seq(
- "org.scalatest" % "scalatest_2.11" % "2.2.0" % "test",
- "org.scalacheck" % "scalacheck_2.11" % "1.11.4" % "test",
- "org.xerial" % "xerial-core" % "3.3.0" % "test",
- "org.msgpack" % "msgpack" % "0.6.9" % "test",
- "com.novocode" % "junit-interface" % "0.10" % "test",
- "commons-codec" % "commons-codec" % "1.9" % "test"
- )
-
- val jacksonLib = Seq(
- "com.fasterxml.jackson.core" % "jackson-databind" % "2.4.4",
- "com.novocode" % "junit-interface" % "0.10" % "test",
- "org.apache.commons" % "commons-math3" % "3.3" % "test"
- )
- }
-
-}
-
-
-
-
-
-
-
-
diff --git a/project/build.properties b/project/build.properties
index 005786e4d..02cb92b32 100755
--- a/project/build.properties
+++ b/project/build.properties
@@ -1,2 +1,2 @@
-sbt.version=0.13.6
+sbt.version=0.13.9
diff --git a/project/plugins.sbt b/project/plugins.sbt
index 2ce2dad4c..be8535f05 100755
--- a/project/plugins.sbt
+++ b/project/plugins.sbt
@@ -1,14 +1,14 @@
-addSbtPlugin("com.github.gseitz" % "sbt-release" % "0.8.5")
+addSbtPlugin("com.github.gseitz" % "sbt-release" % "1.0.0")
-addSbtPlugin("org.xerial.sbt" % "sbt-sonatype" % "0.2.1")
+addSbtPlugin("org.xerial.sbt" % "sbt-sonatype" % "1.0")
-addSbtPlugin("com.typesafe.sbt" % "sbt-pgp" % "0.8.3")
-
-addSbtPlugin("com.github.mpeltonen" % "sbt-idea" % "1.6.0")
+addSbtPlugin("com.jsuereth" % "sbt-pgp" % "1.0.0")
addSbtPlugin("de.johoop" % "findbugs4sbt" % "1.3.0")
-addSbtPlugin("de.johoop" % "jacoco4sbt" % "2.1.5")
+addSbtPlugin("de.johoop" % "jacoco4sbt" % "2.1.6")
+
+addSbtPlugin("org.xerial.sbt" % "sbt-jcheckstyle" % "0.1.2")
scalacOptions ++= Seq("-deprecation", "-feature")
diff --git a/sbt b/sbt
index 3721584c9..c475bc64b 100755
--- a/sbt
+++ b/sbt
@@ -1,36 +1,27 @@
#!/usr/bin/env bash
#
# A more capable sbt runner, coincidentally also called sbt.
-# Author: Paul Phillips
+# Author: Paul Phillips
+
+set -o pipefail
# todo - make this dynamic
-declare -r sbt_release_version="0.13.1"
-declare -r sbt_unreleased_version="0.13.2-SNAPSHOT" # -sbt-dev doesn't work at present
+declare -r sbt_release_version="0.13.9"
+declare -r sbt_unreleased_version="0.13.9"
declare -r buildProps="project/build.properties"
-declare sbt_jar sbt_dir sbt_create sbt_launch_dir
-declare scala_version java_home sbt_explicit_version
-declare verbose debug quiet noshare batch trace_level log_level
-declare sbt_saved_stty
-
-echoerr () { [[ -z "$quiet" ]] && echo "$@" >&2; }
-vlog () { [[ -n "$verbose$debug" ]] && echoerr "$@"; }
-dlog () { [[ -n "$debug" ]] && echoerr "$@"; }
-
-# we'd like these set before we get around to properly processing arguments
-for arg in "$@"; do
- case "$arg" in
- -q|-quiet) quiet=true ;;
- -d|-debug) debug=true ;;
- -v|-verbose) verbose=true ;;
- *) ;;
- esac
-done
+declare sbt_jar sbt_dir sbt_create sbt_version
+declare scala_version sbt_explicit_version
+declare verbose noshare batch trace_level log_level
+declare sbt_saved_stty debugUs
+
+echoerr () { echo >&2 "$@"; }
+vlog () { [[ -n "$verbose" ]] && echoerr "$@"; }
# spaces are possible, e.g. sbt.version = 0.13.0
build_props_sbt () {
[[ -r "$buildProps" ]] && \
- grep '^sbt\.version' "$buildProps" | tr '=' ' ' | awk '{ print $2; }'
+ grep '^sbt\.version' "$buildProps" | tr '=\r' ' ' | awk '{ print $2; }'
}
update_build_props_sbt () {
@@ -41,31 +32,24 @@ update_build_props_sbt () {
perl -pi -e "s/^sbt\.version\b.*\$/sbt.version=${ver}/" "$buildProps"
grep -q '^sbt.version[ =]' "$buildProps" || printf "\nsbt.version=%s\n" "$ver" >> "$buildProps"
- echoerr "!!!"
- echoerr "!!! Updated file $buildProps setting sbt.version to: $ver"
- echoerr "!!! Previous value was: $old"
- echoerr "!!!"
+ vlog "!!!"
+ vlog "!!! Updated file $buildProps setting sbt.version to: $ver"
+ vlog "!!! Previous value was: $old"
+ vlog "!!!"
}
}
-sbt_version () {
- if [[ -n "$sbt_explicit_version" ]]; then
- echo "$sbt_explicit_version"
- else
- local v="$(build_props_sbt)"
- if [[ -n "$v" ]]; then
- echo "$v"
- else
- echo "$sbt_release_version"
- fi
- fi
+set_sbt_version () {
+ sbt_version="${sbt_explicit_version:-$(build_props_sbt)}"
+ [[ -n "$sbt_version" ]] || sbt_version=$sbt_release_version
+ export sbt_version
}
# restore stty settings (echo in particular)
onSbtRunnerExit() {
[[ -n "$sbt_saved_stty" ]] || return
- dlog ""
- dlog "restoring stty: $sbt_saved_stty"
+ vlog ""
+ vlog "restoring stty: $sbt_saved_stty"
stty "$sbt_saved_stty"
unset sbt_saved_stty
}
@@ -73,7 +57,7 @@ onSbtRunnerExit() {
# save stty and trap exit, to ensure echo is reenabled if we are interrupted.
trap onSbtRunnerExit EXIT
sbt_saved_stty="$(stty -g 2>/dev/null)"
-dlog "Saved stty: $sbt_saved_stty"
+vlog "Saved stty: $sbt_saved_stty"
# this seems to cover the bases on OSX, and someone will
# have to tell me about the others.
@@ -119,12 +103,13 @@ init_default_option_file () {
declare -r cms_opts="-XX:+CMSClassUnloadingEnabled -XX:+UseConcMarkSweepGC"
declare -r jit_opts="-XX:ReservedCodeCacheSize=256m -XX:+TieredCompilation"
-declare -r default_jvm_opts="-ea -Dfile.encoding=UTF8 -XX:MaxPermSize=384m -Xms512m -Xmx1536m -Xss2m $jit_opts $cms_opts"
+declare -r default_jvm_opts_common="-Xms512m -Xmx1536m -Xss2m $jit_opts $cms_opts"
declare -r noshare_opts="-Dsbt.global.base=project/.sbtboot -Dsbt.boot.directory=project/.boot -Dsbt.ivy.home=project/.ivy"
declare -r latest_28="2.8.2"
declare -r latest_29="2.9.3"
-declare -r latest_210="2.10.3"
-declare -r latest_211="2.11.0-M5"
+declare -r latest_210="2.10.5"
+declare -r latest_211="2.11.7"
+declare -r latest_212="2.12.0-M3"
declare -r script_path="$(get_script_path "$BASH_SOURCE")"
declare -r script_name="${script_path##*/}"
@@ -133,7 +118,7 @@ declare -r script_name="${script_path##*/}"
declare java_cmd="java"
declare sbt_opts_file="$(init_default_option_file SBT_OPTS .sbtopts)"
declare jvm_opts_file="$(init_default_option_file JVM_OPTS .jvmopts)"
-declare sbt_launch_repo="http://typesafe.artifactoryonline.com/typesafe/ivy-releases"
+declare sbt_launch_repo="http://repo.typesafe.com/typesafe/ivy-releases"
# pull -J and -D options to give to java.
declare -a residual_args
@@ -144,14 +129,79 @@ declare -a sbt_commands
# args to jvm/sbt via files or environment variables
declare -a extra_jvm_opts extra_sbt_opts
-# if set, use JAVA_HOME over java found in path
-[[ -e "$JAVA_HOME/bin/java" ]] && java_cmd="$JAVA_HOME/bin/java"
+addJava () {
+ vlog "[addJava] arg = '$1'"
+ java_args+=("$1")
+}
+addSbt () {
+ vlog "[addSbt] arg = '$1'"
+ sbt_commands+=("$1")
+}
+setThisBuild () {
+ vlog "[addBuild] args = '$@'"
+ local key="$1" && shift
+ addSbt "set $key in ThisBuild := $@"
+}
+addScalac () {
+ vlog "[addScalac] arg = '$1'"
+ scalac_args+=("$1")
+}
+addResidual () {
+ vlog "[residual] arg = '$1'"
+ residual_args+=("$1")
+}
+addResolver () {
+ addSbt "set resolvers += $1"
+}
+addDebugger () {
+ addJava "-Xdebug"
+ addJava "-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=$1"
+}
+setScalaVersion () {
+ [[ "$1" == *"-SNAPSHOT" ]] && addResolver 'Resolver.sonatypeRepo("snapshots")'
+ addSbt "++ $1"
+}
+setJavaHome () {
+ java_cmd="$1/bin/java"
+ setThisBuild javaHome "Some(file(\"$1\"))"
+ export JAVA_HOME="$1"
+ export JDK_HOME="$1"
+ export PATH="$JAVA_HOME/bin:$PATH"
+}
+setJavaHomeQuietly () {
+ addSbt warn
+ setJavaHome "$1"
+ addSbt info
+}
+
+# if set, use JDK_HOME/JAVA_HOME over java found in path
+if [[ -e "$JDK_HOME/lib/tools.jar" ]]; then
+ setJavaHomeQuietly "$JDK_HOME"
+elif [[ -e "$JAVA_HOME/bin/java" ]]; then
+ setJavaHomeQuietly "$JAVA_HOME"
+fi
# directory to store sbt launchers
declare sbt_launch_dir="$HOME/.sbt/launchers"
[[ -d "$sbt_launch_dir" ]] || mkdir -p "$sbt_launch_dir"
[[ -w "$sbt_launch_dir" ]] || sbt_launch_dir="$(mktemp -d -t sbt_extras_launchers.XXXXXX)"
+java_version () {
+ local version=$("$java_cmd" -version 2>&1 | grep -E -e '(java|openjdk) version' | awk '{ print $3 }' | tr -d \")
+ vlog "Detected Java version: $version"
+ echo "${version:2:1}"
+}
+
+# MaxPermSize critical on pre-8 jvms but incurs noisy warning on 8+
+default_jvm_opts () {
+ local v="$(java_version)"
+ if [[ $v -ge 8 ]]; then
+ echo "$default_jvm_opts_common"
+ else
+ echo "-XX:MaxPermSize=384m $default_jvm_opts_common"
+ fi
+}
+
build_props_scala () {
if [[ -r "$buildProps" ]]; then
versionLine="$(grep '^build.scala.versions' "$buildProps")"
@@ -162,22 +212,20 @@ build_props_scala () {
execRunner () {
# print the arguments one to a line, quoting any containing spaces
- [[ "$verbose" || "$debug" ]] && echo "# Executing command line:" && {
+ vlog "# Executing command line:" && {
for arg; do
if [[ -n "$arg" ]]; then
if printf "%s\n" "$arg" | grep -q ' '; then
- printf "\"%s\"\n" "$arg"
+ printf >&2 "\"%s\"\n" "$arg"
else
- printf "%s\n" "$arg"
+ printf >&2 "%s\n" "$arg"
fi
fi
done
- echo ""
+ vlog ""
}
- if [[ -n "$batch" ]]; then
- exec /dev/null; then
- curl --fail --silent "$url" --output "$jar"
+ curl --fail --silent --location "$url" --output "$jar"
elif which wget >/dev/null; then
wget --quiet -O "$jar" "$url"
fi
@@ -207,9 +255,8 @@ download_url () {
}
acquire_sbt_jar () {
- for_sbt_version="$(sbt_version)"
- sbt_url="$(jar_url "$for_sbt_version")"
- sbt_jar="$(jar_file "$for_sbt_version")"
+ sbt_url="$(jar_url "$sbt_version")"
+ sbt_jar="$(jar_file "$sbt_version")"
[[ -r "$sbt_jar" ]] || download_url "$sbt_url" "$sbt_jar"
}
@@ -218,11 +265,23 @@ usage () {
cat < display stack traces with a max of frames (default: -1, traces suppressed)
+ -debug-inc enable debugging log for the incremental compiler
-no-colors disable ANSI color codes
-sbt-create start sbt even if current directory contains no sbt project
-sbt-dir