void generate_typedef (t_typedef* ttypedef);
void generate_enum (t_enum* tenum);
void generate_struct (t_struct* tstruct);
+ void generate_union (t_struct* tunion);
void generate_xception(t_struct* txception);
void generate_service (t_service* tservice);
void generate_service_server (t_service* tservice);
void generate_process_function (t_service* tservice, t_function* tfunction);
+ void generate_java_union(t_struct* tstruct);
+ void generate_union_constructor(ofstream& out, t_struct* tstruct);
+ void generate_union_getters_and_setters(ofstream& out, t_struct* tstruct);
+ void generate_union_abstract_methods(ofstream& out, t_struct* tstruct);
+ void generate_check_type(ofstream& out, t_struct* tstruct);
+ void generate_read_value(ofstream& out, t_struct* tstruct);
+ void generate_write_value(ofstream& out, t_struct* tstruct);
+ void generate_get_field_desc(ofstream& out, t_struct* tstruct);
+ void generate_get_struct_desc(ofstream& out, t_struct* tstruct);
+ void generate_get_field_name(ofstream& out, t_struct* tstruct);
+
+ void generate_union_comparisons(ofstream& out, t_struct* tstruct);
+ void generate_union_hashcode(ofstream& out, t_struct* tstruct);
+
/**
* Serialization constructs
*/
std::string java_package();
std::string java_type_imports();
std::string java_thrift_imports();
- std::string type_name(t_type* ttype, bool in_container=false, bool in_init=false);
+ std::string type_name(t_type* ttype, bool in_container=false, bool in_init=false, bool skip_generic=false);
std::string base_type_name(t_base_type* tbase, bool in_container=false);
std::string declare_field(t_field* tfield, bool init=false);
std::string function_signature(t_function* tfunction, std::string prefix="");
std::string argument_list(t_struct* tstruct);
std::string type_to_enum(t_type* ttype);
std::string get_enum_class_name(t_type* type);
-
+ void generate_struct_desc(ofstream& out, t_struct* tstruct);
+ void generate_field_descs(ofstream& out, t_struct* tstruct);
+ void generate_field_name_constants(ofstream& out, t_struct* tstruct);
+
bool type_can_be_null(t_type* ttype) {
ttype = get_true_type(ttype);
"import java.util.HashSet;\n" +
"import java.util.Collections;\n" +
"import java.util.BitSet;\n" +
+ "import java.util.Arrays;\n" +
"import org.slf4j.Logger;\n" +
"import org.slf4j.LoggerFactory;\n\n";
}
}
/**
- * Generates a struct definition for a thrift data type. This is a class
- * with data members, read(), write(), and an inner Isset class.
+ * Generates a struct definition for a thrift data type. This will be a TBase
+ * implementor.
*
* @param tstruct The struct definition
*/
void t_java_generator::generate_struct(t_struct* tstruct) {
- generate_java_struct(tstruct, false);
+ if (tstruct->is_union()) {
+ generate_java_union(tstruct);
+ } else {
+ generate_java_struct(tstruct, false);
+ }
}
/**
f_struct.close();
}
+/**
+ * Java union definition.
+ *
+ * @param tstruct The struct definition
+ */
+void t_java_generator::generate_java_union(t_struct* tstruct) {
+ // Make output file
+ string f_struct_name = package_dir_+"/"+(tstruct->get_name())+".java";
+ ofstream f_struct;
+ f_struct.open(f_struct_name.c_str());
+
+ f_struct <<
+ autogen_comment() <<
+ java_package() <<
+ java_type_imports() <<
+ java_thrift_imports();
+
+ generate_java_doc(f_struct, tstruct);
+
+ bool is_final = (tstruct->annotations_.find("final") != tstruct->annotations_.end());
+
+ indent(f_struct) <<
+ "public " << (is_final ? "final " : "") << "class " << tstruct->get_name()
+ << " extends TUnion ";
+
+ if (is_comparable(tstruct)) {
+ f_struct << "implements Comparable<" << type_name(tstruct) << "> ";
+ }
+
+ scope_up(f_struct);
+
+ generate_struct_desc(f_struct, tstruct);
+ generate_field_descs(f_struct, tstruct);
+
+ f_struct << endl;
+
+ generate_field_name_constants(f_struct, tstruct);
+
+ f_struct << endl;
+
+ generate_java_meta_data_map(f_struct, tstruct);
+
+ generate_union_constructor(f_struct, tstruct);
+
+ f_struct << endl;
+
+ generate_union_abstract_methods(f_struct, tstruct);
+
+ f_struct << endl;
+
+ generate_union_getters_and_setters(f_struct, tstruct);
+
+ f_struct << endl;
+
+ generate_union_comparisons(f_struct, tstruct);
+
+ f_struct << endl;
+
+ generate_union_hashcode(f_struct, tstruct);
+
+ f_struct << endl;
+
+ scope_down(f_struct);
+
+ f_struct.close();
+}
+
+void t_java_generator::generate_union_constructor(ofstream& out, t_struct* tstruct) {
+ indent(out) << "public " << type_name(tstruct) << "() {" << endl;
+ indent(out) << " super();" << endl;
+ indent(out) << "}" << endl << endl;
+
+ indent(out) << "public " << type_name(tstruct) << "(int setField, Object value) {" << endl;
+ indent(out) << " super(setField, value);" << endl;
+ indent(out) << "}" << endl << endl;
+
+ indent(out) << "public " << type_name(tstruct) << "(" << type_name(tstruct) << " other) {" << endl;
+ indent(out) << " super(other);" << endl;
+ indent(out) << "}" << endl;
+
+ indent(out) << "public " << tstruct->get_name() << " deepCopy() {" << endl;
+ indent(out) << " return new " << tstruct->get_name() << "(this);" << endl;
+ indent(out) << "}" << endl << endl;
+
+ // generate "constructors" for each field
+ const vector<t_field*>& members = tstruct->get_members();
+ vector<t_field*>::const_iterator m_iter;
+ for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+ indent(out) << "public static " << type_name(tstruct) << " " << (*m_iter)->get_name() << "(" << type_name((*m_iter)->get_type()) << " value) {" << endl;
+ indent(out) << " " << type_name(tstruct) << " x = new " << type_name(tstruct) << "();" << endl;
+ indent(out) << " x.set" << get_cap_name((*m_iter)->get_name()) << "(value);" << endl;
+ indent(out) << " return x;" << endl;
+ indent(out) << "}" << endl << endl;
+ }
+}
+
+void t_java_generator::generate_union_getters_and_setters(ofstream& out, t_struct* tstruct) {
+ const vector<t_field*>& members = tstruct->get_members();
+ vector<t_field*>::const_iterator m_iter;
+
+ bool first = true;
+ for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+ if (first) {
+ first = false;
+ } else {
+ out << endl;
+ }
+
+ t_field* field = (*m_iter);
+
+ generate_java_doc(out, field);
+ indent(out) << "public " << type_name(field->get_type()) << " get" << get_cap_name(field->get_name()) << "() {" << endl;
+ indent(out) << " if (getSetField() == " << upcase_string(field->get_name()) << ") {" << endl;
+ indent(out) << " return (" << type_name(field->get_type(), true) << ")getFieldValue();" << endl;
+ indent(out) << " } else {" << endl;
+ indent(out) << " throw new RuntimeException(\"Cannot get field '" << field->get_name()
+ << "' because union is currently set to \" + getFieldDesc(getSetField()).name);" << endl;
+ indent(out) << " }" << endl;
+ indent(out) << "}" << endl;
+
+ out << endl;
+
+ generate_java_doc(out, field);
+ indent(out) << "public void set" << get_cap_name(field->get_name()) << "(" << type_name(field->get_type()) << " value) {" << endl;
+ if (type_can_be_null(field->get_type())) {
+ indent(out) << " if (value == null) throw new NullPointerException();" << endl;
+ }
+ indent(out) << " setField_ = " << upcase_string(field->get_name()) << ";" << endl;
+ indent(out) << " value_ = value;" << endl;
+ indent(out) << "}" << endl;
+ }
+}
+
+void t_java_generator::generate_union_abstract_methods(ofstream& out, t_struct* tstruct) {
+ generate_check_type(out, tstruct);
+ out << endl;
+ generate_read_value(out, tstruct);
+ out << endl;
+ generate_write_value(out, tstruct);
+ out << endl;
+ generate_get_field_desc(out, tstruct);
+ out << endl;
+ generate_get_struct_desc(out, tstruct);
+}
+
+void t_java_generator::generate_check_type(ofstream& out, t_struct* tstruct) {
+ indent(out) << "@Override" << endl;
+ indent(out) << "protected void checkType(short setField, Object value) throws ClassCastException {" << endl;
+ indent_up();
+
+ indent(out) << "switch (setField) {" << endl;
+ indent_up();
+
+ const vector<t_field*>& members = tstruct->get_members();
+ vector<t_field*>::const_iterator m_iter;
+
+ for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+ t_field* field = (*m_iter);
+
+ indent(out) << "case " << upcase_string(field->get_name()) << ":" << endl;
+ indent(out) << " if (value instanceof " << type_name(field->get_type(), true, false, true) << ") {" << endl;
+ indent(out) << " break;" << endl;
+ indent(out) << " }" << endl;
+ indent(out) << " throw new ClassCastException(\"Was expecting value of type "
+ << type_name(field->get_type(), true, false) << " for field '" << field->get_name()
+ << "', but got \" + value.getClass().getSimpleName());" << endl;
+ // do the real check here
+ }
+
+ indent(out) << "default:" << endl;
+ indent(out) << " throw new IllegalArgumentException(\"Unknown field id \" + setField);" << endl;
+
+ indent_down();
+ indent(out) << "}" << endl;
+
+ indent_down();
+ indent(out) << "}" << endl;
+}
+
+void t_java_generator::generate_read_value(ofstream& out, t_struct* tstruct) {
+ indent(out) << "@Override" << endl;
+ indent(out) << "protected Object readValue(TProtocol iprot, TField field) throws TException {" << endl;
+
+ indent_up();
+
+ indent(out) << "switch (field.id) {" << endl;
+ indent_up();
+
+ const vector<t_field*>& members = tstruct->get_members();
+ vector<t_field*>::const_iterator m_iter;
+
+ for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+ t_field* field = (*m_iter);
+
+ indent(out) << "case " << upcase_string(field->get_name()) << ":" << endl;
+ indent_up();
+ indent(out) << "if (field.type == " << upcase_string(field->get_name()) << "_FIELD_DESC.type) {" << endl;
+ indent_up();
+ indent(out) << type_name(field->get_type(), true, false) << " " << field->get_name() << ";" << endl;
+ generate_deserialize_field(out, field, "");
+ indent(out) << "return " << field->get_name() << ";" << endl;
+ indent_down();
+ indent(out) << "} else {" << endl;
+ indent(out) << " TProtocolUtil.skip(iprot, field.type);" << endl;
+ indent(out) << " return null;" << endl;
+ indent(out) << "}" << endl;
+ indent_down();
+ }
+
+ indent(out) << "default:" << endl;
+ indent(out) << " TProtocolUtil.skip(iprot, field.type);" << endl;
+ indent(out) << " return null;" << endl;
+
+ indent_down();
+ indent(out) << "}" << endl;
+
+ indent_down();
+ indent(out) << "}" << endl;
+}
+
+void t_java_generator::generate_write_value(ofstream& out, t_struct* tstruct) {
+ indent(out) << "@Override" << endl;
+ indent(out) << "protected void writeValue(TProtocol oprot, short setField, Object value) throws TException {" << endl;
+
+ indent_up();
+
+ indent(out) << "switch (setField) {" << endl;
+ indent_up();
+
+ const vector<t_field*>& members = tstruct->get_members();
+ vector<t_field*>::const_iterator m_iter;
+
+ for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+ t_field* field = (*m_iter);
+
+ indent(out) << "case " << upcase_string(field->get_name()) << ":" << endl;
+ indent_up();
+ indent(out) << type_name(field->get_type(), true, false) << " " << field->get_name()
+ << " = (" << type_name(field->get_type(), true, false) << ")getFieldValue();" << endl;
+ generate_serialize_field(out, field, "");
+ indent(out) << "return;" << endl;
+ indent_down();
+ }
+
+ indent(out) << "default:" << endl;
+ indent(out) << " throw new IllegalStateException(\"Cannot write union with unknown field \" + setField);" << endl;
+
+ indent_down();
+ indent(out) << "}" << endl;
+
+ indent_down();
+
+
+
+ indent(out) << "}" << endl;
+}
+
+void t_java_generator::generate_get_field_desc(ofstream& out, t_struct* tstruct) {
+ indent(out) << "@Override" << endl;
+ indent(out) << "protected TField getFieldDesc(int setField) {" << endl;
+ indent_up();
+
+ const vector<t_field*>& members = tstruct->get_members();
+ vector<t_field*>::const_iterator m_iter;
+
+ indent(out) << "switch (setField) {" << endl;
+ indent_up();
+
+ for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+ t_field* field = (*m_iter);
+ indent(out) << "case " << upcase_string(field->get_name()) << ":" << endl;
+ indent(out) << " return " << upcase_string(field->get_name()) << "_FIELD_DESC;" << endl;
+ }
+
+ indent(out) << "default:" << endl;
+ indent(out) << " throw new IllegalArgumentException(\"Unknown field id \" + setField);" << endl;
+
+ indent_down();
+ indent(out) << "}" << endl;
+
+ indent_down();
+ indent(out) << "}" << endl;
+}
+
+void t_java_generator::generate_get_struct_desc(ofstream& out, t_struct* tstruct) {
+ indent(out) << "@Override" << endl;
+ indent(out) << "protected TStruct getStructDesc() {" << endl;
+ indent(out) << " return STRUCT_DESC;" << endl;
+ indent(out) << "}" << endl;
+}
+
+void t_java_generator::generate_union_comparisons(ofstream& out, t_struct* tstruct) {
+ // equality
+ indent(out) << "public boolean equals(Object other) {" << endl;
+ indent(out) << " if (other instanceof " << tstruct->get_name() << ") {" << endl;
+ indent(out) << " return equals((" << tstruct->get_name() << ")other);" << endl;
+ indent(out) << " } else {" << endl;
+ indent(out) << " return false;" << endl;
+ indent(out) << " }" << endl;
+ indent(out) << "}" << endl;
+
+ out << endl;
+
+ indent(out) << "public boolean equals(" << tstruct->get_name() << " other) {" << endl;
+ indent(out) << " return getSetField() == other.getSetField() && ((value_ instanceof byte[]) ? " << endl;
+ indent(out) << " Arrays.equals((byte[])getFieldValue(), (byte[])other.getFieldValue()) : getFieldValue().equals(other.getFieldValue()));" << endl;
+ indent(out) << "}" << endl;
+ out << endl;
+
+ if (is_comparable(tstruct)) {
+ indent(out) << "@Override" << endl;
+ indent(out) << "public int compareTo(" << type_name(tstruct) << " other) {" << endl;
+ indent(out) << " int lastComparison = TBaseHelper.compareTo(getSetField(), other.getSetField());" << endl;
+ indent(out) << " if (lastComparison != 0) {" << endl;
+ indent(out) << " return TBaseHelper.compareTo((Comparable)getFieldValue(), (Comparable)other.getFieldValue());" << endl;
+ indent(out) << " }" << endl;
+ indent(out) << " return lastComparison;" << endl;
+ indent(out) << "}" << endl;
+ out << endl;
+ }
+}
+
+void t_java_generator::generate_union_hashcode(ofstream& out, t_struct* tstruct) {
+ if (gen_hash_code_) {
+ indent(out) << "@Override" << endl;
+ indent(out) << "public int hashCode() {" << endl;
+ indent(out) << " return new HashCodeBuilder().append(getSetField()).append(getFieldValue()).toHashCode();" << endl;
+ indent(out) << "}";
+ } else {
+ indent(out) << "/**" << endl;
+ indent(out) << " * If you'd like this to perform more respectably, use the hashcode generator option." << endl;
+ indent(out) << " */" << endl;
+ indent(out) << "@Override" << endl;
+ indent(out) << "public int hashCode() {" << endl;
+ indent(out) << " return 0;" << endl;
+ indent(out) << "}" << endl;
+ }
+}
+
/**
* Java struct definition. This has various parameters, as it could be
* generated standalone or inside another class as a helper. If it
scope_up(out);
- indent(out) <<
- "private static final TStruct STRUCT_DESC = new TStruct(\"" << tstruct->get_name() << "\");" << endl;
+ generate_struct_desc(out, tstruct);
// Members are public for -java, private for -javabean
const vector<t_field*>& members = tstruct->get_members();
vector<t_field*>::const_iterator m_iter;
- for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
- indent(out) <<
- "private static final TField " << constant_name((*m_iter)->get_name()) <<
- "_FIELD_DESC = new TField(\"" << (*m_iter)->get_name() << "\", " <<
- type_to_enum((*m_iter)->get_type()) << ", " <<
- "(short)" << (*m_iter)->get_key() << ");" << endl;
- }
-
+ generate_field_descs(out, tstruct);
+
out << endl;
for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
indent(out) << "public ";
}
out << declare_field(*m_iter, false) << endl;
-
- indent(out) << "public static final int " << upcase_string((*m_iter)->get_name()) << " = " << (*m_iter)->get_key() << ";" << endl;
}
+
+ generate_field_name_constants(out, tstruct);
// isset data
if (members.size() > 0) {
}
generate_java_meta_data_map(out, tstruct);
-
- // Static initializer to populate global class to struct metadata map
- indent(out) << "static {" << endl;
- indent_up();
- indent(out) << "FieldMetaData.addStructMetaDataMap(" << type_name(tstruct) << ".class, metaDataMap);" << endl;
- indent_down();
- indent(out) << "}" << endl << endl;
// Default constructor
indent(out) <<
indent(out) << "}" << endl << endl;
// clone method, so that you can deep copy an object when you don't know its class.
- indent(out) << "@Override" << endl;
+ indent(out) << "public " << tstruct->get_name() << " deepCopy() {" << endl;
+ indent(out) << " return new " << tstruct->get_name() << "(this);" << endl;
+ indent(out) << "}" << endl << endl;
+
+ indent(out) << "@Deprecated" << endl;
indent(out) << "public " << tstruct->get_name() << " clone() {" << endl;
indent(out) << " return new " << tstruct->get_name() << "(this);" << endl;
indent(out) << "}" << endl << endl;
}
indent_down();
indent(out) << "}});" << endl << endl;
+
+ // Static initializer to populate global class to struct metadata map
+ indent(out) << "static {" << endl;
+ indent_up();
+ indent(out) << "FieldMetaData.addStructMetaDataMap(" << type_name(tstruct) << ".class, metaDataMap);" << endl;
+ indent_down();
+ indent(out) << "}" << endl << endl;
}
/**
* @param container Is the type going inside a container?
* @return Java type name, i.e. HashMap<Key,Value>
*/
-string t_java_generator::type_name(t_type* ttype, bool in_container, bool in_init) {
+string t_java_generator::type_name(t_type* ttype, bool in_container, bool in_init, bool skip_generic) {
// In Java typedefs are just resolved to their real type
ttype = get_true_type(ttype);
string prefix;
} else {
prefix = "Map";
}
- return prefix + "<" +
+ return prefix + (skip_generic ? "" : "<" +
type_name(tmap->get_key_type(), true) + "," +
- type_name(tmap->get_val_type(), true) + ">";
+ type_name(tmap->get_val_type(), true) + ">");
} else if (ttype->is_set()) {
t_set* tset = (t_set*) ttype;
if (in_init) {
- prefix = "HashSet<";
+ prefix = "HashSet";
} else {
- prefix = "Set<";
+ prefix = "Set";
}
- return prefix + type_name(tset->get_elem_type(), true) + ">";
+ return prefix + (skip_generic ? "" : "<" + type_name(tset->get_elem_type(), true) + ">");
} else if (ttype->is_list()) {
t_list* tlist = (t_list*) ttype;
if (in_init) {
- prefix = "ArrayList<";
+ prefix = "ArrayList";
} else {
- prefix = "List<";
+ prefix = "List";
}
- return prefix + type_name(tlist->get_elem_type(), true) + ">";
+ return prefix + (skip_generic ? "" : "<" + type_name(tlist->get_elem_type(), true) + ">");
}
// Check for namespacing
return package + type->get_name();
}
+void t_java_generator::generate_struct_desc(ofstream& out, t_struct* tstruct) {
+ indent(out) <<
+ "private static final TStruct STRUCT_DESC = new TStruct(\"" << tstruct->get_name() << "\");" << endl;
+}
+
+void t_java_generator::generate_field_descs(ofstream& out, t_struct* tstruct) {
+ const vector<t_field*>& members = tstruct->get_members();
+ vector<t_field*>::const_iterator m_iter;
+
+ for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+ indent(out) <<
+ "private static final TField " << constant_name((*m_iter)->get_name()) <<
+ "_FIELD_DESC = new TField(\"" << (*m_iter)->get_name() << "\", " <<
+ type_to_enum((*m_iter)->get_type()) << ", " <<
+ "(short)" << (*m_iter)->get_key() << ");" << endl;
+ }
+}
+
+void t_java_generator::generate_field_name_constants(ofstream& out, t_struct* tstruct) {
+ // Members are public for -java, private for -javabean
+ const vector<t_field*>& members = tstruct->get_members();
+ vector<t_field*>::const_iterator m_iter;
+
+ for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+ indent(out) << "public static final int " << upcase_string((*m_iter)->get_name()) << " = " << (*m_iter)->get_key() << ";" << endl;
+ }
+}
+
bool t_java_generator::is_comparable(t_struct* tstruct) {
const vector<t_field*>& members = tstruct->get_members();
vector<t_field*>::const_iterator m_iter;
" nocamel: Do not use CamelCase field accessors with beans.\n"
" hashcode: Generate quality hashCode methods.\n"
);
+
--- /dev/null
+package org.apache.thrift;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.thrift.protocol.TField;
+import org.apache.thrift.protocol.TProtocol;
+import org.apache.thrift.protocol.TProtocolException;
+import org.apache.thrift.protocol.TStruct;
+
+public abstract class TUnion implements TBase {
+
+ protected Object value_;
+ protected int setField_;
+
+ protected TUnion() {
+ setField_ = 0;
+ value_ = null;
+ }
+
+ protected TUnion(int setField, Object value) {
+ setFieldValue(setField, value);
+ }
+
+ protected TUnion(TUnion other) {
+ if (!other.getClass().equals(this.getClass())) {
+ throw new ClassCastException();
+ }
+ setField_ = other.setField_;
+ value_ = deepCopyObject(other.value_);
+ }
+
+ private static Object deepCopyObject(Object o) {
+ if (o instanceof TBase) {
+ return ((TBase)o).deepCopy();
+ } else if (o instanceof byte[]) {
+ byte[] other_val = (byte[])o;
+ byte[] this_val = new byte[other_val.length];
+ System.arraycopy(other_val, 0, this_val, 0, other_val.length);
+ return this_val;
+ } else if (o instanceof List) {
+ return deepCopyList((List)o);
+ } else if (o instanceof Set) {
+ return deepCopySet((Set)o);
+ } else if (o instanceof Map) {
+ return deepCopyMap((Map)o);
+ } else {
+ return o;
+ }
+ }
+
+ private static Map deepCopyMap(Map<Object, Object> map) {
+ Map copy = new HashMap();
+ for (Map.Entry<Object, Object> entry : map.entrySet()) {
+ copy.put(deepCopyObject(entry.getKey()), deepCopyObject(entry.getValue()));
+ }
+ return copy;
+ }
+
+ private static Set deepCopySet(Set set) {
+ Set copy = new HashSet();
+ for (Object o : set) {
+ copy.add(deepCopyObject(o));
+ }
+ return copy;
+ }
+
+ private static List deepCopyList(List list) {
+ List copy = new ArrayList(list.size());
+ for (Object o : list) {
+ copy.add(deepCopyObject(o));
+ }
+ return copy;
+ }
+
+ public int getSetField() {
+ return setField_;
+ }
+
+ public Object getFieldValue() {
+ return value_;
+ }
+
+ public Object getFieldValue(int fieldId) {
+ if (fieldId != setField_) {
+ throw new IllegalArgumentException("Cannot get the value of field " + fieldId + " because union's set field is " + setField_);
+ }
+
+ return getFieldValue();
+ }
+
+ public boolean isSet() {
+ return setField_ != 0;
+ }
+
+ public boolean isSet(int fieldId) {
+ return setField_ == fieldId;
+ }
+
+ public void read(TProtocol iprot) throws TException {
+ setField_ = 0;
+ value_ = null;
+
+ iprot.readStructBegin();
+
+ TField field = iprot.readFieldBegin();
+
+ value_ = readValue(iprot, field);
+ if (value_ != null) {
+ setField_ = field.id;
+ }
+
+ iprot.readFieldEnd();
+ // this is so that we will eat the stop byte. we could put a check here to
+ // make sure that it actually *is* the stop byte, but it's faster to do it
+ // this way.
+ iprot.readFieldBegin();
+ iprot.readStructEnd();
+ }
+
+ public void setFieldValue(int fieldId, Object value) {
+ checkType((short)fieldId, value);
+ setField_ = (short)fieldId;
+ value_ = value;
+ }
+
+ public void write(TProtocol oprot) throws TException {
+ if (getSetField() == 0 || getFieldValue() == null) {
+ throw new TProtocolException("Cannot write a TUnion with no set value!");
+ }
+ oprot.writeStructBegin(getStructDesc());
+ oprot.writeFieldBegin(getFieldDesc(setField_));
+ writeValue(oprot, (short)setField_, value_);
+ oprot.writeFieldEnd();
+ oprot.writeFieldStop();
+ oprot.writeStructEnd();
+ }
+
+ /**
+ * Implementation should be generated so that we can efficiently type check
+ * various values.
+ * @param setField
+ * @param value
+ */
+ protected abstract void checkType(short setField, Object value) throws ClassCastException;
+
+ /**
+ * Implementation should be generated to read the right stuff from the wire
+ * based on the field header.
+ * @param field
+ * @return
+ */
+ protected abstract Object readValue(TProtocol iprot, TField field) throws TException;
+
+ protected abstract void writeValue(TProtocol oprot, short setField, Object value) throws TException;
+
+ protected abstract TStruct getStructDesc();
+
+ protected abstract TField getFieldDesc(int setField);
+
+ @Override
+ public String toString() {
+ Object v = getFieldValue();
+ String vStr = null;
+ if (v instanceof byte[]) {
+ vStr = bytesToStr((byte[])v);
+ } else {
+ vStr = v.toString();
+ }
+ return "<" + this.getClass().getSimpleName() + " " + getFieldDesc(getSetField()).name + ":" + vStr + ">";
+ }
+
+ private static String bytesToStr(byte[] bytes) {
+ StringBuilder sb = new StringBuilder();
+ int size = Math.min(bytes.length, 128);
+ for (int i = 0; i < size; i++) {
+ if (i != 0) {
+ sb.append(" ");
+ }
+ String digit = Integer.toHexString(bytes[i]);
+ sb.append(digit.length() > 1 ? digit : "0" + digit);
+ }
+ if (bytes.length > 128) {
+ sb.append(" ...");
+ }
+ return sb.toString();
+ }
+}