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 * Licensed to the Apache Software Foundation (ASF) under one 21 * or more contributor license agreements. See the NOTICE file 22 * distributed with this work for additional information 23 * regarding copyright ownership. The ASF licenses this file 24 * to you under the Apache License, Version 2.0 (the 25 * "License"); you may not use this file except in compliance 26 * with the License. You may obtain a copy of the License at 27 * 28 * http://www.apache.org/licenses/LICENSE-2.0 29 * 30 * Unless required by applicable law or agreed to in writing, 31 * software distributed under the License is distributed on an 32 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 33 * KIND, either express or implied. See the License for the 34 * specific language governing permissions and limitations 35 * under the License. 36 */ 37 38 package org.apache.thrift.meta_data; 39 40 import org.apache.thrift.TBase; 41 42 import java.util.Hashtable; 43 44 45 /** 46 * This class is used to store meta data about thrift fields. Every field in a 47 * a struct should have a corresponding instance of this class describing it. 48 * 49 * The meta data is registered by ALL Thrift struct classes via a static {...} 50 * initializer block in the generated Thrift code. 51 * 52 * Since different threads could be initializing different Thrift classes, calls 53 * to the public static methods of this class could be racy. 54 * 55 * All methods of this class should be made thread safe. 56 */ 57 public class FieldMetaData { 58 public final String fieldName; 59 public final byte requirementType; 60 public final FieldValueMetaData valueMetaData; 61 private static final Hashtable structMap; 62 63 static { 64 structMap = new Hashtable(); 65 } 66 FieldMetaData(String name, byte req, FieldValueMetaData vMetaData)67 public FieldMetaData(String name, byte req, FieldValueMetaData vMetaData){ 68 this.fieldName = name; 69 this.requirementType = req; 70 this.valueMetaData = vMetaData; 71 } 72 addStructMetaDataMap(Class sClass, Hashtable map)73 public static void addStructMetaDataMap(Class sClass, Hashtable map){ 74 synchronized (structMap) { 75 structMap.put(sClass, map); 76 } 77 } 78 79 /** 80 * Returns a map with metadata (i.e. instances of FieldMetaData) that 81 * describe the fields of the given class. 82 * 83 * @param sClass The TBase class for which the metadata map is requested. It is not 84 * guaranteed that sClass will have been statically initialized before 85 * this method is called. A racy call to 86 * {@link FieldMetaData#addStructMetaDataMap(Class, Hashtable)} from a different 87 * thread during static initialization of the Thrift class is possible. 88 */ getStructMetaDataMap(Class sClass)89 public static Hashtable getStructMetaDataMap(Class sClass) { 90 // Note: Do not use synchronized on this method declaration - it leads to a deadlock. 91 // Similarly, do not trigger sClass.newInstance() while holding a lock on structMap, 92 // it will lead to the same deadlock. 93 // See: https://issues.apache.org/jira/browse/THRIFT-5430 for details. 94 boolean isThriftStructStaticallyInitialized = false; 95 synchronized (structMap) { 96 isThriftStructStaticallyInitialized = structMap.containsKey(sClass); 97 } 98 99 if (!isThriftStructStaticallyInitialized){ // Load class if it hasn't been loaded 100 try{ 101 sClass.newInstance(); 102 } catch (InstantiationException e){ 103 throw new RuntimeException("InstantiationException for TBase class: " + sClass.getName() + ", message: " + e.getMessage()); 104 } catch (IllegalAccessException e){ 105 throw new RuntimeException("IllegalAccessException for TBase class: " + sClass.getName() + ", message: " + e.getMessage()); 106 } 107 } 108 synchronized (structMap) { 109 return (Hashtable) structMap.get(sClass); 110 } 111 } 112 } 113