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  * Contains some contributions under the Thrift Software License.
20  * Please see doc/old-thrift-license.txt in the Thrift distribution for
21  * details.
22  */
23 
24 #include <fstream>
25 #include <iostream>
26 #include <sstream>
27 #include <limits>
28 
29 #include <stdlib.h>
30 #include <sys/stat.h>
31 #include <sstream>
32 
33 #include "thrift/platform.h"
34 #include "thrift/generate/t_generator.h"
35 
36 using std::map;
37 using std::ofstream;
38 using std::ostream;
39 using std::ostringstream;
40 using std::string;
41 using std::stringstream;
42 using std::vector;
43 using std::stack;
44 
45 static const string endl = "\n";
46 static const string quot = "\"";
47 static const bool NO_INDENT = false;
48 static const bool FORCE_STRING = true;
49 
50 class t_json_generator : public t_generator {
51 public:
t_json_generator(t_program * program,const std::map<std::string,std::string> & parsed_options,const std::string & option_string)52   t_json_generator(t_program* program,
53                    const std::map<std::string, std::string>& parsed_options,
54                    const std::string& option_string)
55     : t_generator(program) {
56     (void)option_string;
57     std::map<std::string, std::string>::const_iterator iter;
58 
59     should_merge_includes_ = false;
60     for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) {
61       if( iter->first.compare("merge") == 0) {
62         should_merge_includes_ = true;
63       } else {
64         throw "unknown option json:" + iter->first;
65       }
66     }
67 
68     out_dir_base_ = "gen-json";
69   }
70 
~t_json_generator()71   virtual ~t_json_generator() {}
72 
73   /**
74   * Init and close methods
75   */
76 
77   void init_generator();
78   void close_generator();
79 
80   void generate_typedef(t_typedef* ttypedef);
81   void generate_enum(t_enum* tenum);
82   void generate_program();
83   void generate_function(t_function* tfunc);
84   void generate_field(t_field* field);
85 
86   void generate_service(t_service* tservice);
87   void generate_struct(t_struct* tstruct);
88 
89 private:
90   bool should_merge_includes_;
91 
92   ofstream_with_content_based_conditional_update f_json_;
93   std::stack<bool> comma_needed_;
94 
95   template <typename T>
number_to_string(T t)96   string number_to_string(T t) {
97     std::ostringstream out;
98     out.imbue(std::locale::classic());
99     out.precision(std::numeric_limits<T>::digits10);
100     out << t;
101     return out.str();
102   }
103 
104   template <typename T>
write_number(T n)105   void write_number(T n) {
106     f_json_ << number_to_string(n);
107   }
108 
109   string get_type_name(t_type* ttype);
110   string get_qualified_name(t_type* ttype);
111 
112   void start_object(bool should_indent = true);
113   void start_array();
114   void end_object();
115   void end_array();
116   void write_comma_if_needed();
117   void indicate_comma_needed();
118   string escape_json_string(const string& input);
119   string json_str(const string& str);
120   void merge_includes(t_program*);
121 
122   void generate_constant(t_const* con);
123 
124   void write_type_spec_entry(const char* name, t_type* ttype);
125   void write_type_spec_object(const char* name, t_type* ttype);
126   void write_type_spec(t_type* ttype);
127   void write_string(const string& value);
128   void write_value(t_type* tvalue);
129   void write_const_value(t_const_value* value, bool force_string = false);
130   void write_key_and(string key);
131   void write_key_and_string(string key, string val);
132   void write_key_and_integer(string key, int val);
133   void write_key_and_bool(string key, bool val);
134 };
135 
init_generator()136 void t_json_generator::init_generator() {
137   MKDIR(get_out_dir().c_str());
138 
139   string f_json_name = get_out_dir() + program_->get_name() + ".json";
140   f_json_.open(f_json_name.c_str());
141 
142   // Merge all included programs into this one so we can output one big file.
143   if (should_merge_includes_) {
144     merge_includes(program_);
145   }
146 }
147 
escape_json_string(const string & input)148 string t_json_generator::escape_json_string(const string& input) {
149   std::ostringstream ss;
150   for (std::string::const_iterator iter = input.begin(); iter != input.end(); iter++) {
151     switch (*iter) {
152     case '\\':
153       ss << "\\\\";
154       break;
155     case '"':
156       ss << "\\\"";
157       break;
158     case '/':
159       ss << "\\/";
160       break;
161     case '\b':
162       ss << "\\b";
163       break;
164     case '\f':
165       ss << "\\f";
166       break;
167     case '\n':
168       ss << "\\n";
169       break;
170     case '\r':
171       ss << "\\r";
172       break;
173     case '\t':
174       ss << "\\t";
175       break;
176     default:
177       ss << *iter;
178       break;
179     }
180   }
181   return ss.str();
182 }
183 
start_object(bool should_indent)184 void t_json_generator::start_object(bool should_indent) {
185   f_json_ << (should_indent ? indent() : "") << "{" << endl;
186   indent_up();
187   comma_needed_.push(false);
188 }
189 
start_array()190 void t_json_generator::start_array() {
191   f_json_ << "[" << endl;
192   indent_up();
193   comma_needed_.push(false);
194 }
195 
write_comma_if_needed()196 void t_json_generator::write_comma_if_needed() {
197   if (comma_needed_.top()) {
198     f_json_ << "," << endl;
199   }
200 }
201 
indicate_comma_needed()202 void t_json_generator::indicate_comma_needed() {
203   comma_needed_.pop();
204   comma_needed_.push(true);
205 }
206 
write_key_and(string key)207 void t_json_generator::write_key_and(string key) {
208   write_comma_if_needed();
209   indent(f_json_) << json_str(key) << ": ";
210   indicate_comma_needed();
211 }
212 
write_key_and_integer(string key,int val)213 void t_json_generator::write_key_and_integer(string key, int val) {
214   write_comma_if_needed();
215   indent(f_json_) << json_str(key) << ": " << number_to_string(val);
216   indicate_comma_needed();
217 }
218 
write_key_and_string(string key,string val)219 void t_json_generator::write_key_and_string(string key, string val) {
220   write_comma_if_needed();
221   indent(f_json_) << json_str(key) << ": " << json_str(val);
222   indicate_comma_needed();
223 }
224 
write_key_and_bool(string key,bool val)225 void t_json_generator::write_key_and_bool(string key, bool val) {
226   write_comma_if_needed();
227   indent(f_json_) << json_str(key) << ": " << (val ? "true" : "false");
228   indicate_comma_needed();
229 }
230 
end_object()231 void t_json_generator::end_object() {
232   indent_down();
233   f_json_ << endl << indent() << "}";
234   comma_needed_.pop();
235 }
236 
end_array()237 void t_json_generator::end_array() {
238   indent_down();
239   if (comma_needed_.top()) {
240     f_json_ << endl;
241   }
242   indent(f_json_) << "]";
243   comma_needed_.pop();
244 }
245 
write_type_spec_object(const char * name,t_type * ttype)246 void t_json_generator::write_type_spec_object(const char* name, t_type* ttype) {
247   ttype = ttype->get_true_type();
248   if (ttype->is_struct() || ttype->is_xception() || ttype->is_container()) {
249     write_key_and(name);
250     start_object(NO_INDENT);
251     write_key_and("typeId");
252     write_type_spec(ttype);
253     end_object();
254   }
255 }
256 
write_type_spec_entry(const char * name,t_type * ttype)257 void t_json_generator::write_type_spec_entry(const char* name, t_type* ttype) {
258   write_key_and(name);
259   write_type_spec(ttype);
260 }
261 
write_type_spec(t_type * ttype)262 void t_json_generator::write_type_spec(t_type* ttype) {
263   ttype = ttype->get_true_type();
264 
265   write_string(get_type_name(ttype));
266 
267   if (ttype->annotations_.size() > 0) {
268     write_key_and("annotations");
269     start_object();
270     for (map<string, string>::iterator it = ttype->annotations_.begin(); it != ttype->annotations_.end(); ++it) {
271       write_key_and_string(it->first, it->second);
272     }
273     end_object();
274   }
275 
276   if (ttype->is_struct() || ttype->is_xception()) {
277     write_key_and_string("class", get_qualified_name(ttype));
278   } else if (ttype->is_map()) {
279     t_type* ktype = ((t_map*)ttype)->get_key_type();
280     t_type* vtype = ((t_map*)ttype)->get_val_type();
281     write_key_and_string("keyTypeId", get_type_name(ktype));
282     write_key_and_string("valueTypeId", get_type_name(vtype));
283     write_type_spec_object("keyType", ktype);
284     write_type_spec_object("valueType", vtype);
285   } else if (ttype->is_list()) {
286     t_type* etype = ((t_list*)ttype)->get_elem_type();
287     write_key_and_string("elemTypeId", get_type_name(etype));
288     write_type_spec_object("elemType", etype);
289   } else if (ttype->is_set()) {
290     t_type* etype = ((t_set*)ttype)->get_elem_type();
291     write_key_and_string("elemTypeId", get_type_name(etype));
292     write_type_spec_object("elemType", etype);
293   }
294 }
295 
close_generator()296 void t_json_generator::close_generator() {
297   f_json_ << endl;
298   f_json_.close();
299 }
300 
merge_includes(t_program * program)301 void t_json_generator::merge_includes(t_program* program) {
302   vector<t_program*> includes = program->get_includes();
303   vector<t_program*>::iterator inc_iter;
304   for (inc_iter = includes.begin(); inc_iter != includes.end(); ++inc_iter) {
305     t_program* include = *inc_iter;
306     // recurse in case we get crazy
307     merge_includes(include);
308     // merge enums
309     vector<t_enum*> enums = include->get_enums();
310     vector<t_enum*>::iterator en_iter;
311     for (en_iter = enums.begin(); en_iter != enums.end(); ++en_iter) {
312       program->add_enum(*en_iter);
313     }
314     // merge typedefs
315     vector<t_typedef*> typedefs = include->get_typedefs();
316     vector<t_typedef*>::iterator td_iter;
317     for (td_iter = typedefs.begin(); td_iter != typedefs.end(); ++td_iter) {
318       program->add_typedef(*td_iter);
319     }
320     // merge structs
321     vector<t_struct*> objects = include->get_objects();
322     vector<t_struct*>::iterator o_iter;
323     for (o_iter = objects.begin(); o_iter != objects.end(); ++o_iter) {
324       program->add_struct(*o_iter);
325     }
326     // merge constants
327     vector<t_const*> consts = include->get_consts();
328     vector<t_const*>::iterator c_iter;
329     for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
330       program->add_const(*c_iter);
331     }
332 
333     // merge services
334     vector<t_service*> services = include->get_services();
335     vector<t_service*>::iterator sv_iter;
336     for (sv_iter = services.begin(); sv_iter != services.end(); ++sv_iter) {
337       program->add_service(*sv_iter);
338     }
339   }
340 }
341 
generate_program()342 void t_json_generator::generate_program() {
343 
344   init_generator();
345 
346   start_object();
347   write_key_and_string("name", program_->get_name());
348   if (program_->has_doc()) {
349     write_key_and_string("doc", program_->get_doc());
350   }
351 
352   // When merging includes, the "namespaces" and "includes" sections
353   // become ambiguous, so just skip them.
354   if (!should_merge_includes_) {
355     // Generate namespaces
356     write_key_and("namespaces");
357     start_object(NO_INDENT);
358     const map<string, string>& namespaces = program_->get_namespaces();
359     map<string, string>::const_iterator ns_it;
360     for (ns_it = namespaces.begin(); ns_it != namespaces.end(); ++ns_it) {
361       write_key_and_string(ns_it->first, ns_it->second);
362       indicate_comma_needed();
363     }
364     end_object();
365 
366     // Generate includes
367     write_key_and("includes");
368     start_array();
369     const vector<t_program*> includes = program_->get_includes();
370     vector<t_program*>::const_iterator inc_it;
371     for (inc_it = includes.begin(); inc_it != includes.end(); ++inc_it) {
372       write_comma_if_needed();
373       write_string((*inc_it)->get_name());
374       indicate_comma_needed();
375     }
376     end_array();
377   }
378 
379   // Generate enums
380   write_key_and("enums");
381   start_array();
382   vector<t_enum*> enums = program_->get_enums();
383   vector<t_enum*>::iterator en_iter;
384   for (en_iter = enums.begin(); en_iter != enums.end(); ++en_iter) {
385     write_comma_if_needed();
386     generate_enum(*en_iter);
387     indicate_comma_needed();
388   }
389   end_array();
390 
391   // Generate typedefs
392   write_key_and("typedefs");
393   start_array();
394   vector<t_typedef*> typedefs = program_->get_typedefs();
395   vector<t_typedef*>::iterator td_iter;
396   for (td_iter = typedefs.begin(); td_iter != typedefs.end(); ++td_iter) {
397     write_comma_if_needed();
398     generate_typedef(*td_iter);
399     indicate_comma_needed();
400   }
401   end_array();
402 
403   // Generate structs, exceptions, and unions in declared order
404   write_key_and("structs");
405   start_array();
406   vector<t_struct*> objects = program_->get_objects();
407   vector<t_struct*>::iterator o_iter;
408   for (o_iter = objects.begin(); o_iter != objects.end(); ++o_iter) {
409     write_comma_if_needed();
410     if ((*o_iter)->is_xception()) {
411       generate_xception(*o_iter);
412     } else {
413       generate_struct(*o_iter);
414     }
415     indicate_comma_needed();
416   }
417   end_array();
418 
419   // Generate constants
420   write_key_and("constants");
421   start_array();
422   vector<t_const*> consts = program_->get_consts();
423   vector<t_const*>::iterator c_iter;
424   for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
425     write_comma_if_needed();
426     generate_constant(*c_iter);
427     indicate_comma_needed();
428   }
429   end_array();
430 
431   // Generate services
432   write_key_and("services");
433   start_array();
434   vector<t_service*> services = program_->get_services();
435   vector<t_service*>::iterator sv_iter;
436   for (sv_iter = services.begin(); sv_iter != services.end(); ++sv_iter) {
437     write_comma_if_needed();
438     generate_service(*sv_iter);
439     indicate_comma_needed();
440   }
441   end_array();
442 
443   end_object();
444 
445   // Close the generator
446   close_generator();
447 }
448 
generate_typedef(t_typedef * ttypedef)449 void t_json_generator::generate_typedef(t_typedef* ttypedef) {
450   start_object();
451   write_key_and_string("name", get_qualified_name(ttypedef));
452   write_key_and_string("typeId", get_type_name(ttypedef->get_true_type()));
453   write_type_spec_object("type", ttypedef->get_true_type());
454   if (ttypedef->has_doc()) {
455     write_key_and_string("doc", ttypedef->get_doc());
456   }
457   if (ttypedef->annotations_.size() > 0) {
458     write_key_and("annotations");
459     start_object();
460     for (map<string, string>::iterator it = ttypedef->annotations_.begin(); it != ttypedef->annotations_.end(); ++it) {
461       write_key_and_string(it->first, it->second);
462     }
463     end_object();
464   }
465   end_object();
466 }
467 
write_string(const string & value)468 void t_json_generator::write_string(const string& value) {
469   f_json_ << quot << escape_json_string(value) << quot;
470 }
471 
write_const_value(t_const_value * value,bool should_force_string)472 void t_json_generator::write_const_value(t_const_value* value, bool should_force_string) {
473 
474   switch (value->get_type()) {
475 
476   case t_const_value::CV_IDENTIFIER:
477   case t_const_value::CV_INTEGER:
478     if (should_force_string) {
479       write_string(number_to_string(value->get_integer()));
480     } else {
481       write_number(value->get_integer());
482     }
483     break;
484 
485   case t_const_value::CV_DOUBLE:
486     if (should_force_string) {
487       write_string(number_to_string(value->get_double()));
488     } else {
489       write_number(value->get_double());
490     }
491     break;
492 
493   case t_const_value::CV_STRING:
494     write_string(value->get_string());
495     break;
496 
497   case t_const_value::CV_LIST: {
498     start_array();
499     std::vector<t_const_value*> list = value->get_list();
500     std::vector<t_const_value*>::iterator lit;
501     for (lit = list.begin(); lit != list.end(); ++lit) {
502       write_comma_if_needed();
503       f_json_ << indent();
504       write_const_value(*lit);
505       indicate_comma_needed();
506     }
507     end_array();
508     break;
509   }
510 
511   case t_const_value::CV_MAP: {
512     start_object(NO_INDENT);
513     std::map<t_const_value*, t_const_value*, t_const_value::value_compare> map = value->get_map();
514     std::map<t_const_value*, t_const_value*, t_const_value::value_compare>::iterator mit;
515     for (mit = map.begin(); mit != map.end(); ++mit) {
516       write_comma_if_needed();
517       f_json_ << indent();
518       // JSON objects only allow string keys
519       write_const_value(mit->first, FORCE_STRING);
520       f_json_ << ": ";
521       write_const_value(mit->second);
522       indicate_comma_needed();
523     }
524     end_object();
525     break;
526   }
527 
528   default:
529     f_json_ << "null";
530     break;
531   }
532 }
533 
json_str(const string & str)534 string t_json_generator::json_str(const string& str) {
535   return quot + escape_json_string(str) + quot;
536 }
537 
generate_constant(t_const * con)538 void t_json_generator::generate_constant(t_const* con) {
539   start_object();
540 
541   write_key_and_string("name", con->get_name());
542   write_key_and_string("typeId", get_type_name(con->get_type()));
543   write_type_spec_object("type", con->get_type());
544 
545   if (con->has_doc()) {
546     write_key_and_string("doc", con->get_doc());
547   }
548 
549   write_key_and("value");
550   write_const_value(con->get_value());
551 
552   end_object();
553 }
554 
generate_enum(t_enum * tenum)555 void t_json_generator::generate_enum(t_enum* tenum) {
556   start_object();
557 
558   write_key_and_string("name", tenum->get_name());
559 
560   if (tenum->has_doc()) {
561     write_key_and_string("doc", tenum->get_doc());
562   }
563 
564   if (tenum->annotations_.size() > 0) {
565       write_key_and("annotations");
566       start_object();
567       for (map<string, string>::iterator it = tenum->annotations_.begin(); it != tenum->annotations_.end(); ++it) {
568         write_key_and_string(it->first, it->second);
569       }
570       end_object();
571   }
572 
573   write_key_and("members");
574   start_array();
575   vector<t_enum_value*> values = tenum->get_constants();
576   vector<t_enum_value*>::iterator val_iter;
577   for (val_iter = values.begin(); val_iter != values.end(); ++val_iter) {
578     write_comma_if_needed();
579     t_enum_value* val = (*val_iter);
580     start_object();
581     write_key_and_string("name", val->get_name());
582     write_key_and_integer("value", val->get_value());
583     if (val->has_doc()) {
584       write_key_and_string("doc", val->get_doc());
585     }
586     end_object();
587     indicate_comma_needed();
588   }
589   end_array();
590 
591   end_object();
592 }
593 
generate_struct(t_struct * tstruct)594 void t_json_generator::generate_struct(t_struct* tstruct) {
595   start_object();
596 
597   write_key_and_string("name", tstruct->get_name());
598 
599   if (tstruct->has_doc()) {
600     write_key_and_string("doc", tstruct->get_doc());
601   }
602 
603   if (tstruct->annotations_.size() > 0) {
604     write_key_and("annotations");
605     start_object();
606     for (map<string, string>::iterator it = tstruct->annotations_.begin(); it != tstruct->annotations_.end(); ++it) {
607       write_key_and_string(it->first, it->second);
608     }
609     end_object();
610   }
611 
612   write_key_and_bool("isException", tstruct->is_xception());
613 
614   write_key_and_bool("isUnion", tstruct->is_union());
615 
616   write_key_and("fields");
617   start_array();
618   vector<t_field*> members = tstruct->get_members();
619   vector<t_field*>::iterator mem_iter;
620   for (mem_iter = members.begin(); mem_iter != members.end(); mem_iter++) {
621     write_comma_if_needed();
622     generate_field(*mem_iter);
623     indicate_comma_needed();
624   }
625   end_array();
626 
627   end_object();
628 }
629 
generate_service(t_service * tservice)630 void t_json_generator::generate_service(t_service* tservice) {
631   start_object();
632 
633   write_key_and_string("name", get_qualified_name(tservice));
634 
635   if (tservice->get_extends()) {
636     write_key_and_string("extends", get_qualified_name(tservice->get_extends()));
637   }
638 
639   if (tservice->has_doc()) {
640     write_key_and_string("doc", tservice->get_doc());
641   }
642 
643   if (tservice->annotations_.size() > 0) {
644     write_key_and("annotations");
645     start_object();
646     for (map<string, string>::iterator it = tservice->annotations_.begin(); it != tservice->annotations_.end(); ++it) {
647       write_key_and_string(it->first, it->second);
648     }
649     end_object();
650   }
651 
652   write_key_and("functions");
653   start_array();
654   vector<t_function*> functions = tservice->get_functions();
655   vector<t_function*>::iterator fn_iter = functions.begin();
656   for (; fn_iter != functions.end(); fn_iter++) {
657     write_comma_if_needed();
658     generate_function(*fn_iter);
659     indicate_comma_needed();
660   }
661   end_array();
662 
663   end_object();
664 }
665 
generate_function(t_function * tfunc)666 void t_json_generator::generate_function(t_function* tfunc) {
667   start_object();
668 
669   write_key_and_string("name", tfunc->get_name());
670 
671   write_key_and_string("returnTypeId", get_type_name(tfunc->get_returntype()));
672   write_type_spec_object("returnType", tfunc->get_returntype());
673 
674   write_key_and_bool("oneway", tfunc->is_oneway());
675 
676   if (tfunc->has_doc()) {
677     write_key_and_string("doc", tfunc->get_doc());
678   }
679 
680   if (tfunc->annotations_.size() > 0) {
681     write_key_and("annotations");
682     start_object();
683     for (map<string, string>::iterator it = tfunc->annotations_.begin(); it != tfunc->annotations_.end(); ++it) {
684       write_key_and_string(it->first, it->second);
685     }
686     end_object();
687   }
688 
689   write_key_and("arguments");
690   start_array();
691   vector<t_field*> members = tfunc->get_arglist()->get_members();
692   vector<t_field*>::iterator mem_iter = members.begin();
693   for (; mem_iter != members.end(); mem_iter++) {
694     write_comma_if_needed();
695     generate_field(*mem_iter);
696     indicate_comma_needed();
697   }
698   end_array();
699 
700   write_key_and("exceptions");
701   start_array();
702   vector<t_field*> excepts = tfunc->get_xceptions()->get_members();
703   vector<t_field*>::iterator ex_iter = excepts.begin();
704   for (; ex_iter != excepts.end(); ex_iter++) {
705     write_comma_if_needed();
706     generate_field(*ex_iter);
707     indicate_comma_needed();
708   }
709   end_array();
710 
711   end_object();
712 }
713 
generate_field(t_field * field)714 void t_json_generator::generate_field(t_field* field) {
715   start_object();
716 
717   write_key_and_integer("key", field->get_key());
718   write_key_and_string("name", field->get_name());
719   write_key_and_string("typeId", get_type_name(field->get_type()));
720   write_type_spec_object("type", field->get_type());
721 
722   if (field->has_doc()) {
723     write_key_and_string("doc", field->get_doc());
724   }
725 
726   if (field->annotations_.size() > 0) {
727     write_key_and("annotations");
728     start_object();
729     for (map<string, string>::iterator it = field->annotations_.begin(); it != field->annotations_.end(); ++it) {
730       write_key_and_string(it->first, it->second);
731     }
732     end_object();
733   }
734 
735   write_key_and("required");
736   switch (field->get_req()) {
737   case t_field::T_REQUIRED:
738     write_string("required");
739     break;
740   case t_field::T_OPT_IN_REQ_OUT:
741     write_string("req_out");
742     break;
743   default:
744     write_string("optional");
745     break;
746   }
747 
748   if (field->get_value()) {
749     write_key_and("default");
750     write_const_value(field->get_value());
751   }
752 
753   end_object();
754 }
755 
get_type_name(t_type * ttype)756 string t_json_generator::get_type_name(t_type* ttype) {
757   ttype = ttype->get_true_type();
758   if (ttype->is_list()) {
759     return "list";
760   }
761   if (ttype->is_set()) {
762     return "set";
763   }
764   if (ttype->is_map()) {
765     return "map";
766   }
767   if (ttype->is_enum()) {
768     return "i32";
769   }
770   if (ttype->is_struct()) {
771     return ((t_struct*)ttype)->is_union() ? "union" : "struct";
772   }
773   if (ttype->is_xception()) {
774     return "exception";
775   }
776   if (ttype->is_base_type()) {
777     t_base_type* tbasetype = (t_base_type*)ttype;
778     return tbasetype->is_binary() ? "binary" : t_base_type::t_base_name(tbasetype->get_base());
779   }
780 
781   return "(unknown)";
782 }
783 
get_qualified_name(t_type * ttype)784 string t_json_generator::get_qualified_name(t_type* ttype) {
785   if (should_merge_includes_ || ttype->get_program() == program_) {
786     return ttype->get_name();
787   }
788   return ttype->get_program()->get_name() + "." + ttype->get_name();
789 }
790 
791 THRIFT_REGISTER_GENERATOR(json,
792                           "JSON",
793                           "    merge:           Generate output with included files merged\n")
794