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.Properties;
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 public void generate(Model model, Properties parameters) throws ModelloException {
78 initialize(model, parameters);
79
80 requiresDomSupport = false;
81 locationTracker = sourceTracker = null;
82 trackingArgs = locationField = "";
83
84 if (isLocationTracking()) {
85 locationTracker = model.getLocationTracker(getGeneratedVersion());
86 if (locationTracker == null) {
87 throw new ModelloException("No model class has been marked as location tracker"
88 + " via the attribute locationTracker=\"locations\""
89 + ", cannot generate extended reader.");
90 }
91
92 locationField =
93 ((ModelClassMetadata) locationTracker.getMetadata(ModelClassMetadata.ID)).getLocationTracker();
94
95 sourceTracker = model.getSourceTracker(getGeneratedVersion());
96
97 if (sourceTracker != null) {
98 trackingArgs += ", " + SOURCE_PARAM;
99 }
100 }
101
102 try {
103 generateJacksonReader();
104 } catch (IOException ex) {
105 throw new ModelloException("Exception while generating Jackson Reader.", ex);
106 }
107 }
108
109 private void writeAllClassesReaders(Model objectModel, JClass jClass) {
110 ModelClass root = objectModel.getClass(objectModel.getRoot(getGeneratedVersion()), getGeneratedVersion());
111
112 for (ModelClass clazz : getClasses(objectModel)) {
113 if (isTrackingSupport(clazz)) {
114 continue;
115 }
116
117 writeClassReaders(clazz, jClass, root.getName().equals(clazz.getName()));
118 }
119 }
120
121 private void writeClassReaders(ModelClass modelClass, JClass jClass, boolean rootElement) {
122 JavaClassMetadata javaClassMetadata =
123 (JavaClassMetadata) modelClass.getMetadata(JavaClassMetadata.class.getName());
124
125
126 if (javaClassMetadata.isAbstract()) {
127 return;
128 }
129
130 XmlClassMetadata xmlClassMetadata = (XmlClassMetadata) modelClass.getMetadata(XmlClassMetadata.ID);
131 if (!rootElement && !xmlClassMetadata.isStandaloneRead()) {
132 return;
133 }
134
135 String className = modelClass.getName();
136
137 String capClassName = capitalise(className);
138
139 String readerMethodName = "read";
140 if (!rootElement) {
141 readerMethodName += capClassName;
142 }
143
144
145
146
147
148 JMethod unmarshall = new JMethod(readerMethodName, new JClass(className), null);
149 unmarshall.getModifiers().makePrivate();
150
151 unmarshall.addParameter(new JParameter(new JClass("JsonParser"), "parser"));
152 unmarshall.addParameter(new JParameter(JClass.BOOLEAN, "strict"));
153 addTrackingParameters(unmarshall);
154
155 unmarshall.addException(new JClass("IOException"));
156
157 JSourceCode sc = unmarshall.getSourceCode();
158
159 String variableName = uncapitalise(className);
160
161 sc.add(className + ' ' + variableName + " = parse" + capClassName + "( parser, strict" + trackingArgs + " );");
162
163 if (rootElement) {
164
165
166 }
167
168 sc.add("return " + variableName + ';');
169
170 jClass.addMethod(unmarshall);
171
172
173
174
175
176 unmarshall = new JMethod(readerMethodName, new JClass(className), null);
177
178 unmarshall.addParameter(new JParameter(new JClass("Reader"), "reader"));
179 unmarshall.addParameter(new JParameter(JClass.BOOLEAN, "strict"));
180 addTrackingParameters(unmarshall);
181
182 unmarshall.addException(new JClass("IOException"));
183
184 sc = unmarshall.getSourceCode();
185
186 sc.add("JsonParser parser = factory.createParser( reader );");
187
188 sc.add("return " + readerMethodName + "( parser, strict );");
189
190 jClass.addMethod(unmarshall);
191 unmarshall = new JMethod(readerMethodName, new JClass(className), null);
192
193 unmarshall.addParameter(new JParameter(new JClass("Reader"), "reader"));
194
195 unmarshall.addException(new JClass("IOException"));
196
197 sc = unmarshall.getSourceCode();
198 sc.add("return " + readerMethodName + "( reader, true );");
199
200 jClass.addMethod(unmarshall);
201
202
203
204
205
206 unmarshall = new JMethod(readerMethodName, new JClass(className), null);
207
208 unmarshall.addParameter(new JParameter(new JClass("InputStream"), "in"));
209 unmarshall.addParameter(new JParameter(JClass.BOOLEAN, "strict"));
210 addTrackingParameters(unmarshall);
211
212 unmarshall.addException(new JClass("IOException"));
213
214 sc = unmarshall.getSourceCode();
215
216 sc.add("return " + readerMethodName + "( new InputStreamReader( in ), strict" + trackingArgs + " );");
217
218 jClass.addMethod(unmarshall);
219 unmarshall = new JMethod(readerMethodName, new JClass(className), null);
220
221 unmarshall.addParameter(new JParameter(new JClass("InputStream"), "in"));
222
223 unmarshall.addException(new JClass("IOException"));
224
225 sc = unmarshall.getSourceCode();
226
227 sc.add("return " + readerMethodName + "( in, true );");
228
229 jClass.addMethod(unmarshall);
230
231
232 }
233
234 private void generateJacksonReader() throws ModelloException, IOException {
235 Model objectModel = getModel();
236
237 String packageName =
238 objectModel.getDefaultPackageName(isPackageWithVersion(), getGeneratedVersion()) + ".io.jackson";
239
240 String unmarshallerName = getFileName("JacksonReader" + (isLocationTracking() ? "Ex" : ""));
241
242 JSourceWriter sourceWriter = newJSourceWriter(packageName, unmarshallerName);
243
244 JClass jClass = new JClass(packageName + '.' + unmarshallerName);
245 initHeader(jClass);
246 suppressAllWarnings(objectModel, jClass);
247
248 jClass.addImport("com.fasterxml.jackson.core.JsonFactory");
249 jClass.addImport("com.fasterxml.jackson.core.JsonParser");
250 jClass.addImport("com.fasterxml.jackson.core.JsonParser.Feature");
251 jClass.addImport("com.fasterxml.jackson.core.JsonParseException");
252 jClass.addImport("com.fasterxml.jackson.core.JsonToken");
253 jClass.addImport("java.io.InputStream");
254 jClass.addImport("java.io.InputStreamReader");
255 jClass.addImport("java.io.IOException");
256 jClass.addImport("java.io.Reader");
257 jClass.addImport("java.text.DateFormat");
258 jClass.addImport("java.util.Set");
259 jClass.addImport("java.util.HashSet");
260
261 addModelImports(jClass, null);
262
263 JField factoryField = new JField(new JClass("JsonFactory"), "factory");
264 factoryField.getModifiers().setFinal(true);
265 factoryField.setInitString("new JsonFactory()");
266 jClass.addField(factoryField);
267
268 JConstructor jacksonReaderConstructor = new JConstructor(jClass);
269 JSourceCode sc = jacksonReaderConstructor.getSourceCode();
270 sc.add("factory.enable( Feature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER );");
271 sc.add("factory.enable( Feature.ALLOW_COMMENTS );");
272 sc.add("factory.enable( Feature.ALLOW_NON_NUMERIC_NUMBERS );");
273 sc.add("factory.enable( Feature.ALLOW_NUMERIC_LEADING_ZEROS );");
274 sc.add("factory.enable( Feature.ALLOW_SINGLE_QUOTES );");
275 sc.add("factory.enable( Feature.ALLOW_UNQUOTED_CONTROL_CHARS );");
276 sc.add("factory.enable( Feature.ALLOW_UNQUOTED_FIELD_NAMES );");
277
278 jClass.addConstructor(jacksonReaderConstructor);
279
280
281
282
283
284 writeAllClassesParser(objectModel, jClass);
285
286
287
288
289
290 writeAllClassesReaders(objectModel, jClass);
291
292
293
294
295
296 writeHelpers(jClass);
297
298
299
300
301
302 if (requiresDomSupport) {
303 jClass.addImport("com.fasterxml.jackson.databind.ObjectMapper");
304
305 sc.add("factory.setCodec( new ObjectMapper() );");
306 }
307
308 jClass.print(sourceWriter);
309
310 sourceWriter.close();
311 }
312
313 private void writeAllClassesParser(Model objectModel, JClass jClass) {
314 ModelClass root = objectModel.getClass(objectModel.getRoot(getGeneratedVersion()), getGeneratedVersion());
315
316 for (ModelClass clazz : getClasses(objectModel)) {
317 if (isTrackingSupport(clazz)) {
318 continue;
319 }
320
321 writeClassParser(clazz, jClass, root.getName().equals(clazz.getName()));
322 }
323 }
324
325 private void writeClassParser(ModelClass modelClass, JClass jClass, boolean rootElement) {
326 JavaClassMetadata javaClassMetadata =
327 (JavaClassMetadata) modelClass.getMetadata(JavaClassMetadata.class.getName());
328
329
330 if (javaClassMetadata.isAbstract()) {
331 return;
332 }
333
334 String className = modelClass.getName();
335
336 String capClassName = capitalise(className);
337
338 String uncapClassName = uncapitalise(className);
339
340 JMethod unmarshall = new JMethod("parse" + capClassName, new JClass(className), null);
341 unmarshall.getModifiers().makePrivate();
342
343 unmarshall.addParameter(new JParameter(new JClass("JsonParser"), "parser"));
344 unmarshall.addParameter(new JParameter(JClass.BOOLEAN, "strict"));
345 addTrackingParameters(unmarshall);
346
347 unmarshall.addException(new JClass("IOException"));
348
349 JSourceCode sc = unmarshall.getSourceCode();
350
351 sc.add(
352 "if ( JsonToken.START_OBJECT != parser.getCurrentToken() && JsonToken.START_OBJECT != parser.nextToken() )");
353 sc.add("{");
354 sc.addIndented("throw new JsonParseException( \"Expected '"
355 + className
356 + "' data to start with an Object\", parser.getCurrentLocation() );");
357 sc.add("}");
358
359 sc.add(className + " " + uncapClassName + " = new " + className + "();");
360
361 if (locationTracker != null) {
362 sc.add(locationTracker.getName() + " " + LOCATION_VAR + ";");
363 writeNewSetLocation("\"\"", uncapClassName, null, sc);
364 }
365
366 List<ModelField> modelFields = getFieldsForXml(modelClass, getGeneratedVersion());
367
368 {
369
370
371 sc.add("Set<String> parsed = new HashSet<String>();");
372
373 sc.add("while ( JsonToken.END_OBJECT != parser.nextToken() )");
374
375 sc.add("{");
376 sc.indent();
377
378 boolean addElse = false;
379
380 for (ModelField field : modelFields) {
381 XmlFieldMetadata xmlFieldMetadata = (XmlFieldMetadata) field.getMetadata(XmlFieldMetadata.ID);
382
383 processField(field, xmlFieldMetadata, addElse, sc, uncapClassName, jClass);
384
385 addElse = true;
386 }
387
388 if (addElse) {
389 sc.add("else");
390
391 sc.add("{");
392 sc.indent();
393 }
394
395 sc.add("checkUnknownElement( parser, strict );");
396
397 if (addElse) {
398 sc.unindent();
399 sc.add("}");
400 }
401
402 sc.unindent();
403 sc.add("}");
404 }
405
406 sc.add("return " + uncapClassName + ";");
407
408 jClass.addMethod(unmarshall);
409 }
410
411
412
413
414
415
416
417
418
419
420
421 private void processField(
422 ModelField field,
423 XmlFieldMetadata xmlFieldMetadata,
424 boolean addElse,
425 JSourceCode sc,
426 String objectName,
427 JClass jClass) {
428 String fieldTagName = resolveTagName(field, xmlFieldMetadata);
429
430 String capFieldName = capitalise(field.getName());
431
432 String singularName = singular(field.getName());
433
434 String alias;
435 if (StringUtils.isEmpty(field.getAlias())) {
436 alias = "null";
437 } else {
438 alias = "\"" + field.getAlias() + "\"";
439 }
440
441 String tagComparison = (addElse ? "else " : "") + "if ( checkFieldWithDuplicate( parser, \"" + fieldTagName
442 + "\", " + alias + ", parsed ) )";
443
444 if (!(field instanceof ModelAssociation)) {
445 sc.add(tagComparison);
446
447 sc.add("{");
448
449 sc.indent();
450
451 writePrimitiveField(
452 field,
453 field.getType(),
454 objectName,
455 objectName,
456 "\"" + field.getName() + "\"",
457 "set" + capFieldName,
458 sc,
459 false);
460
461 sc.unindent();
462 sc.add("}");
463 } else {
464 ModelAssociation association = (ModelAssociation) field;
465
466 String associationName = association.getName();
467
468 if (association.isOneMultiplicity()) {
469 sc.add(tagComparison);
470
471 sc.add("{");
472 sc.addIndented(objectName + ".set" + capFieldName + "( parse" + association.getTo() + "( parser, strict"
473 + trackingArgs + " ) );");
474 sc.add("}");
475 } else {
476
477
478 XmlAssociationMetadata xmlAssociationMetadata =
479 (XmlAssociationMetadata) association.getAssociationMetadata(XmlAssociationMetadata.ID);
480
481 String type = association.getType();
482
483 if (ModelDefault.LIST.equals(type) || ModelDefault.SET.equals(type)) {
484 boolean inModel = isClassInModel(
485 association.getTo(), field.getModelClass().getModel());
486
487 sc.add((addElse ? "else " : "") + "if ( checkFieldWithDuplicate( parser, \""
488 + fieldTagName
489 + "\", "
490 + alias
491 + ", parsed ) )");
492
493 sc.add("{");
494 sc.indent();
495
496 sc.add("if ( JsonToken.START_ARRAY != parser.nextToken() )");
497 sc.add("{");
498 sc.addIndented("throw new JsonParseException( \"Expected '"
499 + fieldTagName
500 + "' data to start with an Array\", parser.getCurrentLocation() );");
501 sc.add("}");
502
503 JavaFieldMetadata javaFieldMetadata =
504 (JavaFieldMetadata) association.getMetadata(JavaFieldMetadata.ID);
505
506 String adder;
507
508 if (javaFieldMetadata.isGetter() && javaFieldMetadata.isSetter()) {
509 sc.add(type + " " + associationName + " = " + objectName + ".get" + capFieldName + "();");
510
511 sc.add("if ( " + associationName + " == null )");
512
513 sc.add("{");
514 sc.indent();
515
516 sc.add(associationName + " = " + association.getDefaultValue() + ";");
517
518 sc.add(objectName + ".set" + capFieldName + "( " + associationName + " );");
519
520 sc.unindent();
521 sc.add("}");
522
523 adder = associationName + ".add";
524 } else {
525 adder = objectName + ".add" + association.getTo();
526 }
527
528 if (!inModel && locationTracker != null) {
529 sc.add(locationTracker.getName() + " " + LOCATION_VAR + "s = " + objectName + ".get"
530 + capitalise(singular(locationField)) + "( \"" + field.getName()
531 + "\" );");
532 sc.add("if ( " + LOCATION_VAR + "s == null )");
533 sc.add("{");
534 sc.indent();
535 writeNewSetLocation(field, objectName, LOCATION_VAR + "s", sc);
536 sc.unindent();
537 sc.add("}");
538 }
539
540 sc.add("while ( JsonToken.END_ARRAY != parser.nextToken() )");
541
542 sc.add("{");
543 sc.indent();
544
545 if (inModel) {
546 sc.add(adder + "( parse" + association.getTo() + "( parser, strict" + trackingArgs + " ) );");
547 } else {
548 String key;
549 if (ModelDefault.SET.equals(type)) {
550 key = "?";
551 } else {
552 key = (hasJavaSourceSupport(5) ? "Integer.valueOf" : "new java.lang.Integer") + "( "
553 + 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.length() > 0) {
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 }