2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
20 package org
.apache
.thrift
.protocol
;
22 import org
.apache
.thrift
.TException
;
25 * Utility class with static methods for interacting with protocol data
29 public class TProtocolUtil
{
32 * The maximum recursive depth the skip() function will traverse before
33 * throwing a TException.
35 private static int maxSkipDepth
= Integer
.MAX_VALUE
;
38 * Specifies the maximum recursive depth that the skip function will
39 * traverse before throwing a TException. This is a global setting, so
40 * any call to skip in this JVM will enforce this value.
42 * @param depth the maximum recursive depth. A value of 2 would allow
43 * the skip function to skip a structure or collection with basic children,
44 * but it would not permit skipping a struct that had a field containing
45 * a child struct. A value of 1 would only allow skipping of simple
46 * types and empty structs/collections.
48 public static void setMaxSkipDepth(int depth
) {
53 * Skips over the next data element from the provided input TProtocol object.
55 * @param prot the protocol object to read from
56 * @param type the next value will be interpreted as this TType value.
58 public static void skip(TProtocol prot
, byte type
)
60 skip(prot
, type
, maxSkipDepth
);
64 * Skips over the next data element from the provided input TProtocol object.
66 * @param prot the protocol object to read from
67 * @param type the next value will be interpreted as this TType value.
68 * @param maxDepth this function will only skip complex objects to this
69 * recursive depth, to prevent Java stack overflow.
71 public static void skip(TProtocol prot
, byte type
, int maxDepth
)
74 throw new TException("Maximum skip depth exceeded");
106 prot
.readStructBegin();
108 TField field
= prot
.readFieldBegin();
109 if (field
.type
== TType
.STOP
) {
112 skip(prot
, field
.type
, maxDepth
- 1);
115 prot
.readStructEnd();
119 TMap map
= prot
.readMapBegin();
120 for (int i
= 0; i
< map
.size
; i
++) {
121 skip(prot
, map
.keyType
, maxDepth
- 1);
122 skip(prot
, map
.valueType
, maxDepth
- 1);
128 TSet set
= prot
.readSetBegin();
129 for (int i
= 0; i
< set
.size
; i
++) {
130 skip(prot
, set
.elemType
, maxDepth
- 1);
136 TList list
= prot
.readListBegin();
137 for (int i
= 0; i
< list
.size
; i
++) {
138 skip(prot
, list
.elemType
, maxDepth
- 1);
144 throw new TProtocolException(TProtocolException
.INVALID_DATA
,
145 "Unrecognized type " + type
);
150 * Attempt to determine the protocol used to serialize some data.
152 * The guess is based on known specificities of supported protocols.
153 * In some cases, no guess can be done, in that case we return the
154 * fallback TProtocolFactory.
155 * To be certain to correctly detect the protocol, the first encoded
156 * field should have a field id < 256
158 * @param data The serialized data to guess the protocol for.
159 * @param fallback The TProtocol to return if no guess can be made.
160 * @return a Class implementing TProtocolFactory which can be used to create a deserializer.
162 public static TProtocolFactory
guessProtocolFactory(byte[] data
, TProtocolFactory fallback
) {
164 // If the first and last bytes are opening/closing curly braces we guess the protocol as
165 // being TJSONProtocol.
166 // It could not be a TCompactBinary encoding for a field of type 0xb (Map)
167 // with delta id 7 as the last byte for TCompactBinary is always 0.
170 if ('{' == data
[0] && '}' == data
[data
.length
- 1]) {
171 return new TJSONProtocol
.Factory();
175 // If the last byte is not 0, then it cannot be TCompactProtocol, it must be
179 if (data
[data
.length
- 1] != 0) {
180 return new TBinaryProtocol
.Factory();
184 // A first byte of value > 16 indicates TCompactProtocol was used, and the first byte
185 // encodes a delta field id (id <= 15) and a field type.
188 if (data
[0] > 0x10) {
189 return new TCompactProtocol
.Factory();
193 // If the second byte is 0 then it is a field id < 256 encoded by TBinaryProtocol.
194 // It cannot possibly be TCompactProtocol since a value of 0 would imply a field id
195 // of 0 as the zig zag varint encoding would end.
198 if (data
.length
> 1 && 0 == data
[1]) {
199 return new TBinaryProtocol
.Factory();
203 // If bit 7 of the first byte of the field id is set then we have two choices:
204 // 1. A field id > 63 was encoded with TCompactProtocol.
205 // 2. A field id > 0x7fff (32767) was encoded with TBinaryProtocol and the last byte of the
206 // serialized data is 0.
207 // Option 2 is impossible since field ids are short and thus limited to 32767.
210 if (data
.length
> 1 && (data
[1] & 0x80) != 0) {
211 return new TCompactProtocol
.Factory();
215 // The remaining case is either a field id <= 63 encoded as TCompactProtocol,
216 // one >= 256 encoded with TBinaryProtocol with a last byte at 0, or an empty structure.
217 // As we cannot really decide, we return the fallback protocol.