1 /* 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 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 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 17 * under the License. 18 */ 19 20 package org.apache.thrift; 21 22 import java.io.UnsupportedEncodingException; 23 import java.nio.ByteBuffer; 24 25 import org.apache.thrift.protocol.TBinaryProtocol; 26 import org.apache.thrift.protocol.TField; 27 import org.apache.thrift.protocol.TProtocol; 28 import org.apache.thrift.protocol.TProtocolFactory; 29 import org.apache.thrift.protocol.TProtocolUtil; 30 import org.apache.thrift.protocol.TType; 31 import org.apache.thrift.transport.TMemoryInputTransport; 32 import org.apache.thrift.transport.TTransportException; 33 34 /** 35 * Generic utility for easily deserializing objects from a byte array or Java 36 * String. 37 * 38 */ 39 public class TDeserializer { 40 private final TProtocol protocol_; 41 private final TMemoryInputTransport trans_; 42 43 /** 44 * Create a new TDeserializer that uses the TBinaryProtocol by default. 45 */ TDeserializer()46 public TDeserializer() throws TTransportException { 47 this(new TBinaryProtocol.Factory()); 48 } 49 50 /** 51 * Create a new TDeserializer. It will use the TProtocol specified by the 52 * factory that is passed in. 53 * 54 * @param protocolFactory Factory to create a protocol 55 */ TDeserializer(TProtocolFactory protocolFactory)56 public TDeserializer(TProtocolFactory protocolFactory) throws TTransportException { 57 trans_ = new TMemoryInputTransport(new TConfiguration()); 58 protocol_ = protocolFactory.getProtocol(trans_); 59 } 60 61 /** 62 * Deserialize the Thrift object from a byte array. 63 * 64 * @param base The object to read into 65 * @param bytes The array to read from 66 */ deserialize(TBase base, byte[] bytes)67 public void deserialize(TBase base, byte[] bytes) throws TException { 68 deserialize(base, bytes, 0, bytes.length); 69 } 70 71 /** 72 * Deserialize the Thrift object from a byte array. 73 * 74 * @param base The object to read into 75 * @param bytes The array to read from 76 * @param offset The offset into {@code bytes} 77 * @param length The length to read from {@code bytes} 78 */ deserialize(TBase base, byte[] bytes, int offset, int length)79 public void deserialize(TBase base, byte[] bytes, int offset, int length) throws TException { 80 try { 81 trans_.reset(bytes, offset, length); 82 base.read(protocol_); 83 } finally { 84 trans_.clear(); 85 protocol_.reset(); 86 } 87 } 88 89 /** 90 * Deserialize the Thrift object from a Java string, using a specified 91 * character set for decoding. 92 * 93 * @param base The object to read into 94 * @param data The string to read from 95 * @param charset Valid JVM charset 96 */ deserialize(TBase base, String data, String charset)97 public void deserialize(TBase base, String data, String charset) throws TException { 98 try { 99 deserialize(base, data.getBytes(charset)); 100 } catch (UnsupportedEncodingException uex) { 101 throw new TException("JVM DOES NOT SUPPORT ENCODING: " + charset); 102 } finally { 103 protocol_.reset(); 104 } 105 } 106 107 /** 108 * Deserialize only a single Thrift object (addressed by recursively using field id) 109 * from a byte record. 110 * @param tb The object to read into 111 * @param bytes The serialized object to read from 112 * @param fieldIdPathFirst First of the FieldId's that define a path tb 113 * @param fieldIdPathRest The rest FieldId's that define a path tb 114 * @throws TException 115 */ partialDeserialize(TBase tb, byte[] bytes, TFieldIdEnum fieldIdPathFirst, TFieldIdEnum ... fieldIdPathRest)116 public void partialDeserialize(TBase tb, byte[] bytes, TFieldIdEnum fieldIdPathFirst, TFieldIdEnum ... fieldIdPathRest) throws TException { 117 try { 118 if (locateField(bytes, fieldIdPathFirst, fieldIdPathRest) != null) { 119 // if this line is reached, iprot will be positioned at the start of tb. 120 tb.read(protocol_); 121 } 122 } catch (Exception e) { 123 throw new TException(e); 124 } finally { 125 trans_.clear(); 126 protocol_.reset(); 127 } 128 } 129 130 /** 131 * Deserialize only a boolean field (addressed by recursively using field id) 132 * from a byte record. 133 * @param bytes The serialized object to read from 134 * @param fieldIdPathFirst First of the FieldId's that define a path to a boolean field 135 * @param fieldIdPathRest The rest FieldId's that define a path to a boolean field 136 * @throws TException 137 */ partialDeserializeBool(byte[] bytes, TFieldIdEnum fieldIdPathFirst, TFieldIdEnum ... fieldIdPathRest)138 public Boolean partialDeserializeBool(byte[] bytes, TFieldIdEnum fieldIdPathFirst, TFieldIdEnum ... fieldIdPathRest) throws TException { 139 return (Boolean) partialDeserializeField(TType.BOOL, bytes, fieldIdPathFirst, fieldIdPathRest); 140 } 141 142 /** 143 * Deserialize only a byte field (addressed by recursively using field id) 144 * from a byte record. 145 * @param bytes The serialized object to read from 146 * @param fieldIdPathFirst First of the FieldId's that define a path to a byte field 147 * @param fieldIdPathRest The rest FieldId's that define a path to a byte field 148 * @throws TException 149 */ partialDeserializeByte(byte[] bytes, TFieldIdEnum fieldIdPathFirst, TFieldIdEnum ... fieldIdPathRest)150 public Byte partialDeserializeByte(byte[] bytes, TFieldIdEnum fieldIdPathFirst, TFieldIdEnum ... fieldIdPathRest) throws TException { 151 return (Byte) partialDeserializeField(TType.BYTE, bytes, fieldIdPathFirst, fieldIdPathRest); 152 } 153 154 /** 155 * Deserialize only a double field (addressed by recursively using field id) 156 * from a byte record. 157 * @param bytes The serialized object to read from 158 * @param fieldIdPathFirst First of the FieldId's that define a path to a double field 159 * @param fieldIdPathRest The rest FieldId's that define a path to a double field 160 * @throws TException 161 */ partialDeserializeDouble(byte[] bytes, TFieldIdEnum fieldIdPathFirst, TFieldIdEnum ... fieldIdPathRest)162 public Double partialDeserializeDouble(byte[] bytes, TFieldIdEnum fieldIdPathFirst, TFieldIdEnum ... fieldIdPathRest) throws TException { 163 return (Double) partialDeserializeField(TType.DOUBLE, bytes, fieldIdPathFirst, fieldIdPathRest); 164 } 165 166 /** 167 * Deserialize only an i16 field (addressed by recursively using field id) 168 * from a byte record. 169 * @param bytes The serialized object to read from 170 * @param fieldIdPathFirst First of the FieldId's that define a path to an i16 field 171 * @param fieldIdPathRest The rest FieldId's that define a path to an i16 field 172 * @throws TException 173 */ partialDeserializeI16(byte[] bytes, TFieldIdEnum fieldIdPathFirst, TFieldIdEnum ... fieldIdPathRest)174 public Short partialDeserializeI16(byte[] bytes, TFieldIdEnum fieldIdPathFirst, TFieldIdEnum ... fieldIdPathRest) throws TException { 175 return (Short) partialDeserializeField(TType.I16, bytes, fieldIdPathFirst, fieldIdPathRest); 176 } 177 178 /** 179 * Deserialize only an i32 field (addressed by recursively using field id) 180 * from a byte record. 181 * @param bytes The serialized object to read from 182 * @param fieldIdPathFirst First of the FieldId's that define a path to an i32 field 183 * @param fieldIdPathRest The rest FieldId's that define a path to an i32 field 184 * @throws TException 185 */ partialDeserializeI32(byte[] bytes, TFieldIdEnum fieldIdPathFirst, TFieldIdEnum ... fieldIdPathRest)186 public Integer partialDeserializeI32(byte[] bytes, TFieldIdEnum fieldIdPathFirst, TFieldIdEnum ... fieldIdPathRest) throws TException { 187 return (Integer) partialDeserializeField(TType.I32, bytes, fieldIdPathFirst, fieldIdPathRest); 188 } 189 190 /** 191 * Deserialize only an i64 field (addressed by recursively using field id) 192 * from a byte record. 193 * @param bytes The serialized object to read from 194 * @param fieldIdPathFirst First of the FieldId's that define a path to an i64 field 195 * @param fieldIdPathRest The rest FieldId's that define a path to an i64 field 196 * @throws TException 197 */ partialDeserializeI64(byte[] bytes, TFieldIdEnum fieldIdPathFirst, TFieldIdEnum ... fieldIdPathRest)198 public Long partialDeserializeI64(byte[] bytes, TFieldIdEnum fieldIdPathFirst, TFieldIdEnum ... fieldIdPathRest) throws TException { 199 return (Long) partialDeserializeField(TType.I64, bytes, fieldIdPathFirst, fieldIdPathRest); 200 } 201 202 /** 203 * Deserialize only a string field (addressed by recursively using field id) 204 * from a byte record. 205 * @param bytes The serialized object to read from 206 * @param fieldIdPathFirst First of the FieldId's that define a path to a string field 207 * @param fieldIdPathRest The rest FieldId's that define a path to a string field 208 * @throws TException 209 */ partialDeserializeString(byte[] bytes, TFieldIdEnum fieldIdPathFirst, TFieldIdEnum ... fieldIdPathRest)210 public String partialDeserializeString(byte[] bytes, TFieldIdEnum fieldIdPathFirst, TFieldIdEnum ... fieldIdPathRest) throws TException { 211 return (String) partialDeserializeField(TType.STRING, bytes, fieldIdPathFirst, fieldIdPathRest); 212 } 213 214 /** 215 * Deserialize only a binary field (addressed by recursively using field id) 216 * from a byte record. 217 * @param bytes The serialized object to read from 218 * @param fieldIdPathFirst First of the FieldId's that define a path to a binary field 219 * @param fieldIdPathRest The rest FieldId's that define a path to a binary field 220 * @throws TException 221 */ partialDeserializeByteArray(byte[] bytes, TFieldIdEnum fieldIdPathFirst, TFieldIdEnum ... fieldIdPathRest)222 public ByteBuffer partialDeserializeByteArray(byte[] bytes, TFieldIdEnum fieldIdPathFirst, TFieldIdEnum ... fieldIdPathRest) throws TException { 223 // TType does not have binary, so we use the arbitrary num 100 224 return (ByteBuffer) partialDeserializeField((byte)100, bytes, fieldIdPathFirst, fieldIdPathRest); 225 } 226 227 /** 228 * Deserialize only the id of the field set in a TUnion (addressed by recursively using field id) 229 * from a byte record. 230 * @param bytes The serialized object to read from 231 * @param fieldIdPathFirst First of the FieldId's that define a path to a TUnion 232 * @param fieldIdPathRest The rest FieldId's that define a path to a TUnion 233 * @throws TException 234 */ partialDeserializeSetFieldIdInUnion(byte[] bytes, TFieldIdEnum fieldIdPathFirst, TFieldIdEnum ... fieldIdPathRest)235 public Short partialDeserializeSetFieldIdInUnion(byte[] bytes, TFieldIdEnum fieldIdPathFirst, TFieldIdEnum ... fieldIdPathRest) throws TException { 236 try { 237 TField field = locateField(bytes, fieldIdPathFirst, fieldIdPathRest); 238 if (field != null){ 239 protocol_.readStructBegin(); // The Union 240 return protocol_.readFieldBegin().id; // The field set in the union 241 } 242 return null; 243 } catch (Exception e) { 244 throw new TException(e); 245 } finally { 246 trans_.clear(); 247 protocol_.reset(); 248 } 249 } 250 partialDeserializeField(byte ttype, byte[] bytes, TFieldIdEnum fieldIdPathFirst, TFieldIdEnum ... fieldIdPathRest)251 private Object partialDeserializeField(byte ttype, byte[] bytes, TFieldIdEnum fieldIdPathFirst, TFieldIdEnum ... fieldIdPathRest) throws TException { 252 try { 253 TField field = locateField(bytes, fieldIdPathFirst, fieldIdPathRest); 254 if (field != null) { 255 if (ttype == field.type) { 256 // if this point is reached, iprot will be positioned at the start of 257 // the field 258 switch (ttype) { 259 case TType.BOOL: 260 return protocol_.readBool(); 261 case TType.BYTE: 262 return protocol_.readByte(); 263 case TType.DOUBLE: 264 return protocol_.readDouble(); 265 case TType.I16: 266 return protocol_.readI16(); 267 case TType.I32: 268 return protocol_.readI32(); 269 case TType.I64: 270 return protocol_.readI64(); 271 case TType.STRING: 272 return protocol_.readString(); 273 default: 274 return null; 275 } 276 } 277 // hack to differentiate between string and binary 278 if (ttype == 100 && field.type == TType.STRING) { 279 return protocol_.readBinary(); 280 } 281 } 282 return null; 283 } catch (Exception e) { 284 throw new TException(e); 285 } finally { 286 trans_.clear(); 287 protocol_.reset(); 288 } 289 } 290 locateField(byte[] bytes, TFieldIdEnum fieldIdPathFirst, TFieldIdEnum ... fieldIdPathRest)291 private TField locateField(byte[] bytes, TFieldIdEnum fieldIdPathFirst, TFieldIdEnum ... fieldIdPathRest) throws TException { 292 trans_.reset(bytes); 293 294 TFieldIdEnum[] fieldIdPath = new TFieldIdEnum[fieldIdPathRest.length + 1]; 295 fieldIdPath[0] = fieldIdPathFirst; 296 System.arraycopy(fieldIdPathRest, 0, fieldIdPath, 1, fieldIdPathRest.length); 297 298 // index into field ID path being currently searched for 299 int curPathIndex = 0; 300 301 // this will be the located field, or null if it is not located 302 TField field = null; 303 304 protocol_.readStructBegin(); 305 306 while (curPathIndex < fieldIdPath.length) { 307 field = protocol_.readFieldBegin(); 308 // we can stop searching if we either see a stop or we go past the field 309 // id we're looking for (since fields should now be serialized in asc 310 // order). 311 if (field.type == TType.STOP || field.id > fieldIdPath[curPathIndex].getThriftFieldId()) { 312 return null; 313 } 314 315 if (field.id != fieldIdPath[curPathIndex].getThriftFieldId()) { 316 // Not the field we're looking for. Skip field. 317 TProtocolUtil.skip(protocol_, field.type); 318 protocol_.readFieldEnd(); 319 } else { 320 // This field is the next step in the path. Step into field. 321 curPathIndex++; 322 if (curPathIndex < fieldIdPath.length) { 323 protocol_.readStructBegin(); 324 } 325 } 326 } 327 return field; 328 } 329 330 /** 331 * Deserialize the Thrift object from a Java string, using the default JVM 332 * charset encoding. 333 * 334 * @param base The object to read into 335 * @param data The string to read from 336 */ fromString(TBase base, String data)337 public void fromString(TBase base, String data) throws TException { 338 deserialize(base, data.getBytes()); 339 } 340 } 341