summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBryan Duxbury <bryanduxbury@apache.org>2009-10-01 20:53:45 +0000
committerBryan Duxbury <bryanduxbury@apache.org>2009-10-01 20:53:45 +0000
commit51f288062dceebbb16886752ddeb0a24a8d04956 (patch)
tree39a9b4ee28f83ca7b5d6d227028805503c8ee9bf
parent315a5dbe29213aa70750f4e93542e1d72f3b0bb9 (diff)
downloadthrift-51f288062dceebbb16886752ddeb0a24a8d04956.tar.gz
THRIFT-446. java: PartialDeserialization in Java
This patch adds a partialDeserialize method to TDeserializer that allows you to request a specific subfield of the serialized data. git-svn-id: https://svn.apache.org/repos/asf/incubator/thrift/trunk@820786 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r--lib/java/build.xml2
-rw-r--r--lib/java/src/org/apache/thrift/TDeserializer.java57
-rw-r--r--lib/java/test/org/apache/thrift/test/PartialDeserializeTest.java82
-rw-r--r--test/DebugProtoTest.thrift6
4 files changed, 147 insertions, 0 deletions
diff --git a/lib/java/build.xml b/lib/java/build.xml
index dbbaf6b57..c62694816 100644
--- a/lib/java/build.xml
+++ b/lib/java/build.xml
@@ -182,6 +182,8 @@
classpathref="test.classpath" failonerror="true" />
<java classname="org.apache.thrift.test.UnionTest"
classpathref="test.classpath" failonerror="true" />
+ <java classname="org.apache.thrift.test.PartialDeserializeTest"
+ classpathref="test.classpath" failonerror="true" />
</target>
<target name="generate">
diff --git a/lib/java/src/org/apache/thrift/TDeserializer.java b/lib/java/src/org/apache/thrift/TDeserializer.java
index d6dd5d4b1..7b7d51dc1 100644
--- a/lib/java/src/org/apache/thrift/TDeserializer.java
+++ b/lib/java/src/org/apache/thrift/TDeserializer.java
@@ -23,7 +23,11 @@ import java.io.ByteArrayInputStream;
import java.io.UnsupportedEncodingException;
import org.apache.thrift.protocol.TBinaryProtocol;
+import org.apache.thrift.protocol.TField;
+import org.apache.thrift.protocol.TProtocol;
import org.apache.thrift.protocol.TProtocolFactory;
+import org.apache.thrift.protocol.TProtocolUtil;
+import org.apache.thrift.protocol.TType;
import org.apache.thrift.transport.TIOStreamTransport;
/**
@@ -81,6 +85,59 @@ public class TDeserializer {
}
/**
+ * Deserialize only a single Thrift object (addressed by recursively using field id)
+ * from a byte record.
+ * @param record The object to read from
+ * @param tb The object to read into
+ * @param fieldIdPath The FieldId's that define a path tb
+ * @throws TException
+ */
+ public void partialDeserialize(TBase tb, byte[] bytes, int ... fieldIdPath) throws TException {
+ // if there are no elements in the path, then the user is looking for the
+ // regular deserialize method
+ // TODO: it might be nice not to have to do this check every time to save
+ // some performance.
+ if (fieldIdPath.length == 0) {
+ deserialize(tb, bytes);
+ return;
+ }
+
+ TProtocol iprot = protocolFactory_.getProtocol(
+ new TIOStreamTransport(
+ new ByteArrayInputStream(bytes)));
+
+ // index into field ID path being currently searched for
+ int curPathIndex = 0;
+
+ iprot.readStructBegin();
+
+ while (curPathIndex < fieldIdPath.length) {
+ TField field = iprot.readFieldBegin();
+ // we can stop searching if we either see a stop or we go past the field
+ // id we're looking for (since fields should now be serialized in asc
+ // order).
+ if (field.type == TType.STOP || field.id > fieldIdPath[curPathIndex]) {
+ return;
+ }
+
+ if (field.id != fieldIdPath[curPathIndex]) {
+ // Not the field we're looking for. Skip field.
+ TProtocolUtil.skip(iprot, field.type);
+ iprot.readFieldEnd();
+ } else {
+ // This field is the next step in the path. Step into field.
+ curPathIndex++;
+ if (curPathIndex < fieldIdPath.length) {
+ iprot.readStructBegin();
+ }
+ }
+ }
+
+ // when this line is reached, iprot will be positioned at the start of tb.
+ tb.read(iprot);
+ }
+
+ /**
* Deserialize the Thrift object from a Java string, using the default JVM
* charset encoding.
*
diff --git a/lib/java/test/org/apache/thrift/test/PartialDeserializeTest.java b/lib/java/test/org/apache/thrift/test/PartialDeserializeTest.java
new file mode 100644
index 000000000..d88a686da
--- /dev/null
+++ b/lib/java/test/org/apache/thrift/test/PartialDeserializeTest.java
@@ -0,0 +1,82 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.thrift.test;
+
+import org.apache.thrift.TBase;
+import org.apache.thrift.TDeserializer;
+import org.apache.thrift.TException;
+import org.apache.thrift.TSerializer;
+import org.apache.thrift.protocol.TBinaryProtocol;
+import org.apache.thrift.protocol.TCompactProtocol;
+import org.apache.thrift.protocol.TJSONProtocol;
+import org.apache.thrift.protocol.TProtocolFactory;
+
+import thrift.test.Backwards;
+import thrift.test.OneOfEach;
+import thrift.test.PrimitiveThenStruct;
+import thrift.test.StructWithAUnion;
+import thrift.test.TestUnion;
+
+public class PartialDeserializeTest {
+
+ private static final TProtocolFactory[] PROTOCOLS = new TProtocolFactory[] {
+ new TBinaryProtocol.Factory(),
+ new TCompactProtocol.Factory(),
+ new TJSONProtocol.Factory()
+ };
+
+ public static void main(String[] args) throws TException {
+ //Root:StructWithAUnion
+ // 1:Union
+ // 1.3:OneOfEach
+ OneOfEach Level3OneOfEach = Fixtures.oneOfEach;
+ TestUnion Level2TestUnion = new TestUnion(TestUnion.STRUCT_FIELD, Level3OneOfEach);
+ StructWithAUnion Level1SWU = new StructWithAUnion(Level2TestUnion);
+
+ Backwards bw = new Backwards(2, 1);
+ PrimitiveThenStruct pts = new PrimitiveThenStruct(12345, 67890, bw);
+
+ for (TProtocolFactory factory : PROTOCOLS) {
+ //Full deserialization test
+ testPartialDeserialize(factory, Level1SWU, new StructWithAUnion(), Level1SWU);
+
+ //Level 2 test
+ testPartialDeserialize(factory, Level1SWU, new TestUnion(), Level2TestUnion, StructWithAUnion.TEST_UNION);
+
+ //Level 3 on 3rd field test
+ testPartialDeserialize(factory, Level1SWU, new OneOfEach(), Level3OneOfEach, StructWithAUnion.TEST_UNION, TestUnion.STRUCT_FIELD);
+
+ //Test early termination when traversed path Field.id exceeds the one being searched for
+ testPartialDeserialize(factory, Level1SWU, new OneOfEach(), new OneOfEach(), StructWithAUnion.TEST_UNION, TestUnion.I32_FIELD);
+
+ //Test that readStructBegin isn't called on primitive
+ testPartialDeserialize(factory, pts, new Backwards(), bw, PrimitiveThenStruct.BW);
+ }
+ }
+
+ public static void testPartialDeserialize(TProtocolFactory protocolFactory, TBase input, TBase output, TBase expected, int ... fieldIdPath) throws TException {
+ byte[] record = new TSerializer(protocolFactory).serialize(input);
+ new TDeserializer(protocolFactory).partialDeserialize(output, record, fieldIdPath);
+ if(!output.equals(expected))
+ throw new RuntimeException("with " + protocolFactory.toString() + ", expected " + expected + " but got " + output);
+ }
+}
+
diff --git a/test/DebugProtoTest.thrift b/test/DebugProtoTest.thrift
index 9ba60a264..9b3952e6c 100644
--- a/test/DebugProtoTest.thrift
+++ b/test/DebugProtoTest.thrift
@@ -265,4 +265,10 @@ union TestUnion {
struct StructWithAUnion {
1: TestUnion test_union;
+}
+
+struct PrimitiveThenStruct {
+ 1: i32 blah;
+ 2: i32 blah2;
+ 3: Backwards bw;
} \ No newline at end of file