diff --git a/java/src/main/java/org/msgpack/BufferedUnpackerImpl.java b/java/src/main/java/org/msgpack/BufferedUnpackerImpl.java
index 5fde4e18..0aba62b0 100644
--- a/java/src/main/java/org/msgpack/BufferedUnpackerImpl.java
+++ b/java/src/main/java/org/msgpack/BufferedUnpackerImpl.java
@@ -367,7 +367,7 @@ abstract class BufferedUnpackerImpl extends UnpackerImpl {
}
}
- final byte[] unpackRawBody(int length) throws IOException, MessageTypeException {
+ final byte[] unpackRawBody(int length) throws IOException {
more(length);
byte[] bytes = new byte[length];
System.arraycopy(buffer, offset, bytes, 0, length);
@@ -388,12 +388,12 @@ abstract class BufferedUnpackerImpl extends UnpackerImpl {
return s;
}
- final Object unpackObject() throws IOException, MessageTypeException {
+ final Object unpackObject() throws IOException {
// FIXME save state, restore state
UnpackResult result = new UnpackResult();
if(!next(result)) {
super.reset();
- throw new MessageTypeException();
+ throw new UnpackException("insufficient buffer");
}
return result.getData();
}
diff --git a/java/src/main/java/org/msgpack/Unpacker.java b/java/src/main/java/org/msgpack/Unpacker.java
index 7fd6fcd4..7563b392 100644
--- a/java/src/main/java/org/msgpack/Unpacker.java
+++ b/java/src/main/java/org/msgpack/Unpacker.java
@@ -23,6 +23,82 @@ import java.io.IOException;
import java.util.Iterator;
import java.nio.ByteBuffer;
+/**
+ * Deserializer class that includes Buffered API, Unbuffered API,
+ * Schema API and Direct Conversion API.
+ *
+ * Buffered API uses the internal buffer of the Unpacker.
+ * Following code uses Buffered API with an input stream:
+ *
+ * // create an unpacker with input stream
+ * Unpacker pac = new Unpacker(System.in);
+ *
+ * // take a object out using next() method, or ...
+ * UnpackResult result = pac.next();
+ *
+ * // use an iterator.
+ * for(Object obj : pac) {
+ * // use MessageConvertable interface to convert the
+ * // the generic object to the specific type.
+ * }
+ *
+ *
+ * Following code doesn't use the input stream and feeds buffer
+ * using {@link feed(byte[])} method. This is useful to use
+ * special stream like zlib or event-driven I/O library.
+ *
+ * // create an unpacker without input stream
+ * Unpacker pac = new Unpacker();
+ *
+ * // feed buffer to the internal buffer.
+ * pac.feed(input_bytes);
+ *
+ * // use next() method or iterators.
+ * for(Object obj : pac) {
+ * // ...
+ * }
+ *
+ *
+ * The combination of {@link reserveBuffer()}, {@link getBuffer()},
+ * {@link getBufferOffset()}, {@link getBufferCapacity()} and
+ * {@link bufferConsumed()} is useful to omit copying.
+ *
+ * // create an unpacker without input stream
+ * Unpacker pac = new Unpacker();
+ *
+ * // reserve internal buffer at least 1024 bytes.
+ * pac.reserveBuffer(1024);
+ *
+ * // feed buffer to the internal buffer upto pac.getBufferCapacity() bytes.
+ * System.in.read(pac.getBuffer(), pac.getBufferOffset(), pac.getBufferCapacity());
+ *
+ * // use next() method or iterators.
+ * for(Object obj : pac) {
+ * // ...
+ * }
+ *
+ *
+ * Unbuffered API doesn't initialize the internal buffer.
+ * You can manage the buffer manually.
+ *
+ * // create an unpacker with input stream
+ * Unpacker pac = new Unpacker(System.in);
+ *
+ * // manage the buffer manually.
+ * byte[] buffer = new byte[1024];
+ * int filled = System.in.read(buffer);
+ * int offset = 0;
+ *
+ * // deserialize objects using execute() method.
+ * int nextOffset = pac.execute(buffer, offset, filled);
+ *
+ * // take out object if deserialized object is ready.
+ * if(pac.isFinished()) {
+ * Object obj = pac.getData();
+ * // ...
+ * }
+ *
+ */
public class Unpacker implements Iterable {
// buffer:
@@ -59,38 +135,86 @@ public class Unpacker implements Iterable {
final BufferedUnpackerMixin impl = new BufferedUnpackerMixin();
+ /**
+ * Calls {@link Unpacker(DEFAULT_BUFFER_SIZE)}
+ */
public Unpacker() {
this(DEFAULT_BUFFER_SIZE);
}
+ /**
+ * Calls {@link Unpacker(null, bufferReserveSize)}
+ */
public Unpacker(int bufferReserveSize) {
this(null, bufferReserveSize);
}
+ /**
+ * Calls {@link Unpacker(stream, DEFAULT_BUFFER_SIZE)}
+ */
public Unpacker(InputStream stream) {
this(stream, DEFAULT_BUFFER_SIZE);
}
+ /**
+ * Constructs the unpacker.
+ * The stream is used to fill the buffer when more buffer is required by {@link next()} or {@link UnpackIterator#hasNext()} method.
+ * @param stream input stream to fill the buffer
+ * @param bufferReserveSize threshold size to expand the size of buffer
+ */
public Unpacker(InputStream stream, int bufferReserveSize) {
this.parsed = 0;
this.bufferReserveSize = bufferReserveSize/2;
this.stream = stream;
}
+ /**
+ * Sets schema to convert deserialized object into specific type.
+ * Default schema is {@link GenericSchema} that leaves objects for generic type. Use {@link MessageConvertable#messageConvert(Object)} method to convert the generic object.
+ * @param s schem to use
+ */
public Unpacker useSchema(Schema s) {
impl.setSchema(s);
return this;
}
+ /**
+ * Gets the input stream.
+ * @return the input stream. it may be null.
+ */
public InputStream getStream() {
return this.stream;
}
+ /**
+ * Sets the input stream.
+ * @param stream the input stream to set.
+ */
public void setStream(InputStream stream) {
this.stream = stream;
}
+
+ /**
+ * Fills the buffer with the specified buffer.
+ */
+ public void feed(byte[] buffer) {
+ feed(buffer, 0, buffer.length);
+ }
+
+ /**
+ * Fills the buffer with the specified buffer.
+ */
+ public void feed(byte[] buffer, int offset, int length) {
+ reserveBuffer(length);
+ System.arraycopy(buffer, offset, impl.buffer, impl.offset, length);
+ bufferConsumed(length);
+ }
+
+ /**
+ * Fills the buffer with the specified buffer.
+ */
public void feed(ByteBuffer buffer) {
int length = buffer.remaining();
if (length == 0) return;
@@ -99,45 +223,62 @@ public class Unpacker implements Iterable {
bufferConsumed(length);
}
- public void feed(byte[] buffer) {
- feed(buffer, 0, buffer.length);
- }
-
- public void feed(byte[] buffer, int offset, int length) {
- reserveBuffer(length);
- System.arraycopy(buffer, offset, impl.buffer, impl.offset, length);
- bufferConsumed(length);
- }
-
+ /**
+ * Swaps the internal buffer with the specified buffer.
+ * This method doesn't copy the buffer and the its contents will be rewritten by {@link fill()} or {@link feed(byte[])} method.
+ */
public void wrap(byte[] buffer) {
wrap(buffer, 0, buffer.length);
}
+ /**
+ * Swaps the internal buffer with the specified buffer.
+ * This method doesn't copy the buffer and the its contents will be rewritten by {@link fill()} or {@link feed(byte[])} method.
+ */
public void wrap(byte[] buffer, int offset, int length) {
impl.buffer = buffer;
impl.offset = offset;
impl.filled = length;
}
+ /**
+ * Fills the internal using the input stream.
+ * @return false if the stream is null or stream.read returns <= 0.
+ */
public boolean fill() throws IOException {
return impl.fill();
}
+
+ /**
+ * Returns the iterator that calls {@link next()} method repeatedly.
+ */
public Iterator iterator() {
return new UnpackIterator(this);
}
+ /**
+ * Deserializes one object and returns it.
+ * @return {@link UnpackResult#isFinished()} returns false if the buffer is insufficient to deserialize one object.
+ */
public UnpackResult next() throws IOException, UnpackException {
UnpackResult result = new UnpackResult();
impl.next(result);
return result;
}
+ /**
+ * Deserializes one object and returns it.
+ * @return false if the buffer is insufficient to deserialize one object.
+ */
public boolean next(UnpackResult result) throws IOException, UnpackException {
return impl.next(result);
}
+ /**
+ * Reserve free space of the internal buffer at least specified size and expands {@link getBufferCapacity()}.
+ */
public void reserveBuffer(int require) {
if(impl.buffer == null) {
int nextSize = (bufferReserveSize < require) ? require : bufferReserveSize;
@@ -163,22 +304,40 @@ public class Unpacker implements Iterable {
impl.offset = 0;
}
+ /**
+ * Returns the internal buffer.
+ */
public byte[] getBuffer() {
return impl.buffer;
}
- public int getBufferOffset() {
- return impl.filled;
- }
-
+ /**
+ * Returns the size of free space of the internal buffer.
+ */
public int getBufferCapacity() {
return impl.buffer.length - impl.filled;
}
+ /**
+ * Returns the offset of free space in the internal buffer.
+ */
+ public int getBufferOffset() {
+ return impl.filled;
+ }
+
+ /**
+ * Moves front the offset of the free space in the internal buffer.
+ * Call this method after fill the buffer manually using {@link reserveBuffer()}, {@link getBuffer()}, {@link getBufferOffset()} and {@link getBufferCapacity()} methods.
+ */
public void bufferConsumed(int size) {
impl.filled += size;
}
+ /**
+ * Deserializes one object upto the offset of the internal buffer.
+ * Call {@link reset()} method before calling this method again.
+ * @return true if one object is deserialized. Use {@link getData()} to get the deserialized object.
+ */
public boolean execute() throws UnpackException {
int noffset = impl.execute(impl.buffer, impl.offset, impl.filled);
if(noffset <= impl.offset) {
@@ -190,10 +349,24 @@ public class Unpacker implements Iterable {
}
+ /**
+ * Deserializes one object over the specified buffer.
+ * This method doesn't use the internal buffer.
+ * Use {@link isFinished()} method to known a object is ready to get.
+ * Call {@link reset()} method before calling this method again.
+ * @return offset position that is parsed.
+ */
public int execute(byte[] buffer) throws UnpackException {
return execute(buffer, 0, buffer.length);
}
+ /**
+ * Deserializes one object over the specified buffer.
+ * This method doesn't use the internal buffer.
+ * Use {@link isFinished()} method to known a object is ready to get.
+ * Call {@link reset()} method before calling this method again.
+ * @return offset position that is parsed.
+ */
public int execute(byte[] buffer, int offset, int length) throws UnpackException {
int noffset = impl.execute(buffer, offset + impl.offset, length);
impl.offset = noffset - offset;
@@ -203,14 +376,23 @@ public class Unpacker implements Iterable {
return noffset;
}
- public boolean isFinished() {
- return impl.isFinished();
- }
-
+ /**
+ * Gets the object deserialized by {@link execute(byte[])} method.
+ */
public Object getData() {
return impl.getData();
}
+ /**
+ * Returns true if an object is ready to get with {@link getData()} method.
+ */
+ public boolean isFinished() {
+ return impl.isFinished();
+ }
+
+ /**
+ * Resets the internal state of the unpacker.
+ */
public void reset() {
impl.reset();
}
@@ -236,59 +418,130 @@ public class Unpacker implements Iterable {
}
+ /**
+ * Gets one {@code byte} value from the buffer.
+ * This method calls {@link fill()} method if needed.
+ * @throws MessageTypeException the first value of the buffer is not a {@code byte}.
+ */
public byte unpackByte() throws IOException, MessageTypeException {
return impl.unpackByte();
}
+ /**
+ * Gets one {@code short} value from the buffer.
+ * This method calls {@link fill()} method if needed.
+ * @throws MessageTypeException the first value of the buffer is not a {@code short}.
+ */
public short unpackShort() throws IOException, MessageTypeException {
return impl.unpackShort();
}
+ /**
+ * Gets one {@code int} value from the buffer.
+ * This method calls {@link fill()} method if needed.
+ * @throws MessageTypeException the first value of the buffer is not a {@code int}.
+ */
public int unpackInt() throws IOException, MessageTypeException {
return impl.unpackInt();
}
+ /**
+ * Gets one {@code long} value from the buffer.
+ * This method calls {@link fill()} method if needed.
+ * @throws MessageTypeException the first value of the buffer is not a {@code long}.
+ */
public long unpackLong() throws IOException, MessageTypeException {
return impl.unpackLong();
}
+ /**
+ * Gets one {@code float} value from the buffer.
+ * This method calls {@link fill()} method if needed.
+ * @throws MessageTypeException the first value of the buffer is not a {@code float}.
+ */
public float unpackFloat() throws IOException, MessageTypeException {
return impl.unpackFloat();
}
+ /**
+ * Gets one {@code double} value from the buffer.
+ * This method calls {@link fill()} method if needed.
+ * @throws MessageTypeException the first value of the buffer is not a {@code double}.
+ */
public double unpackDouble() throws IOException, MessageTypeException {
return impl.unpackDouble();
}
+ /**
+ * Gets one {@code null} value from the buffer.
+ * This method calls {@link fill()} method if needed.
+ * @throws MessageTypeException the first value of the buffer is not a {@code null}.
+ */
public Object unpackNull() throws IOException, MessageTypeException {
return impl.unpackNull();
}
+ /**
+ * Gets one {@code boolean} value from the buffer.
+ * This method calls {@link fill()} method if needed.
+ * @throws MessageTypeException the first value of the buffer is not a {@code boolean}.
+ */
public boolean unpackBoolean() throws IOException, MessageTypeException {
return impl.unpackBoolean();
}
+ /**
+ * Gets one array header from the buffer.
+ * This method calls {@link fill()} method if needed.
+ * @return the length of the map. There are {@code retval} objects to get.
+ * @throws MessageTypeException the first value of the buffer is not a array.
+ */
public int unpackArray() throws IOException, MessageTypeException {
return impl.unpackArray();
}
+ /**
+ * Gets one map header from the buffer.
+ * This method calls {@link fill()} method if needed.
+ * @return the length of the map. There are {@code retval * 2} objects to get.
+ * @throws MessageTypeException the first value of the buffer is not a map.
+ */
public int unpackMap() throws IOException, MessageTypeException {
return impl.unpackMap();
}
+ /**
+ * Gets one raw header from the buffer.
+ * This method calls {@link fill()} method if needed.
+ * @return the length of the raw bytes. There are {@code retval} bytes to get.
+ * @throws MessageTypeException the first value of the buffer is not a raw bytes.
+ */
public int unpackRaw() throws IOException, MessageTypeException {
return impl.unpackRaw();
}
- public byte[] unpackRawBody(int length) throws IOException, MessageTypeException {
+ /**
+ * Gets one raw header from the buffer.
+ * This method calls {@link fill()} method if needed.
+ */
+ public byte[] unpackRawBody(int length) throws IOException {
return impl.unpackRawBody(length);
}
+ /**
+ * Gets one {@code String} value from the buffer.
+ * This method calls {@link fill()} method if needed.
+ * @throws MessageTypeException the first value of the buffer is not a {@code String}.
+ */
final public String unpackString() throws IOException, MessageTypeException {
return impl.unpackString();
}
- final public Object unpackObject() throws IOException, MessageTypeException {
+ /**
+ * Gets one {@code Object} value from the buffer.
+ * This method calls {@link fill()} method if needed.
+ */
+ final public Object unpackObject() throws IOException {
return impl.unpackObject();
}
}