JRecord.java 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508
  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, software
  13. * distributed under the License is distributed on an "AS IS" BASIS,
  14. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. * See the License for the specific language governing permissions and
  16. * limitations under the License.
  17. */
  18. package com.yahoo.jute.compiler;
  19. import java.io.File;
  20. import java.io.FileWriter;
  21. import java.io.IOException;
  22. import java.util.ArrayList;
  23. import java.util.HashMap;
  24. import java.util.Iterator;
  25. /**
  26. *
  27. * @author Milind Bhandarkar
  28. */
  29. public class JRecord extends JCompType {
  30. private String mFQName;
  31. private String mName;
  32. private String mModule;
  33. private ArrayList<JField> mFields;
  34. /**
  35. * Creates a new instance of JRecord
  36. */
  37. public JRecord(String name, ArrayList flist) {
  38. super("struct " + name.substring(name.lastIndexOf('.')+1), name.replaceAll("\\.","::"), name, "Record", name);
  39. mFQName = name;
  40. int idx = name.lastIndexOf('.');
  41. mName = name.substring(idx+1);
  42. mModule = name.substring(0, idx);
  43. mFields = flist;
  44. }
  45. public String getName() {
  46. return mName;
  47. }
  48. public String getJavaFQName() {
  49. return mFQName;
  50. }
  51. public String getCppFQName() {
  52. return mFQName.replaceAll("\\.", "::");
  53. }
  54. public String getJavaPackage() {
  55. return mModule;
  56. }
  57. public String getCppNameSpace() {
  58. return mModule.replaceAll("\\.", "::");
  59. }
  60. public ArrayList getFields() {
  61. return mFields;
  62. }
  63. public String getSignature() {
  64. StringBuffer sb = new StringBuffer();
  65. sb.append("L").append(mName).append("(");
  66. for (Iterator i = mFields.iterator(); i.hasNext();) {
  67. String s = ((JField) i.next()).getSignature();
  68. sb.append(s);
  69. }
  70. sb.append(")");
  71. return sb.toString();
  72. }
  73. public String genCppDecl(String fname) {
  74. return " "+mName+" "+fname+";\n";
  75. }
  76. public String genJavaReadMethod(String fname, String tag) {
  77. return genJavaReadWrapper(fname, tag, false);
  78. }
  79. public String genJavaReadWrapper(String fname, String tag, boolean decl) {
  80. StringBuffer ret = new StringBuffer("");
  81. if (decl) {
  82. ret.append(" "+getJavaFQName()+" "+fname+";\n");
  83. }
  84. ret.append(" "+fname+"= new "+getJavaFQName()+"();\n");
  85. ret.append(" a_.readRecord("+fname+",\""+tag+"\");\n");
  86. return ret.toString();
  87. }
  88. public String genJavaWriteWrapper(String fname, String tag) {
  89. return " a_.writeRecord("+fname+",\""+tag+"\");\n";
  90. }
  91. static HashMap<String, String> vectorStructs = new HashMap<String, String>();
  92. public void genCCode(FileWriter h, FileWriter c) throws IOException {
  93. for (JField f : mFields) {
  94. if (f.getType() instanceof JVector) {
  95. JVector jv = (JVector)f.getType();
  96. JType jvType = jv.getElementType();
  97. String struct_name = JVector.extractVectorName(jvType);
  98. if (vectorStructs.get(struct_name) == null) {
  99. vectorStructs.put(struct_name, struct_name);
  100. h.write("struct " + struct_name + " {\n int32_t count;\n" + jv.getElementType().genCDecl("*data") + ";\n};\n");
  101. h.write("int serialize_" + struct_name + "(struct oarchive *out, const char *tag, struct " + struct_name + " *v);\n");
  102. h.write("int deserialize_" + struct_name + "(struct iarchive *in, const char *tag, struct " + struct_name + " *v);\n");
  103. h.write("int allocate_" + struct_name + "(struct " + struct_name + " *v, int32_t len);\n");
  104. h.write("int deallocate_" + struct_name + "(struct " + struct_name + " *v);\n");
  105. c.write("int allocate_" + struct_name + "(struct " + struct_name + " *v, int32_t len) {\n");
  106. c.write(" if (!len) {\n");
  107. c.write(" v->count = 0;\n");
  108. c.write(" v->data = 0;\n");
  109. c.write(" } else {\n");
  110. c.write(" v->count = len;\n");
  111. c.write(" v->data = calloc(sizeof(*v->data), len);\n");
  112. c.write(" }\n");
  113. c.write(" return 0;\n");
  114. c.write("}\n");
  115. c.write("int deallocate_" + struct_name + "(struct " + struct_name + " *v) {\n");
  116. c.write(" if (v->data) {\n");
  117. c.write(" int32_t i;\n");
  118. c.write(" for(i=0;i<v->count; i++) {\n");
  119. c.write(" deallocate_"+JRecord.extractMethodSuffix(jvType)+"(&v->data[i]);\n");
  120. c.write(" }\n");
  121. c.write(" free(v->data);\n");
  122. c.write(" v->data = 0;\n");
  123. c.write(" }\n");
  124. c.write(" return 0;\n");
  125. c.write("}\n");
  126. c.write("int serialize_" + struct_name + "(struct oarchive *out, const char *tag, struct " + struct_name + " *v)\n");
  127. c.write("{\n");
  128. c.write(" int32_t count = v->count;\n");
  129. c.write(" int rc = 0;\n");
  130. c.write(" int32_t i;\n");
  131. c.write(" rc = out->start_vector(out, tag, &count);\n");
  132. c.write(" for(i=0;i<v->count;i++) {\n");
  133. genSerialize(c, jvType, "data", "data[i]");
  134. c.write(" }\n");
  135. c.write(" rc = rc ? : out->end_vector(out, tag);\n");
  136. c.write(" return rc;\n");
  137. c.write("}\n");
  138. c.write("int deserialize_" + struct_name + "(struct iarchive *in, const char *tag, struct " + struct_name + " *v)\n");
  139. c.write("{\n");
  140. c.write(" int rc = 0;\n");
  141. c.write(" int32_t i;\n");
  142. c.write(" rc = in->start_vector(in, tag, &v->count);\n");
  143. c.write(" v->data = calloc(v->count, sizeof(*v->data));\n");
  144. c.write(" for(i=0;i<v->count;i++) {\n");
  145. genDeserialize(c, jvType, "value", "data[i]");
  146. c.write(" }\n");
  147. c.write(" rc = in->end_vector(in, tag);\n");
  148. c.write(" return rc;\n");
  149. c.write("}\n");
  150. }
  151. }
  152. }
  153. String rec_name = getName();
  154. h.write("struct " + rec_name + " {\n");
  155. for (JField f : mFields) {
  156. h.write(f.genCDecl());
  157. }
  158. h.write("};\n");
  159. h.write("int serialize_" + rec_name + "(struct oarchive *out, const char *tag, struct " + rec_name + " *v);\n");
  160. h.write("int deserialize_" + rec_name + "(struct iarchive *in, const char *tag, struct " + rec_name + "*v);\n");
  161. h.write("void deallocate_" + rec_name + "(struct " + rec_name + "*);\n");
  162. c.write("int serialize_" + rec_name + "(struct oarchive *out, const char *tag, struct " + rec_name + " *v)");
  163. c.write("{\n");
  164. c.write(" int rc;\n");
  165. c.write(" rc = out->start_record(out, tag);\n");
  166. for(JField f : mFields) {
  167. genSerialize(c, f.getType(), f.getTag(), f.getName());
  168. }
  169. c.write(" rc = rc ? : out->end_record(out, tag);\n");
  170. c.write(" return rc;\n");
  171. c.write("}\n");
  172. c.write("int deserialize_" + rec_name + "(struct iarchive *in, const char *tag, struct " + rec_name + "*v)");
  173. c.write("{\n");
  174. c.write(" int rc;\n");
  175. c.write(" rc = in->start_record(in, tag);\n");
  176. for(JField f : mFields) {
  177. genDeserialize(c, f.getType(), f.getTag(), f.getName());
  178. }
  179. c.write(" rc = rc ? : in->end_record(in, tag);\n");
  180. c.write(" return rc;\n");
  181. c.write("}\n");
  182. c.write("void deallocate_" + rec_name + "(struct " + rec_name + "*v)");
  183. c.write("{\n");
  184. for(JField f : mFields) {
  185. if (f.getType() instanceof JRecord) {
  186. c.write(" deallocate_" + extractStructName(f.getType()) + "(&v->" + f.getName() + ");\n");
  187. } else if (f.getType() instanceof JVector) {
  188. JVector vt = (JVector)f.getType();
  189. c.write(" deallocate_" + JVector.extractVectorName(vt.getElementType())+ "(&v->"+f.getName()+");\n");
  190. } else if (f.getType() instanceof JCompType) {
  191. c.write(" deallocate_" + extractMethodSuffix(f.getType()) + "(&v->"+f.getName()+");\n");
  192. }
  193. }
  194. c.write("}\n");
  195. }
  196. private void genSerialize(FileWriter c, JType type, String tag, String name) throws IOException {
  197. if (type instanceof JRecord) {
  198. c.write(" rc = rc ? : serialize_" + extractStructName(type) + "(out, \"" + tag + "\", &v->" + name + ");\n");
  199. } else if (type instanceof JVector) {
  200. c.write(" rc = rc ? : serialize_" + JVector.extractVectorName(((JVector)type).getElementType()) + "(out, \"" + tag + "\", &v->" + name + ");\n");
  201. } else {
  202. c.write(" rc = rc ? : out->serialize_" + extractMethodSuffix(type) + "(out, \"" + tag + "\", &v->" + name + ");\n");
  203. }
  204. }
  205. private void genDeserialize(FileWriter c, JType type, String tag, String name) throws IOException {
  206. if (type instanceof JRecord) {
  207. c.write(" rc = rc ? : deserialize_" + extractStructName(type) + "(in, \"" + tag + "\", &v->" + name + ");\n");
  208. } else if (type instanceof JVector) {
  209. c.write(" rc = rc ? : deserialize_" + JVector.extractVectorName(((JVector)type).getElementType()) + "(in, \"" + tag + "\", &v->" + name + ");\n");
  210. } else {
  211. c.write(" rc = rc ? : in->deserialize_" + extractMethodSuffix(type) + "(in, \"" + tag + "\", &v->" + name + ");\n");
  212. }
  213. }
  214. static String extractMethodSuffix(JType t) {
  215. if (t instanceof JRecord) {
  216. return extractStructName(t);
  217. }
  218. return t.getMethodSuffix();
  219. }
  220. static private String extractStructName(JType t) {
  221. String type = t.getCType();
  222. if (!type.startsWith("struct ")) return type;
  223. return type.substring("struct ".length());
  224. }
  225. public void genCppCode(FileWriter hh, FileWriter cc)
  226. throws IOException {
  227. String[] ns = getCppNameSpace().split("::");
  228. for (int i = 0; i < ns.length; i++) {
  229. hh.write("namespace "+ns[i]+" {\n");
  230. }
  231. hh.write("class "+getName()+" : public ::hadoop::Record {\n");
  232. hh.write("private:\n");
  233. for (Iterator i = mFields.iterator(); i.hasNext();) {
  234. JField jf = (JField) i.next();
  235. hh.write(jf.genCppDecl());
  236. }
  237. hh.write(" mutable std::bitset<"+mFields.size()+"> bs_;\n");
  238. hh.write("public:\n");
  239. hh.write(" virtual void serialize(::hadoop::OArchive& a_, const char* tag) const;\n");
  240. hh.write(" virtual void deserialize(::hadoop::IArchive& a_, const char* tag);\n");
  241. hh.write(" virtual const ::std::string& type() const;\n");
  242. hh.write(" virtual const ::std::string& signature() const;\n");
  243. hh.write(" virtual bool validate() const;\n");
  244. hh.write(" virtual bool operator<(const "+getName()+"& peer_) const;\n");
  245. hh.write(" virtual bool operator==(const "+getName()+"& peer_) const;\n");
  246. hh.write(" virtual ~"+getName()+"() {};\n");
  247. int fIdx = 0;
  248. for (Iterator i = mFields.iterator(); i.hasNext(); fIdx++) {
  249. JField jf = (JField) i.next();
  250. hh.write(jf.genCppGetSet(fIdx));
  251. }
  252. hh.write("}; // end record "+getName()+"\n");
  253. for (int i=ns.length-1; i>=0; i--) {
  254. hh.write("} // end namespace "+ns[i]+"\n");
  255. }
  256. cc.write("void "+getCppFQName()+"::serialize(::hadoop::OArchive& a_, const char* tag) const {\n");
  257. cc.write(" if (!validate()) throw new ::hadoop::IOException(\"All fields not set.\");\n");
  258. cc.write(" a_.startRecord(*this,tag);\n");
  259. fIdx = 0;
  260. for (Iterator i = mFields.iterator(); i.hasNext(); fIdx++) {
  261. JField jf = (JField) i.next();
  262. String name = jf.getName();
  263. if (jf.getType() instanceof JBuffer) {
  264. cc.write(" a_.serialize("+name+","+name+".length(),\""+jf.getTag()+"\");\n");
  265. } else {
  266. cc.write(" a_.serialize("+name+",\""+jf.getTag()+"\");\n");
  267. }
  268. cc.write(" bs_.reset("+fIdx+");\n");
  269. }
  270. cc.write(" a_.endRecord(*this,tag);\n");
  271. cc.write(" return;\n");
  272. cc.write("}\n");
  273. cc.write("void "+getCppFQName()+"::deserialize(::hadoop::IArchive& a_, const char* tag) {\n");
  274. cc.write(" a_.startRecord(*this,tag);\n");
  275. fIdx = 0;
  276. for (Iterator i = mFields.iterator(); i.hasNext(); fIdx++) {
  277. JField jf = (JField) i.next();
  278. String name = jf.getName();
  279. if (jf.getType() instanceof JBuffer) {
  280. cc.write(" { size_t len=0; a_.deserialize("+name+",len,\""+jf.getTag()+"\");}\n");
  281. } else {
  282. cc.write(" a_.deserialize("+name+",\""+jf.getTag()+"\");\n");
  283. }
  284. cc.write(" bs_.set("+fIdx+");\n");
  285. }
  286. cc.write(" a_.endRecord(*this,tag);\n");
  287. cc.write(" return;\n");
  288. cc.write("}\n");
  289. cc.write("bool "+getCppFQName()+"::validate() const {\n");
  290. cc.write(" if (bs_.size() != bs_.count()) return false;\n");
  291. for (Iterator i = mFields.iterator(); i.hasNext(); fIdx++) {
  292. JField jf = (JField) i.next();
  293. JType type = jf.getType();
  294. if (type instanceof JRecord) {
  295. cc.write(" if (!"+jf.getName()+".validate()) return false;\n");
  296. }
  297. }
  298. cc.write(" return true;\n");
  299. cc.write("}\n");
  300. cc.write("bool "+getCppFQName()+"::operator< (const "+getCppFQName()+"& peer_) const {\n");
  301. cc.write(" return (1\n");
  302. for (Iterator i = mFields.iterator(); i.hasNext();) {
  303. JField jf = (JField) i.next();
  304. String name = jf.getName();
  305. cc.write(" && ("+name+" < peer_."+name+")\n");
  306. }
  307. cc.write(" );\n");
  308. cc.write("}\n");
  309. cc.write("bool "+getCppFQName()+"::operator== (const "+getCppFQName()+"& peer_) const {\n");
  310. cc.write(" return (1\n");
  311. for (Iterator i = mFields.iterator(); i.hasNext();) {
  312. JField jf = (JField) i.next();
  313. String name = jf.getName();
  314. cc.write(" && ("+name+" == peer_."+name+")\n");
  315. }
  316. cc.write(" );\n");
  317. cc.write("}\n");
  318. cc.write("const ::std::string&"+getCppFQName()+"::type() const {\n");
  319. cc.write(" static const ::std::string type_(\""+mName+"\");\n");
  320. cc.write(" return type_;\n");
  321. cc.write("}\n");
  322. cc.write("const ::std::string&"+getCppFQName()+"::signature() const {\n");
  323. cc.write(" static const ::std::string sig_(\""+getSignature()+"\");\n");
  324. cc.write(" return sig_;\n");
  325. cc.write("}\n");
  326. }
  327. public void genJavaCode() throws IOException {
  328. String pkg = getJavaPackage();
  329. String pkgpath = pkg.replaceAll("\\.", "/");
  330. File pkgdir = new File(pkgpath);
  331. if (!pkgdir.exists()) {
  332. // create the pkg directory
  333. boolean ret = pkgdir.mkdirs();
  334. if (!ret) {
  335. System.out.println("Cannnot create directory: "+pkgpath);
  336. System.exit(1);
  337. }
  338. } else if (!pkgdir.isDirectory()) {
  339. // not a directory
  340. System.out.println(pkgpath+" is not a directory.");
  341. System.exit(1);
  342. }
  343. File jfile = new File(pkgdir, getName()+".java");
  344. FileWriter jj = new FileWriter(jfile);
  345. jj.write("// File generated by hadoop record compiler. Do not edit.\n");
  346. jj.write("package "+getJavaPackage()+";\n\n");
  347. jj.write("import com.yahoo.jute.*;\n");
  348. jj.write("public class "+getName()+" implements Record {\n");
  349. for (Iterator i = mFields.iterator(); i.hasNext();) {
  350. JField jf = (JField) i.next();
  351. jj.write(jf.genJavaDecl());
  352. }
  353. jj.write(" public "+getName()+"() {\n");
  354. jj.write(" }\n");
  355. jj.write(" public "+getName()+"(\n");
  356. int fIdx = 0;
  357. int fLen = mFields.size();
  358. for (Iterator i = mFields.iterator(); i.hasNext(); fIdx++) {
  359. JField jf = (JField) i.next();
  360. jj.write(jf.genJavaConstructorParam(jf.getName()));
  361. jj.write((fLen-1 == fIdx)?"":",\n");
  362. }
  363. jj.write(") {\n");
  364. fIdx = 0;
  365. for (Iterator i = mFields.iterator(); i.hasNext(); fIdx++) {
  366. JField jf = (JField) i.next();
  367. jj.write(jf.genJavaConstructorSet(jf.getName()));
  368. }
  369. jj.write(" }\n");
  370. fIdx = 0;
  371. for (Iterator i = mFields.iterator(); i.hasNext(); fIdx++) {
  372. JField jf = (JField) i.next();
  373. jj.write(jf.genJavaGetSet(fIdx));
  374. }
  375. jj.write(" public void serialize(OutputArchive a_, String tag) throws java.io.IOException {\n");
  376. jj.write(" a_.startRecord(this,tag);\n");
  377. fIdx = 0;
  378. for (Iterator i = mFields.iterator(); i.hasNext(); fIdx++) {
  379. JField jf = (JField) i.next();
  380. jj.write(jf.genJavaWriteMethodName());
  381. }
  382. jj.write(" a_.endRecord(this,tag);\n");
  383. jj.write(" }\n");
  384. jj.write(" public void deserialize(InputArchive a_, String tag) throws java.io.IOException {\n");
  385. jj.write(" a_.startRecord(tag);\n");
  386. fIdx = 0;
  387. for (Iterator i = mFields.iterator(); i.hasNext(); fIdx++) {
  388. JField jf = (JField) i.next();
  389. jj.write(jf.genJavaReadMethodName());
  390. }
  391. jj.write(" a_.endRecord(tag);\n");
  392. jj.write("}\n");
  393. jj.write(" public String toString() {\n");
  394. jj.write(" try {\n");
  395. jj.write(" java.io.ByteArrayOutputStream s =\n");
  396. jj.write(" new java.io.ByteArrayOutputStream();\n");
  397. jj.write(" CsvOutputArchive a_ = \n");
  398. jj.write(" new CsvOutputArchive(s);\n");
  399. jj.write(" a_.startRecord(this,\"\");\n");
  400. fIdx = 0;
  401. for (Iterator i = mFields.iterator(); i.hasNext(); fIdx++) {
  402. JField jf = (JField) i.next();
  403. jj.write(jf.genJavaWriteMethodName());
  404. }
  405. jj.write(" a_.endRecord(this,\"\");\n");
  406. jj.write(" return new String(s.toByteArray(), \"UTF-8\");\n");
  407. jj.write(" } catch (Throwable ex) {\n");
  408. jj.write(" ex.printStackTrace();\n");
  409. jj.write(" }\n");
  410. jj.write(" return \"ERROR\";\n");
  411. jj.write(" }\n");
  412. jj.write(" public void write(java.io.DataOutput out) throws java.io.IOException {\n");
  413. jj.write(" BinaryOutputArchive archive = new BinaryOutputArchive(out);\n");
  414. jj.write(" serialize(archive, \"\");\n");
  415. jj.write(" }\n");
  416. jj.write(" public void readFields(java.io.DataInput in) throws java.io.IOException {\n");
  417. jj.write(" BinaryInputArchive archive = new BinaryInputArchive(in);\n");
  418. jj.write(" deserialize(archive, \"\");\n");
  419. jj.write(" }\n");
  420. jj.write(" public int compareTo (Object peer_) throws ClassCastException {\n");
  421. jj.write(" if (!(peer_ instanceof "+getName()+")) {\n");
  422. jj.write(" throw new ClassCastException(\"Comparing different types of records.\");\n");
  423. jj.write(" }\n");
  424. jj.write(" "+getName()+" peer = ("+getName()+") peer_;\n");
  425. jj.write(" int ret = 0;\n");
  426. for (Iterator i = mFields.iterator(); i.hasNext(); fIdx++) {
  427. JField jf = (JField) i.next();
  428. jj.write(jf.genJavaCompareTo());
  429. jj.write(" if (ret != 0) return ret;\n");
  430. }
  431. jj.write(" return ret;\n");
  432. jj.write(" }\n");
  433. jj.write(" public boolean equals(Object peer_) {\n");
  434. jj.write(" if (!(peer_ instanceof "+getName()+")) {\n");
  435. jj.write(" return false;\n");
  436. jj.write(" }\n");
  437. jj.write(" if (peer_ == this) {\n");
  438. jj.write(" return true;\n");
  439. jj.write(" }\n");
  440. jj.write(" "+getName()+" peer = ("+getName()+") peer_;\n");
  441. jj.write(" boolean ret = false;\n");
  442. for (Iterator i = mFields.iterator(); i.hasNext(); fIdx++) {
  443. JField jf = (JField) i.next();
  444. jj.write(jf.genJavaEquals());
  445. jj.write(" if (!ret) return ret;\n");
  446. }
  447. jj.write(" return ret;\n");
  448. jj.write(" }\n");
  449. jj.write(" public int hashCode() {\n");
  450. jj.write(" int result = 17;\n");
  451. jj.write(" int ret;\n");
  452. for (Iterator i = mFields.iterator(); i.hasNext(); fIdx++) {
  453. JField jf = (JField) i.next();
  454. jj.write(jf.genJavaHashCode());
  455. jj.write(" result = 37*result + ret;\n");
  456. }
  457. jj.write(" return result;\n");
  458. jj.write(" }\n");
  459. jj.write(" public static String signature() {\n");
  460. jj.write(" return \""+getSignature()+"\";\n");
  461. jj.write(" }\n");
  462. jj.write("}\n");
  463. jj.close();
  464. }
  465. }