TJSONProtocol writing support in Java
Summary: TJSONProtocol for Java with write support and a TSerializer utility for easier conversion of Thrift objects into byte[] or strings.
Reviewed By: dreiss
Test Plan: Included a basic piece of this in test/ client for Java.
Revert: OK
DiffCamp Revision: 3890
git-svn-id: https://svn.apache.org/repos/asf/incubator/thrift/trunk@665367 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/lib/java/src/TSerializer.java b/lib/java/src/TSerializer.java
new file mode 100644
index 0000000..2fb3794
--- /dev/null
+++ b/lib/java/src/TSerializer.java
@@ -0,0 +1,73 @@
+// Copyright (c) 2006- Facebook
+// Distributed under the Thrift Software License
+//
+// See accompanying file LICENSE or visit the Thrift site at:
+// http://developers.facebook.com/thrift/
+
+package com.facebook.thrift;
+
+import java.io.ByteArrayOutputStream;
+import java.io.UnsupportedEncodingException;
+
+import com.facebook.thrift.protocol.TBinaryProtocol;
+import com.facebook.thrift.protocol.TProtocol;
+import com.facebook.thrift.protocol.TProtocolFactory;
+import com.facebook.thrift.transport.TIOStreamTransport;
+import com.facebook.thrift.transport.TTransport;
+
+/**
+ * Generic utility for easily serializing objects into a byte array.
+ *
+ * @author Mark Slee <mcslee@facebook.com>
+ */
+public class TSerializer {
+
+ private static class TByteArrayTransport extends TIOStreamTransport {
+
+ private final ByteArrayOutputStream baos_ = new ByteArrayOutputStream();
+
+ public TByteArrayTransport() {
+ outputStream_ = baos_;
+ }
+
+ public byte[] get() {
+ return baos_.toByteArray();
+ }
+
+ public void reset() {
+ baos_.reset();
+ }
+ }
+
+ private TProtocol protocol_;
+
+ private final TByteArrayTransport transport_ = new TByteArrayTransport();
+
+ public TSerializer() {
+ this(new TBinaryProtocol.Factory());
+ }
+
+ public TSerializer(TProtocolFactory protocolFactory) {
+ protocol_ = protocolFactory.getProtocol(transport_);
+ }
+
+ public byte[] serialize(TBase base) throws TException {
+ transport_.reset();
+ base.write(protocol_);
+ byte[] data = transport_.get();
+ return data;
+ }
+
+ public String toString(TBase base, String charset) throws TException {
+ try {
+ return new String(serialize(base), charset);
+ } catch (UnsupportedEncodingException uex) {
+ throw new TException("JVM DOES NOT SUPPORT ENCODING");
+ }
+ }
+
+ public String toString(TBase base) throws TException {
+ return new String(serialize(base));
+ }
+}
+
diff --git a/lib/java/src/protocol/TJSONProtocol.java b/lib/java/src/protocol/TJSONProtocol.java
new file mode 100644
index 0000000..07dee63
--- /dev/null
+++ b/lib/java/src/protocol/TJSONProtocol.java
@@ -0,0 +1,337 @@
+// Copyright (c) 2006- Facebook
+// Distributed under the Thrift Software License
+//
+// See accompanying file LICENSE or visit the Thrift site at:
+// http://developers.facebook.com/thrift/
+
+package com.facebook.thrift.protocol;
+
+import com.facebook.thrift.TException;
+import com.facebook.thrift.transport.TTransport;
+import java.io.UnsupportedEncodingException;
+import java.util.Stack;
+
+/**
+ * JSON protocol implementation for thrift.
+ *
+ * @author Joydeep Sen Sarma <jssarma@facebook.com>
+ * @author Mark Slee <mcslee@facebook.com>
+ */
+public class TJSONProtocol extends TProtocol {
+
+ /**
+ * Factory
+ */
+ public static class Factory implements TProtocolFactory {
+ public TProtocol getProtocol(TTransport trans) {
+ return new TJSONProtocol(trans);
+ }
+ }
+
+ public static final byte[] COMMA = new byte[] {','};
+ public static final byte[] COLON = new byte[] {':'};
+ public static final byte[] QUOTE = new byte[] {'"'};
+ public static final byte[] LBRACE = new byte[] {'{'};
+ public static final byte[] RBRACE = new byte[] {'}'};
+ public static final byte[] LBRACKET = new byte[] {'['};
+ public static final byte[] RBRACKET = new byte[] {']'};
+
+ protected class Context {
+ protected void write() throws TException {}
+ }
+
+ protected class ListContext extends Context {
+ protected boolean first_ = true;
+
+ protected void write() throws TException {
+ if (first_) {
+ first_ = false;
+ } else {
+ trans_.write(COMMA);
+ }
+ }
+ }
+
+ protected class StructContext extends Context {
+ protected boolean first_ = true;
+ protected boolean colon_ = true;
+
+ protected void write() throws TException {
+ if (first_) {
+ first_ = false;
+ colon_ = true;
+ } else {
+ trans_.write(colon_ ? COLON : COMMA);
+ colon_ = !colon_;
+ }
+ }
+ }
+
+ protected final Context BASE_CONTEXT = new Context();
+
+ /**
+ * Stack of nested contexts that we may be in.
+ */
+ protected Stack<Context> writeContextStack_ = new Stack<Context>();
+
+ /**
+ * Current context that we are in
+ */
+ protected Context writeContext_ = BASE_CONTEXT;
+
+ /**
+ * Push a new write context onto the stack.
+ */
+ protected void pushWriteContext(Context c) {
+ writeContextStack_.push(writeContext_);
+ writeContext_ = c;
+ }
+
+ /**
+ * Pop the last write context off the stack
+ */
+ protected void popWriteContext() {
+ writeContext_ = writeContextStack_.pop();
+ }
+
+ /**
+ * Constructor
+ */
+ public TJSONProtocol(TTransport trans) {
+ super(trans);
+ }
+
+ public void writeMessageBegin(TMessage message) throws TException {
+ trans_.write(LBRACKET);
+ pushWriteContext(new ListContext());
+ writeString(message.name);
+ writeByte(message.type);
+ writeI32(message.seqid);
+ }
+
+ public void writeMessageEnd() throws TException {
+ popWriteContext();
+ trans_.write(RBRACKET);
+ }
+
+ public void writeStructBegin(TStruct struct) throws TException {
+ writeContext_.write();
+ trans_.write(LBRACE);
+ pushWriteContext(new StructContext());
+ }
+
+ public void writeStructEnd() throws TException {
+ popWriteContext();
+ trans_.write(RBRACE);
+ }
+
+ public void writeFieldBegin(TField field) throws TException {
+ // Note that extra type information is omitted in JSON!
+ writeString(field.name);
+ }
+
+ public void writeFieldEnd() {}
+
+ public void writeFieldStop() {}
+
+ public void writeMapBegin(TMap map) throws TException {
+ writeContext_.write();
+ trans_.write(LBRACE);
+ pushWriteContext(new StructContext());
+ // No metadata!
+ }
+
+ public void writeMapEnd() throws TException {
+ popWriteContext();
+ trans_.write(RBRACE);
+ }
+
+ public void writeListBegin(TList list) throws TException {
+ writeContext_.write();
+ trans_.write(LBRACKET);
+ pushWriteContext(new ListContext());
+ // No metadata!
+ }
+
+ public void writeListEnd() throws TException {
+ popWriteContext();
+ trans_.write(RBRACKET);
+ }
+
+ public void writeSetBegin(TSet set) throws TException {
+ writeContext_.write();
+ trans_.write(LBRACKET);
+ pushWriteContext(new ListContext());
+ // No metadata!
+ }
+
+ public void writeSetEnd() throws TException {
+ popWriteContext();
+ trans_.write(RBRACKET);
+ }
+
+ public void writeBool(boolean b) throws TException {
+ writeByte(b ? (byte)1 : (byte)0);
+ }
+
+ public void writeByte(byte b) throws TException {
+ writeI32(b);
+ }
+
+ public void writeI16(short i16) throws TException {
+ writeI32(i16);
+ }
+
+ public void writeI32(int i32) throws TException {
+ writeContext_.write();
+ _writeStringData(Integer.toString(i32));
+ }
+
+ public void _writeStringData(String s) throws TException {
+ try {
+ byte[] b = s.getBytes("UTF-8");
+ trans_.write(b);
+ } catch (UnsupportedEncodingException uex) {
+ throw new TException("JVM DOES NOT SUPPORT UTF-8");
+ }
+ }
+
+ public void writeI64(long i64) throws TException {
+ writeContext_.write();
+ _writeStringData(Long.toString(i64));
+ }
+
+ public void writeDouble(double dub) throws TException {
+ writeContext_.write();
+ _writeStringData(Double.toString(dub));
+ }
+
+ public void writeString(String str) throws TException {
+ writeContext_.write();
+ trans_.write(QUOTE);
+
+ int length = str.length();
+ StringBuffer escape = new StringBuffer(length);
+ char c;
+ for (int i = 0; i < length; ++i) {
+ c = str.charAt(i);
+ switch (c) {
+ case '"':
+ case '\\':
+ escape.append('\\');
+ escape.append(c);
+ break;
+ default:
+ escape.append(c);
+ break;
+ }
+ }
+ _writeStringData(escape.toString());
+ trans_.write(QUOTE);
+ }
+
+ public void writeBinary(byte[] bin) throws TException {
+ try {
+ // TODO(mcslee): Fix this
+ writeString(new String(bin, "UTF-8"));
+ } catch (UnsupportedEncodingException uex) {
+ throw new TException("JVM DOES NOT SUPPORT UTF-8");
+ }
+ }
+
+ /**
+ * Reading methods.
+ */
+
+ public TMessage readMessageBegin() throws TException {
+ TMessage message = new TMessage();
+ // TODO(mcslee): implement
+ return message;
+ }
+
+ public void readMessageEnd() {}
+
+ public TStruct readStructBegin() {
+ // TODO(mcslee): implement
+ return new TStruct();
+ }
+
+ public void readStructEnd() {}
+
+ public TField readFieldBegin() throws TException {
+ TField field = new TField();
+ // TODO(mcslee): implement
+ return field;
+ }
+
+ public void readFieldEnd() {}
+
+ public TMap readMapBegin() throws TException {
+ TMap map = new TMap();
+ // TODO(mcslee): implement
+ return map;
+ }
+
+ public void readMapEnd() {}
+
+ public TList readListBegin() throws TException {
+ TList list = new TList();
+ // TODO(mcslee): implement
+ return list;
+ }
+
+ public void readListEnd() {}
+
+ public TSet readSetBegin() throws TException {
+ TSet set = new TSet();
+ // TODO(mcslee): implement
+ return set;
+ }
+
+ public void readSetEnd() {}
+
+ public boolean readBool() throws TException {
+ return (readByte() == 1);
+ }
+
+ public byte readByte() throws TException {
+ // TODO(mcslee): implement
+ return 0;
+ }
+
+ public short readI16() throws TException {
+ // TODO(mcslee): implement
+ return 0;
+ }
+
+ public int readI32() throws TException {
+ // TODO(mcslee): implement
+ return 0;
+ }
+
+ public long readI64() throws TException {
+ // TODO(mcslee): implement
+ return 0;
+ }
+
+ public double readDouble() throws TException {
+ // TODO(mcslee): implement
+ return 0;
+ }
+
+ public String readString() throws TException {
+ // TODO(mcslee): implement
+ return "";
+ }
+
+ public String readStringBody(int size) throws TException {
+ // TODO(mcslee): implement
+ return "";
+ }
+
+ public byte[] readBinary() throws TException {
+ // TODO(mcslee): implement
+ return new byte[0];
+ }
+
+}
diff --git a/lib/java/src/transport/TTransport.java b/lib/java/src/transport/TTransport.java
index 8322b33..2c10870 100644
--- a/lib/java/src/transport/TTransport.java
+++ b/lib/java/src/transport/TTransport.java
@@ -56,7 +56,7 @@
throws TTransportException;
/**
- * Guarantees that all of len bytes are
+ * Guarantees that all of len bytes are
*
* @param buf Array to read into
* @param off Index to start reading at
@@ -79,6 +79,16 @@
}
/**
+ * Writes the buffer to the output
+ *
+ * @param buf The output data buffer
+ * @throws TTransportException if an error occurs writing data
+ */
+ public void write(byte[] buf) throws TTransportException {
+ write(buf, 0, buf.length);
+ }
+
+ /**
* Writes up to len bytes from the buffer.
*
* @param buf The output data buffer
@@ -94,6 +104,6 @@
*
* @throws TTransportException if there was an error writing out data.
*/
- public void flush()
+ public void flush()
throws TTransportException {}
}