From: Mark Slee Date: Tue, 27 Nov 2007 08:38:52 +0000 (+0000) Subject: TJSONProtocol writing support in Java X-Git-Tag: 0.2.0~1105 X-Git-Url: https://source.supwisdom.com/gerrit/gitweb?a=commitdiff_plain;h=844ac12489600d7647f01ab4f9b99d9e1b81e69e;p=common%2Fthrift.git 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 00000000..2fb3794d --- /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 + */ +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 00000000..07dee63e --- /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 + * @author Mark Slee + */ +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 writeContextStack_ = new Stack(); + + /** + * 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 8322b331..2c108703 100644 --- a/lib/java/src/transport/TTransport.java +++ b/lib/java/src/transport/TTransport.java @@ -56,7 +56,7 @@ public abstract class TTransport { 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 @@ -78,6 +78,16 @@ public abstract class TTransport { return got; } + /** + * 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. * @@ -94,6 +104,6 @@ public abstract class TTransport { * * @throws TTransportException if there was an error writing out data. */ - public void flush() + public void flush() throws TTransportException {} } diff --git a/test/java/src/TestClient.java b/test/java/src/TestClient.java index 778bb160..87f3971e 100644 --- a/test/java/src/TestClient.java +++ b/test/java/src/TestClient.java @@ -4,12 +4,14 @@ package com.facebook.thrift.test; import thrift.test.*; import com.facebook.thrift.TApplicationException; +import com.facebook.thrift.TSerializer; import com.facebook.thrift.transport.TTransport; import com.facebook.thrift.transport.TSocket; import com.facebook.thrift.transport.THttpClient; import com.facebook.thrift.transport.TFramedTransport; import com.facebook.thrift.transport.TTransportException; import com.facebook.thrift.protocol.TBinaryProtocol; +import com.facebook.thrift.protocol.TJSONProtocol; import java.util.AbstractMap; import java.util.HashMap; @@ -39,7 +41,7 @@ public class TestClient { if (args[i].equals("-h")) { String[] hostport = (args[++i]).split(":"); host = hostport[0]; - port = Integer.valueOf(hostport[1]); + port = Integer.valueOf(hostport[1]); } else if (args[i].equals("-f") || args[i].equals("-framed")) { framed = true; } else if (args[i].equals("-fo")) { @@ -54,9 +56,9 @@ public class TestClient { } catch (Exception x) { x.printStackTrace(); } - + TTransport transport; - + if (url != null) { transport = new THttpClient(url); } else { @@ -74,6 +76,7 @@ public class TestClient { new TBinaryProtocol(transport); ThriftTest.Client testClient = new ThriftTest.Client(binaryProtocol); + Insanity insane = new Insanity(); long timeMin = 0; long timeMax = 0; @@ -93,7 +96,7 @@ public class TestClient { } long start = System.nanoTime(); - + /** * VOID TEST */ @@ -118,7 +121,7 @@ public class TestClient { System.out.print("testByte(1)"); byte i8 = testClient.testByte((byte)1); System.out.print(" = " + i8 + "\n"); - + /** * I32 TEST */ @@ -307,7 +310,7 @@ public class TestClient { /** * INSANITY TEST */ - Insanity insane = new Insanity(); + insane = new Insanity(); insane.userMap = new HashMap(); insane.userMap.put(Numberz.FIVE, (long)5000); Xtruct truck = new Xtruct(); @@ -369,14 +372,18 @@ public class TestClient { } long timeAvg = timeTot / numTests; - + System.out.println("Min time: " + timeMin/1000 + "us"); System.out.println("Max time: " + timeMax/1000 + "us"); System.out.println("Avg time: " + timeAvg/1000 + "us"); - + + String json = (new TSerializer(new TJSONProtocol.Factory())).toString(insane); + + System.out.println("\nFor good meausre here is some JSON:\n" + json); + } catch (Exception x) { x.printStackTrace(); - } + } }