1 package org.codehaus.modello.plugin.jackson;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 import javax.inject.Named;
26
27 import java.io.IOException;
28 import java.util.List;
29 import java.util.Map;
30
31 import org.codehaus.modello.ModelloException;
32 import org.codehaus.modello.model.Model;
33 import org.codehaus.modello.model.ModelAssociation;
34 import org.codehaus.modello.model.ModelClass;
35 import org.codehaus.modello.model.ModelDefault;
36 import org.codehaus.modello.model.ModelField;
37 import org.codehaus.modello.plugin.java.javasource.JClass;
38 import org.codehaus.modello.plugin.java.javasource.JConstructor;
39 import org.codehaus.modello.plugin.java.javasource.JField;
40 import org.codehaus.modello.plugin.java.javasource.JMethod;
41 import org.codehaus.modello.plugin.java.javasource.JParameter;
42 import org.codehaus.modello.plugin.java.javasource.JSourceCode;
43 import org.codehaus.modello.plugin.java.javasource.JSourceWriter;
44 import org.codehaus.modello.plugin.java.javasource.JType;
45 import org.codehaus.modello.plugin.java.metadata.JavaClassMetadata;
46 import org.codehaus.modello.plugin.java.metadata.JavaFieldMetadata;
47 import org.codehaus.modello.plugin.model.ModelClassMetadata;
48 import org.codehaus.modello.plugins.xml.metadata.XmlAssociationMetadata;
49 import org.codehaus.modello.plugins.xml.metadata.XmlClassMetadata;
50 import org.codehaus.modello.plugins.xml.metadata.XmlFieldMetadata;
51 import org.codehaus.plexus.util.StringUtils;
52
53
54
55
56 @Named("jackson-reader")
57 public class JacksonReaderGenerator extends AbstractJacksonGenerator {
58
59 private static final String SOURCE_PARAM = "source";
60
61 private static final String LOCATION_VAR = "_location";
62
63 private boolean requiresDomSupport;
64
65 private ModelClass locationTracker;
66
67 private String locationField;
68
69 private ModelClass sourceTracker;
70
71 private String trackingArgs;
72
73 protected boolean isLocationTracking() {
74 return false;
75 }
76
77 @Override
78 public void generate(Model model, Map<String, Object> parameters) throws ModelloException {
79 initialize(model, parameters);
80
81 requiresDomSupport = false;
82 locationTracker = sourceTracker = null;
83 trackingArgs = locationField = "";
84
85 if (isLocationTracking()) {
86 locationTracker = model.getLocationTracker(getGeneratedVersion());
87 if (locationTracker == null) {
88 throw new ModelloException("No model class has been marked as location tracker"
89 + " via the attribute locationTracker=\"locations\""
90 + ", cannot generate extended reader.");
91 }
92
93 locationField =
94 ((ModelClassMetadata) locationTracker.getMetadata(ModelClassMetadata.ID)).getLocationTracker();
95
96 sourceTracker = model.getSourceTracker(getGeneratedVersion());
97
98 if (sourceTracker != null) {
99 trackingArgs += ", " + SOURCE_PARAM;
100 }
101 }
102
103 try {
104 generateJacksonReader();
105 } catch (IOException ex) {
106 throw new ModelloException("Exception while generating Jackson Reader.", ex);
107 }
108 }
109
110 private void writeAllClassesReaders(Model objectModel, JClass jClass) {
111 ModelClass root = objectModel.getClass(objectModel.getRoot(getGeneratedVersion()), getGeneratedVersion());
112
113 for (ModelClass clazz : getClasses(objectModel)) {
114 if (isTrackingSupport(clazz)) {
115 continue;
116 }
117
118 writeClassReaders(clazz, jClass, root.getName().equals(clazz.getName()));
119 }
120 }
121
122 private void writeClassReaders(ModelClass modelClass, JClass jClass, boolean rootElement) {
123 JavaClassMetadata javaClassMetadata =
124 (JavaClassMetadata) modelClass.getMetadata(JavaClassMetadata.class.getName());
125
126
127 if (javaClassMetadata.isAbstract()) {
128 return;
129 }
130
131 XmlClassMetadata xmlClassMetadata = (XmlClassMetadata) modelClass.getMetadata(XmlClassMetadata.ID);
132 if (!rootElement && !xmlClassMetadata.isStandaloneRead()) {
133 return;
134 }
135
136 String className = modelClass.getName();
137
138 String capClassName = capitalise(className);
139
140 String readerMethodName = "read";
141 if (!rootElement) {
142 readerMethodName += capClassName;
143 }
144
145
146
147
148
149 JMethod unmarshall = new JMethod(readerMethodName, new JClass(className), null);
150 unmarshall.getModifiers().makePrivate();
151
152 unmarshall.addParameter(new JParameter(new JClass("JsonParser"), "parser"));
153 unmarshall.addParameter(new JParameter(JClass.BOOLEAN, "strict"));
154 addTrackingParameters(unmarshall);
155
156 unmarshall.addException(new JClass("IOException"));
157
158 JSourceCode sc = unmarshall.getSourceCode();
159
160 String variableName = uncapitalise(className);
161
162 sc.add(className + ' ' + variableName + " = parse" + capClassName + "( parser, strict" + trackingArgs + " );");
163
164 if (rootElement) {
165
166
167 }
168
169 sc.add("return " + variableName + ';');
170
171 jClass.addMethod(unmarshall);
172
173
174
175
176
177 unmarshall = new JMethod(readerMethodName, new JClass(className), null);
178
179 unmarshall.addParameter(new JParameter(new JClass("Reader"), "reader"));
180 unmarshall.addParameter(new JParameter(JClass.BOOLEAN, "strict"));
181 addTrackingParameters(unmarshall);
182
183 unmarshall.addException(new JClass("IOException"));
184
185 sc = unmarshall.getSourceCode();
186
187 sc.add("JsonParser parser = factory.createParser( reader );");
188
189 sc.add("return " + readerMethodName + "( parser, strict );");
190
191 jClass.addMethod(unmarshall);
192 unmarshall = new JMethod(readerMethodName, new JClass(className), null);
193
194 unmarshall.addParameter(new JParameter(new JClass("Reader"), "reader"));
195
196 unmarshall.addException(new JClass("IOException"));
197
198 sc = unmarshall.getSourceCode();
199 sc.add("return " + readerMethodName + "( reader, true );");
200
201 jClass.addMethod(unmarshall);
202
203
204
205
206
207 unmarshall = new JMethod(readerMethodName, new JClass(className), null);
208
209 unmarshall.addParameter(new JParameter(new JClass("InputStream"), "in"));
210 unmarshall.addParameter(new JParameter(JClass.BOOLEAN, "strict"));
211 addTrackingParameters(unmarshall);
212
213 unmarshall.addException(new JClass("IOException"));
214
215 sc = unmarshall.getSourceCode();
216
217 sc.add("return " + readerMethodName + "( new InputStreamReader( in ), strict" + trackingArgs + " );");
218
219 jClass.addMethod(unmarshall);
220 unmarshall = new JMethod(readerMethodName, new JClass(className), null);
221
222 unmarshall.addParameter(new JParameter(new JClass("InputStream"), "in"));
223
224 unmarshall.addException(new JClass("IOException"));
225
226 sc = unmarshall.getSourceCode();
227
228 sc.add("return " + readerMethodName + "( in, true );");
229
230 jClass.addMethod(unmarshall);
231
232
233 }
234
235 private void generateJacksonReader() throws ModelloException, IOException {
236 Model objectModel = getModel();
237
238 String packageName =
239 objectModel.getDefaultPackageName(isPackageWithVersion(), getGeneratedVersion()) + ".io.jackson";
240
241 String unmarshallerName = getFileName("JacksonReader" + (isLocationTracking() ? "Ex" : ""));
242
243 JSourceWriter sourceWriter = newJSourceWriter(packageName, unmarshallerName);
244
245 JClass jClass = new JClass(packageName + '.' + unmarshallerName);
246 initHeader(jClass);
247 suppressAllWarnings(objectModel, jClass);
248
249 jClass.addImport("com.fasterxml.jackson.core.JsonFactory");
250 jClass.addImport("com.fasterxml.jackson.core.JsonParser");
251 jClass.addImport("com.fasterxml.jackson.core.JsonParser.Feature");
252 jClass.addImport("com.fasterxml.jackson.core.JsonParseException");
253 jClass.addImport("com.fasterxml.jackson.core.JsonToken");
254 jClass.addImport("java.io.InputStream");
255 jClass.addImport("java.io.InputStreamReader");
256 jClass.addImport("java.io.IOException");
257 jClass.addImport("java.io.Reader");
258 jClass.addImport("java.text.DateFormat");
259 jClass.addImport("java.util.Set");
260 jClass.addImport("java.util.HashSet");
261
262 addModelImports(jClass, null);
263
264 JField factoryField = new JField(new JClass("JsonFactory"), "factory");
265 factoryField.getModifiers().setFinal(true);
266 factoryField.setInitString("new JsonFactory()");
267 jClass.addField(factoryField);
268
269 JConstructor jacksonReaderConstructor = new JConstructor(jClass);
270 JSourceCode sc = jacksonReaderConstructor.getSourceCode();
271 sc.add("factory.enable( Feature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER );");
272 sc.add("factory.enable( Feature.ALLOW_COMMENTS );");
273 sc.add("factory.enable( Feature.ALLOW_NON_NUMERIC_NUMBERS );");
274 sc.add("factory.enable( Feature.ALLOW_NUMERIC_LEADING_ZEROS );");
275 sc.add("factory.enable( Feature.ALLOW_SINGLE_QUOTES );");
276 sc.add("factory.enable( Feature.ALLOW_UNQUOTED_CONTROL_CHARS );");
277 sc.add("factory.enable( Feature.ALLOW_UNQUOTED_FIELD_NAMES );");
278
279 jClass.addConstructor(jacksonReaderConstructor);
280
281
282
283
284
285 writeAllClassesParser(objectModel, jClass);
286
287
288
289
290
291 writeAllClassesReaders(objectModel, jClass);
292
293
294
295
296
297 writeHelpers(jClass);
298
299
300
301
302
303 if (requiresDomSupport) {
304 jClass.addImport("com.fasterxml.jackson.databind.ObjectMapper");
305
306 sc.add("factory.setCodec( new ObjectMapper() );");
307 }
308
309 jClass.print(sourceWriter);
310
311 sourceWriter.close();
312 }
313
314 private void writeAllClassesParser(Model objectModel, JClass jClass) {
315 ModelClass root = objectModel.getClass(objectModel.getRoot(getGeneratedVersion()), getGeneratedVersion());
316
317 for (ModelClass clazz : getClasses(objectModel)) {
318 if (isTrackingSupport(clazz)) {
319 continue;
320 }
321
322 writeClassParser(clazz, jClass, root.getName().equals(clazz.getName()));
323 }
324 }
325
326 private void writeClassParser(ModelClass modelClass, JClass jClass, boolean rootElement) {
327 JavaClassMetadata javaClassMetadata =
328 (JavaClassMetadata) modelClass.getMetadata(JavaClassMetadata.class.getName());
329
330
331 if (javaClassMetadata.isAbstract()) {
332 return;
333 }
334
335 String className = modelClass.getName();
336
337 String capClassName = capitalise(className);
338
339 String uncapClassName = uncapitalise(className);
340
341 JMethod unmarshall = new JMethod("parse" + capClassName, new JClass(className), null);
342 unmarshall.getModifiers().makePrivate();
343
344 unmarshall.addParameter(new JParameter(new JClass("JsonParser"), "parser"));
345 unmarshall.addParameter(new JParameter(JClass.BOOLEAN, "strict"));
346 addTrackingParameters(unmarshall);
347
348 unmarshall.addException(new JClass("IOException"));
349
350 JSourceCode sc = unmarshall.getSourceCode();
351
352 sc.add(
353 "if ( JsonToken.START_OBJECT != parser.getCurrentToken() && JsonToken.START_OBJECT != parser.nextToken() )");
354 sc.add("{");
355 sc.addIndented("throw new JsonParseException( \"Expected '"
356 + className
357 + "' data to start with an Object\", parser.getCurrentLocation() );");
358 sc.add("}");
359
360 sc.add(className + " " + uncapClassName + " = new " + className + "();");
361
362 if (locationTracker != null) {
363 sc.add(locationTracker.getName() + " " + LOCATION_VAR + ";");
364 writeNewSetLocation("\"\"", uncapClassName, null, sc);
365 }
366
367 List<ModelField> modelFields = getFieldsForXml(modelClass, getGeneratedVersion());
368
369 {
370
371
372 sc.add("Set<String> parsed = new HashSet<String>();");
373
374 sc.add("while ( JsonToken.END_OBJECT != parser.nextToken() )");
375
376 sc.add("{");
377 sc.indent();
378
379 boolean addElse = false;
380
381 for (ModelField field : modelFields) {
382 XmlFieldMetadata xmlFieldMetadata = (XmlFieldMetadata) field.getMetadata(XmlFieldMetadata.ID);
383
384 processField(field, xmlFieldMetadata, addElse, sc, uncapClassName, jClass);
385
386 addElse = true;
387 }
388
389 if (addElse) {
390 sc.add("else");
391
392 sc.add("{");
393 sc.indent();
394 }
395
396 sc.add("checkUnknownElement( parser, strict );");
397
398 if (addElse) {
399 sc.unindent();
400 sc.add("}");
401 }
402
403 sc.unindent();
404 sc.add("}");
405 }
406
407 sc.add("return " + uncapClassName + ";");
408
409 jClass.addMethod(unmarshall);
410 }
411
412
413
414
415
416
417
418
419
420
421
422 private void processField(
423 ModelField field,
424 XmlFieldMetadata xmlFieldMetadata,
425 boolean addElse,
426 JSourceCode sc,
427 String objectName,
428 JClass jClass) {
429 String fieldTagName = resolveTagName(field, xmlFieldMetadata);
430
431 String capFieldName = capitalise(field.getName());
432
433 String singularName = singular(field.getName());
434
435 String alias;
436 if (StringUtils.isEmpty(field.getAlias())) {
437 alias = "null";
438 } else {
439 alias = "\"" + field.getAlias() + "\"";
440 }
441
442 String tagComparison = (addElse ? "else " : "") + "if ( checkFieldWithDuplicate( parser, \"" + fieldTagName
443 + "\", " + alias + ", parsed ) )";
444
445 if (!(field instanceof ModelAssociation)) {
446 sc.add(tagComparison);
447
448 sc.add("{");
449
450 sc.indent();
451
452 writePrimitiveField(
453 field,
454 field.getType(),
455 objectName,
456 objectName,
457 "\"" + field.getName() + "\"",
458 "set" + capFieldName,
459 sc,
460 false);
461
462 sc.unindent();
463 sc.add("}");
464 } else {
465 ModelAssociation association = (ModelAssociation) field;
466
467 String associationName = association.getName();
468
469 if (association.isOneMultiplicity()) {
470 sc.add(tagComparison);
471
472 sc.add("{");
473 sc.addIndented(objectName + ".set" + capFieldName + "( parse" + association.getTo() + "( parser, strict"
474 + trackingArgs + " ) );");
475 sc.add("}");
476 } else {
477
478
479 XmlAssociationMetadata xmlAssociationMetadata =
480 (XmlAssociationMetadata) association.getAssociationMetadata(XmlAssociationMetadata.ID);
481
482 String type = association.getType();
483
484 if (ModelDefault.LIST.equals(type) || ModelDefault.SET.equals(type)) {
485 boolean inModel = isClassInModel(
486 association.getTo(), field.getModelClass().getModel());
487
488 sc.add((addElse ? "else " : "") + "if ( checkFieldWithDuplicate( parser, \""
489 + fieldTagName
490 + "\", "
491 + alias
492 + ", parsed ) )");
493
494 sc.add("{");
495 sc.indent();
496
497 sc.add("if ( JsonToken.START_ARRAY != parser.nextToken() )");
498 sc.add("{");
499 sc.addIndented("throw new JsonParseException( \"Expected '"
500 + fieldTagName
501 + "' data to start with an Array\", parser.getCurrentLocation() );");
502 sc.add("}");
503
504 JavaFieldMetadata javaFieldMetadata =
505 (JavaFieldMetadata) association.getMetadata(JavaFieldMetadata.ID);
506
507 String adder;
508
509 if (javaFieldMetadata.isGetter() && javaFieldMetadata.isSetter()) {
510 sc.add(type + " " + associationName + " = " + objectName + ".get" + capFieldName + "();");
511
512 sc.add("if ( " + associationName + " == null )");
513
514 sc.add("{");
515 sc.indent();
516
517 sc.add(associationName + " = " + association.getDefaultValue() + ";");
518
519 sc.add(objectName + ".set" + capFieldName + "( " + associationName + " );");
520
521 sc.unindent();
522 sc.add("}");
523
524 adder = associationName + ".add";
525 } else {
526 adder = objectName + ".add" + association.getTo();
527 }
528
529 if (!inModel && locationTracker != null) {
530 sc.add(locationTracker.getName() + " " + LOCATION_VAR + "s = " + objectName + ".get"
531 + capitalise(singular(locationField)) + "( \"" + field.getName()
532 + "\" );");
533 sc.add("if ( " + LOCATION_VAR + "s == null )");
534 sc.add("{");
535 sc.indent();
536 writeNewSetLocation(field, objectName, LOCATION_VAR + "s", sc);
537 sc.unindent();
538 sc.add("}");
539 }
540
541 sc.add("while ( JsonToken.END_ARRAY != parser.nextToken() )");
542
543 sc.add("{");
544 sc.indent();
545
546 if (inModel) {
547 sc.add(adder + "( parse" + association.getTo() + "( parser, strict" + trackingArgs + " ) );");
548 } else {
549 String key;
550 if (ModelDefault.SET.equals(type)) {
551 key = "?";
552 } else {
553 key = "Integer.valueOf(" + associationName + ".size())";
554 }
555 writePrimitiveField(
556 association,
557 association.getTo(),
558 associationName,
559 LOCATION_VAR + "s",
560 key,
561 "add",
562 sc,
563 true);
564 }
565
566 sc.unindent();
567 sc.add("}");
568
569 sc.unindent();
570 sc.add("}");
571 } else {
572
573
574 sc.add(tagComparison);
575
576 sc.add("{");
577 sc.indent();
578
579 if (locationTracker != null) {
580 sc.add(locationTracker.getName() + " " + LOCATION_VAR + "s;");
581 writeNewSetLocation(field, objectName, LOCATION_VAR + "s", sc);
582 }
583
584 if (xmlAssociationMetadata.isMapExplode()) {
585 sc.add("if ( JsonToken.START_ARRAY != parser.nextToken() )");
586 sc.add("{");
587 sc.addIndented("throw new JsonParseException( \"Expected '"
588 + fieldTagName
589 + "' data to start with an Array\", parser.getCurrentLocation() );");
590 sc.add("}");
591
592 sc.add("// " + xmlAssociationMetadata.getMapStyle() + " mode.");
593
594 sc.add("while ( JsonToken.END_ARRAY != parser.nextToken() )");
595
596 sc.add("{");
597 sc.indent();
598
599 sc.add(
600 "if ( JsonToken.START_OBJECT != parser.getCurrentToken() && JsonToken.START_OBJECT != parser.nextToken() )");
601 sc.add("{");
602 sc.addIndented("throw new JsonParseException( \"Expected '"
603 + fieldTagName
604 + "' item data to start with an Object\", parser.getCurrentLocation() );");
605 sc.add("}");
606
607 sc.add("String key = null;");
608
609 sc.add("String value = null;");
610
611 sc.add("Set<String> parsedPropertiesElements = new HashSet<String>();");
612
613 sc.add("while ( JsonToken.END_OBJECT != parser.nextToken() )");
614
615 sc.add("{");
616 sc.indent();
617
618 sc.add("if ( checkFieldWithDuplicate( parser, \"key\", \"\", parsedPropertiesElements ) )");
619
620 sc.add("{");
621 sc.addIndented("parser.nextToken();");
622
623 String parserGetter = "parser.getText()";
624
625 if (xmlFieldMetadata.isTrim()) {
626 parserGetter = "getTrimmedValue( " + parserGetter + " )";
627 }
628
629 sc.addIndented("key = " + parserGetter + ";");
630 sc.add("}");
631
632 sc.add(
633 "else if ( checkFieldWithDuplicate( parser, \"value\", \"\", parsedPropertiesElements ) )");
634
635 sc.add("{");
636 sc.addIndented("parser.nextToken();");
637
638 parserGetter = "parser.getText()";
639
640 if (xmlFieldMetadata.isTrim()) {
641 parserGetter = "getTrimmedValue( " + parserGetter + " )";
642 }
643
644 sc.addIndented("value = " + parserGetter + ";");
645 sc.add("}");
646
647 sc.add("else");
648
649 sc.add("{");
650 sc.addIndented("checkUnknownElement( parser, strict );");
651 sc.add("}");
652
653 sc.unindent();
654 sc.add("}");
655
656 sc.add(objectName + ".add" + capitalise(singularName) + "( key, value );");
657
658 sc.unindent();
659 sc.add("}");
660 } else {
661
662
663 sc.add("if ( JsonToken.START_OBJECT != parser.nextToken() )");
664 sc.add("{");
665 sc.addIndented("throw new JsonParseException( \"Expected '"
666 + fieldTagName
667 + "' data to start with an Object\", parser.getCurrentLocation() );");
668 sc.add("}");
669
670 sc.add("while ( JsonToken.END_OBJECT != parser.nextToken() )");
671
672 sc.add("{");
673 sc.indent();
674
675 sc.add("String key = parser.getCurrentName();");
676
677 writeNewSetLocation("key", LOCATION_VAR + "s", null, sc);
678
679 sc.add("String value = parser.nextTextValue()" + (xmlFieldMetadata.isTrim() ? ".trim()" : "")
680 + ";");
681
682 sc.add(objectName + ".add" + capitalise(singularName) + "( key, value );");
683
684 sc.unindent();
685 sc.add("}");
686 }
687
688 sc.unindent();
689 sc.add("}");
690 }
691 }
692 }
693 }
694
695 private void writePrimitiveField(
696 ModelField field,
697 String type,
698 String objectName,
699 String locatorName,
700 String locationKey,
701 String setterName,
702 JSourceCode sc,
703 boolean wrappedItem) {
704 XmlFieldMetadata xmlFieldMetadata = (XmlFieldMetadata) field.getMetadata(XmlFieldMetadata.ID);
705
706 String parserGetter = null;
707 if ("boolean".equals(type) || "Boolean".equals(type)) {
708 parserGetter = "parser.getBooleanValue()";
709 } else if ("int".equals(type) || "Integer".equals(type)) {
710 parserGetter = "parser.getIntValue()";
711 } else if ("short".equals(type) || "Short".equals(type)) {
712 parserGetter = "parser.getShortValue()";
713 } else if ("long".equals(type) || "Long".equals(type)) {
714 parserGetter = "parser.getLongValue()";
715 } else if ("double".equals(type) || "Double".equals(type)) {
716 parserGetter = "parser.getDoubleValue()";
717 } else if ("float".equals(type) || "Float".equals(type)) {
718 parserGetter = "parser.getFloatValue()";
719 } else if ("byte".equals(type)) {
720 parserGetter = "parser.getByteValue()";
721 } else if ("String".equals(type)) {
722 parserGetter = "parser.getText()";
723
724 if (xmlFieldMetadata.isTrim()) {
725 parserGetter = "getTrimmedValue( " + parserGetter + " )";
726 }
727 } else if ("DOM".equals(type)) {
728 requiresDomSupport = true;
729 parserGetter = "parser.readValueAsTree()";
730 } else {
731 throw new IllegalArgumentException("Unknown type "
732 + type
733 + " for field "
734 + field.getModelClass().getName()
735 + "."
736 + field.getName());
737 }
738
739 String keyCapture = "";
740 writeNewLocation(null, sc);
741 if (locationTracker != null && "?".equals(locationKey)) {
742 sc.add("Object _key;");
743 locationKey = "_key";
744 keyCapture = "_key = ";
745 } else {
746 writeSetLocation(locationKey, locatorName, null, sc);
747 }
748
749
750 if (!wrappedItem) {
751 sc.add("parser.nextToken();");
752 }
753
754 sc.add(objectName + "." + setterName + "( " + keyCapture + parserGetter + " );");
755
756 if (!keyCapture.isEmpty()) {
757 writeSetLocation(locationKey, locatorName, null, sc);
758 }
759 }
760
761 private void writeHelpers(JClass jClass) {
762 JMethod method = new JMethod("getTrimmedValue", new JClass("String"), null);
763 method.getModifiers().makePrivate();
764
765 method.addParameter(new JParameter(new JClass("String"), "s"));
766
767 JSourceCode sc = method.getSourceCode();
768
769 sc.add("if ( s != null )");
770
771 sc.add("{");
772 sc.addIndented("s = s.trim();");
773 sc.add("}");
774
775 sc.add("return s;");
776
777 jClass.addMethod(method);
778
779
780
781 method = new JMethod("getRequiredAttributeValue", new JClass("String"), null);
782 method.addException(new JClass("JsonParseException"));
783 method.getModifiers().makePrivate();
784
785 method.addParameter(new JParameter(new JClass("String"), "s"));
786 method.addParameter(new JParameter(new JClass("String"), "attribute"));
787 method.addParameter(new JParameter(new JClass("JsonParser"), "parser"));
788 method.addParameter(new JParameter(JClass.BOOLEAN, "strict"));
789
790 sc = method.getSourceCode();
791
792 sc.add("if ( s == null )");
793
794 sc.add("{");
795 sc.indent();
796
797 sc.add("if ( strict )");
798
799 sc.add("{");
800 sc.addIndented(
801 "throw new JsonParseException( \"Missing required value for attribute '\" + attribute + \"'\", parser.getCurrentLocation() );");
802 sc.add("}");
803
804 sc.unindent();
805 sc.add("}");
806
807 sc.add("return s;");
808
809 jClass.addMethod(method);
810
811
812
813 method = new JMethod("checkFieldWithDuplicate", JType.BOOLEAN, null);
814 method.getModifiers().makePrivate();
815
816 method.addParameter(new JParameter(new JClass("JsonParser"), "parser"));
817 method.addParameter(new JParameter(new JClass("String"), "tagName"));
818 method.addParameter(new JParameter(new JClass("String"), "alias"));
819 method.addParameter(new JParameter(new JClass("Set"), "parsed"));
820 method.addException(new JClass("IOException"));
821
822 sc = method.getSourceCode();
823
824 sc.add("String currentName = parser.getCurrentName();");
825
826 sc.add("");
827
828 sc.add("if ( !( currentName.equals( tagName ) || currentName.equals( alias ) ) )");
829
830 sc.add("{");
831 sc.addIndented("return false;");
832 sc.add("}");
833
834 sc.add("if ( !parsed.add( tagName ) )");
835
836 sc.add("{");
837 sc.addIndented(
838 "throw new JsonParseException( \"Duplicated tag: '\" + tagName + \"'\", parser.getCurrentLocation() );");
839 sc.add("}");
840
841 sc.add("return true;");
842
843 jClass.addMethod(method);
844
845
846
847 method = new JMethod("checkUnknownElement", null, null);
848 method.getModifiers().makePrivate();
849
850 method.addParameter(new JParameter(new JClass("JsonParser"), "parser"));
851 method.addParameter(new JParameter(JType.BOOLEAN, "strict"));
852 method.addException(new JClass("IOException"));
853
854 sc = method.getSourceCode();
855
856 sc.add("if ( strict )");
857
858 sc.add("{");
859 sc.addIndented(
860 "throw new JsonParseException( \"Unrecognised tag: '\" + parser.getCurrentName() + \"'\", parser.getCurrentLocation() );");
861 sc.add("}");
862
863 sc.add("");
864
865 sc.add("for ( int unrecognizedTagCount = 1; unrecognizedTagCount > 0; )");
866 sc.add("{");
867 sc.indent();
868 sc.add("JsonToken eventType = parser.nextToken();");
869 sc.add("if ( eventType == JsonToken.START_OBJECT )");
870 sc.add("{");
871 sc.addIndented("unrecognizedTagCount++;");
872 sc.add("}");
873 sc.add("else if ( eventType == JsonToken.END_OBJECT )");
874 sc.add("{");
875 sc.addIndented("unrecognizedTagCount--;");
876 sc.add("}");
877 sc.unindent();
878 sc.add("}");
879
880 jClass.addMethod(method);
881
882
883
884 method = new JMethod("checkUnknownAttribute", null, null);
885 method.getModifiers().makePrivate();
886
887 method.addParameter(new JParameter(new JClass("JsonParser"), "parser"));
888 method.addParameter(new JParameter(new JClass("String"), "attribute"));
889 method.addParameter(new JParameter(new JClass("String"), "tagName"));
890 method.addParameter(new JParameter(JType.BOOLEAN, "strict"));
891 method.addException(new JClass("IOException"));
892
893 sc = method.getSourceCode();
894
895 if (strictXmlAttributes) {
896 sc.add(
897 "// strictXmlAttributes = true for model: if strict == true, not only elements are checked but attributes too");
898 sc.add("if ( strict )");
899
900 sc.add("{");
901 sc.addIndented(
902 "throw new JsonParseException( \"Unknown attribute '\" + attribute + \"' for tag '\" + tagName + \"'\", parser.getCurrentLocation() );");
903 sc.add("}");
904 } else {
905 sc.add(
906 "// strictXmlAttributes = false for model: always ignore unknown XML attribute, even if strict == true");
907 }
908
909 jClass.addMethod(method);
910 }
911
912 private void addTrackingParameters(JMethod method) {
913 if (sourceTracker != null) {
914 method.addParameter(new JParameter(new JClass(sourceTracker.getName()), SOURCE_PARAM));
915 }
916 }
917
918 private void writeNewSetLocation(ModelField field, String objectName, String trackerVariable, JSourceCode sc) {
919 writeNewSetLocation("\"" + field.getName() + "\"", objectName, trackerVariable, sc);
920 }
921
922 private void writeNewSetLocation(String key, String objectName, String trackerVariable, JSourceCode sc) {
923 writeNewLocation(trackerVariable, sc);
924 writeSetLocation(key, objectName, trackerVariable, sc);
925 }
926
927 private void writeNewLocation(String trackerVariable, JSourceCode sc) {
928 if (locationTracker == null) {
929 return;
930 }
931
932 String constr = "new " + locationTracker.getName() + "( parser.getLineNumber(), parser.getColumnNumber()";
933 constr += (sourceTracker != null) ? ", " + SOURCE_PARAM : "";
934 constr += " )";
935
936 sc.add(((trackerVariable != null) ? trackerVariable : LOCATION_VAR) + " = " + constr + ";");
937 }
938
939 private void writeSetLocation(String key, String objectName, String trackerVariable, JSourceCode sc) {
940 if (locationTracker == null) {
941 return;
942 }
943
944 String variable = (trackerVariable != null) ? trackerVariable : LOCATION_VAR;
945
946 sc.add(objectName + ".set" + capitalise(singular(locationField)) + "( " + key + ", " + variable + " );");
947 }
948 }