1 package org.codehaus.modello.plugin.snakeyaml;
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.JMethod;
39 import org.codehaus.modello.plugin.java.javasource.JParameter;
40 import org.codehaus.modello.plugin.java.javasource.JSourceCode;
41 import org.codehaus.modello.plugin.java.javasource.JSourceWriter;
42 import org.codehaus.modello.plugin.java.javasource.JType;
43 import org.codehaus.modello.plugin.java.metadata.JavaClassMetadata;
44 import org.codehaus.modello.plugin.java.metadata.JavaFieldMetadata;
45 import org.codehaus.modello.plugin.model.ModelClassMetadata;
46 import org.codehaus.modello.plugins.xml.metadata.XmlAssociationMetadata;
47 import org.codehaus.modello.plugins.xml.metadata.XmlClassMetadata;
48 import org.codehaus.modello.plugins.xml.metadata.XmlFieldMetadata;
49 import org.codehaus.plexus.util.StringUtils;
50
51
52
53
54 @Named("snakeyaml-reader")
55 public class SnakeYamlReaderGenerator extends AbstractSnakeYamlGenerator {
56
57 private static final String SOURCE_PARAM = "source";
58
59 private static final String LOCATION_VAR = "_location";
60
61 private ModelClass locationTracker;
62
63 private String locationField;
64
65 private ModelClass sourceTracker;
66
67 private String trackingArgs;
68
69 protected boolean isLocationTracking() {
70 return false;
71 }
72
73 public void generate(Model model, Properties parameters) throws ModelloException {
74 initialize(model, parameters);
75
76 locationTracker = sourceTracker = null;
77 trackingArgs = locationField = "";
78
79 if (isLocationTracking()) {
80 locationTracker = model.getLocationTracker(getGeneratedVersion());
81 if (locationTracker == null) {
82 throw new ModelloException("No model class has been marked as location tracker"
83 + " via the attribute locationTracker=\"locations\""
84 + ", cannot generate extended reader.");
85 }
86
87 locationField =
88 ((ModelClassMetadata) locationTracker.getMetadata(ModelClassMetadata.ID)).getLocationTracker();
89
90 sourceTracker = model.getSourceTracker(getGeneratedVersion());
91
92 if (sourceTracker != null) {
93 trackingArgs += ", " + SOURCE_PARAM;
94 }
95 }
96
97 try {
98 generateSnakeYamlReader();
99 } catch (IOException ex) {
100 throw new ModelloException("Exception while generating SnakeYaml Reader.", ex);
101 }
102 }
103
104 private void writeAllClassesReaders(Model objectModel, JClass jClass) {
105 ModelClass root = objectModel.getClass(objectModel.getRoot(getGeneratedVersion()), getGeneratedVersion());
106
107 for (ModelClass clazz : getClasses(objectModel)) {
108 if (isTrackingSupport(clazz)) {
109 continue;
110 }
111
112 writeClassReaders(clazz, jClass, root.getName().equals(clazz.getName()));
113 }
114 }
115
116 private void writeClassReaders(ModelClass modelClass, JClass jClass, boolean rootElement) {
117 JavaClassMetadata javaClassMetadata =
118 (JavaClassMetadata) modelClass.getMetadata(JavaClassMetadata.class.getName());
119
120
121 if (javaClassMetadata.isAbstract()) {
122 return;
123 }
124
125 XmlClassMetadata xmlClassMetadata = (XmlClassMetadata) modelClass.getMetadata(XmlClassMetadata.ID);
126 if (!rootElement && !xmlClassMetadata.isStandaloneRead()) {
127 return;
128 }
129
130 String className = modelClass.getName();
131
132 String capClassName = capitalise(className);
133
134 String readerMethodName = "read";
135 if (!rootElement) {
136 readerMethodName += capClassName;
137 }
138
139
140
141
142
143 JMethod unmarshall = new JMethod(readerMethodName, new JClass(className), null);
144 unmarshall.getModifiers().makePrivate();
145
146 unmarshall.addParameter(new JParameter(new JClass("Parser"), "parser"));
147 unmarshall.addParameter(new JParameter(JClass.BOOLEAN, "strict"));
148 addTrackingParameters(unmarshall);
149
150 unmarshall.addException(new JClass("IOException"));
151
152 JSourceCode sc = unmarshall.getSourceCode();
153
154 String variableName = uncapitalise(className);
155
156 sc.add("Event event;");
157
158 sc.add("if ( !( event = parser.getEvent() ).is( Event.ID.StreamStart ) )");
159 sc.add("{");
160 sc.addIndented(
161 "throw new ParserException( \"Expected Stream Start event\", event.getStartMark(), \"\", null );");
162 sc.add("}");
163
164 sc.add("if ( !( event = parser.getEvent() ).is( Event.ID.DocumentStart ) )");
165 sc.add("{");
166 sc.addIndented(
167 "throw new ParserException( \"Expected Document Start event\", event.getStartMark(), \"\", null );");
168 sc.add("}");
169
170 sc.add("");
171
172 sc.add(className + ' ' + variableName + " = parse" + capClassName + "( parser, strict" + trackingArgs + " );");
173
174 if (rootElement) {
175
176
177 }
178
179 sc.add("");
180
181 sc.add("if ( !( event = parser.getEvent() ).is( Event.ID.DocumentEnd ) )");
182 sc.add("{");
183 sc.addIndented(
184 "throw new ParserException( \"Expected Document End event\", event.getStartMark(), \"\", null );");
185 sc.add("}");
186
187 sc.add("if ( !( event = parser.getEvent() ).is( Event.ID.StreamEnd ) )");
188 sc.add("{");
189 sc.addIndented("throw new ParserException( \"Expected Stream End event\", event.getStartMark(), \"\", null );");
190 sc.add("}");
191
192 sc.add("");
193
194 sc.add("return " + variableName + ';');
195
196 jClass.addMethod(unmarshall);
197
198
199
200
201
202 unmarshall = new JMethod(readerMethodName, new JClass(className), null);
203
204 unmarshall.addParameter(new JParameter(new JClass("Reader"), "reader"));
205 unmarshall.addParameter(new JParameter(JClass.BOOLEAN, "strict"));
206 addTrackingParameters(unmarshall);
207
208 unmarshall.addException(new JClass("IOException"));
209
210 sc = unmarshall.getSourceCode();
211
212 sc.add("Parser parser = new ParserImpl( new StreamReader( reader ) );");
213
214 sc.add("return " + readerMethodName + "( parser, strict );");
215
216 jClass.addMethod(unmarshall);
217
218 unmarshall = new JMethod(readerMethodName, new JClass(className), null);
219
220 unmarshall.addParameter(new JParameter(new JClass("Reader"), "reader"));
221
222 unmarshall.addException(new JClass("IOException"));
223
224 sc = unmarshall.getSourceCode();
225 sc.add("return " + readerMethodName + "( reader, true );");
226
227 jClass.addMethod(unmarshall);
228
229
230
231
232
233 unmarshall = new JMethod(readerMethodName, new JClass(className), null);
234
235 unmarshall.addParameter(new JParameter(new JClass("InputStream"), "in"));
236 unmarshall.addParameter(new JParameter(JClass.BOOLEAN, "strict"));
237 addTrackingParameters(unmarshall);
238
239 unmarshall.addException(new JClass("IOException"));
240
241 sc = unmarshall.getSourceCode();
242
243 sc.add("return " + readerMethodName + "( new InputStreamReader( in ), strict" + trackingArgs + " );");
244
245 jClass.addMethod(unmarshall);
246 unmarshall = new JMethod(readerMethodName, new JClass(className), null);
247
248 unmarshall.addParameter(new JParameter(new JClass("InputStream"), "in"));
249
250 unmarshall.addException(new JClass("IOException"));
251
252 sc = unmarshall.getSourceCode();
253
254 sc.add("return " + readerMethodName + "( in, true );");
255
256 jClass.addMethod(unmarshall);
257
258
259 }
260
261 private void generateSnakeYamlReader() throws ModelloException, IOException {
262 Model objectModel = getModel();
263
264 String packageName =
265 objectModel.getDefaultPackageName(isPackageWithVersion(), getGeneratedVersion()) + ".io.snakeyaml";
266
267 String unmarshallerName = getFileName("SnakeYamlReader" + (isLocationTracking() ? "Ex" : ""));
268
269 JSourceWriter sourceWriter = newJSourceWriter(packageName, unmarshallerName);
270
271 JClass jClass = new JClass(packageName + '.' + unmarshallerName);
272 initHeader(jClass);
273 suppressAllWarnings(objectModel, jClass);
274
275 jClass.addImport("org.yaml.snakeyaml.events.DocumentEndEvent");
276 jClass.addImport("org.yaml.snakeyaml.events.DocumentStartEvent");
277 jClass.addImport("org.yaml.snakeyaml.events.Event");
278 jClass.addImport("org.yaml.snakeyaml.events.ImplicitTuple");
279 jClass.addImport("org.yaml.snakeyaml.events.MappingEndEvent");
280 jClass.addImport("org.yaml.snakeyaml.events.MappingStartEvent");
281 jClass.addImport("org.yaml.snakeyaml.events.ScalarEvent");
282 jClass.addImport("org.yaml.snakeyaml.events.SequenceEndEvent");
283 jClass.addImport("org.yaml.snakeyaml.events.SequenceStartEvent");
284 jClass.addImport("org.yaml.snakeyaml.events.StreamEndEvent");
285 jClass.addImport("org.yaml.snakeyaml.events.StreamStartEvent");
286 jClass.addImport("org.yaml.snakeyaml.parser.Parser");
287 jClass.addImport("org.yaml.snakeyaml.parser.ParserException");
288 jClass.addImport("org.yaml.snakeyaml.parser.ParserImpl");
289 jClass.addImport("org.yaml.snakeyaml.reader.StreamReader");
290 jClass.addImport("java.io.InputStream");
291 jClass.addImport("java.io.InputStreamReader");
292 jClass.addImport("java.io.IOException");
293 jClass.addImport("java.io.Reader");
294 jClass.addImport("java.text.DateFormat");
295 jClass.addImport("java.util.Set");
296 jClass.addImport("java.util.HashSet");
297
298 addModelImports(jClass, null);
299
300
301
302
303
304 writeAllClassesParser(objectModel, jClass);
305
306
307
308
309
310 writeAllClassesReaders(objectModel, jClass);
311
312
313
314
315
316 writeHelpers(jClass);
317
318
319
320
321
322 jClass.print(sourceWriter);
323
324 sourceWriter.close();
325 }
326
327 private void writeAllClassesParser(Model objectModel, JClass jClass) {
328 ModelClass root = objectModel.getClass(objectModel.getRoot(getGeneratedVersion()), getGeneratedVersion());
329
330 for (ModelClass clazz : getClasses(objectModel)) {
331 if (isTrackingSupport(clazz)) {
332 continue;
333 }
334
335 writeClassParser(clazz, jClass, root.getName().equals(clazz.getName()));
336 }
337 }
338
339 private void writeClassParser(ModelClass modelClass, JClass jClass, boolean rootElement) {
340 JavaClassMetadata javaClassMetadata =
341 (JavaClassMetadata) modelClass.getMetadata(JavaClassMetadata.class.getName());
342
343
344 if (javaClassMetadata.isAbstract()) {
345 return;
346 }
347
348 String className = modelClass.getName();
349
350 String capClassName = capitalise(className);
351
352 String uncapClassName = uncapitalise(className);
353
354 JMethod unmarshall = new JMethod("parse" + capClassName, new JClass(className), null);
355 unmarshall.getModifiers().makePrivate();
356
357 unmarshall.addParameter(new JParameter(new JClass("Parser"), "parser"));
358 unmarshall.addParameter(new JParameter(JClass.BOOLEAN, "strict"));
359 addTrackingParameters(unmarshall);
360
361 unmarshall.addException(new JClass("IOException"));
362
363 JSourceCode sc = unmarshall.getSourceCode();
364
365 sc.add("Event event = parser.getEvent();");
366
367 sc.add("");
368
369 sc.add("if ( !event.is( Event.ID.MappingStart ) )");
370 sc.add("{");
371 sc.addIndented("throw new ParserException( \"Expected '"
372 + className
373 + "' data to start with a Mapping\", event.getStartMark(), \"\", null );");
374 sc.add("}");
375
376 sc.add("");
377
378 sc.add(className + " " + uncapClassName + " = new " + className + "();");
379
380 if (locationTracker != null) {
381 sc.add(locationTracker.getName() + " " + LOCATION_VAR + ";");
382 writeNewSetLocation("\"\"", uncapClassName, null, sc);
383 }
384
385 ModelField contentField = null;
386
387 List<ModelField> modelFields = getFieldsForXml(modelClass, getGeneratedVersion());
388
389
390 contentField = writeClassAttributesParser(modelFields, uncapClassName, rootElement);
391
392
393 if (contentField != null) {
394 writePrimitiveField(
395 contentField,
396 contentField.getType(),
397 uncapClassName,
398 uncapClassName,
399 "\"\"",
400 "set" + capitalise(contentField.getName()),
401 sc,
402 false);
403 } else {
404
405
406 sc.add("Set<String> parsed = new HashSet<String>();");
407
408 sc.add("");
409
410 sc.add("while ( !( event = parser.getEvent() ).is( Event.ID.MappingEnd ) )");
411
412 sc.add("{");
413 sc.indent();
414
415 boolean addElse = false;
416
417 for (ModelField field : modelFields) {
418 XmlFieldMetadata xmlFieldMetadata = (XmlFieldMetadata) field.getMetadata(XmlFieldMetadata.ID);
419
420 processField(field, xmlFieldMetadata, addElse, sc, uncapClassName, jClass);
421
422 addElse = true;
423 }
424
425 if (addElse) {
426 sc.add("else");
427
428 sc.add("{");
429 sc.indent();
430 }
431
432 sc.add("checkUnknownElement( event, parser, strict );");
433
434 if (addElse) {
435 sc.unindent();
436 sc.add("}");
437 }
438
439 sc.unindent();
440 sc.add("}");
441 }
442
443 sc.add("return " + uncapClassName + ";");
444
445 jClass.addMethod(unmarshall);
446 }
447
448 private ModelField writeClassAttributesParser(
449 List<ModelField> modelFields, String objectName, boolean rootElement) {
450 ModelField contentField = null;
451
452 for (ModelField field : modelFields) {
453 XmlFieldMetadata xmlFieldMetadata = (XmlFieldMetadata) field.getMetadata(XmlFieldMetadata.ID);
454
455
456 if (xmlFieldMetadata.isContent()) {
457 contentField = field;
458 }
459 }
460
461 return contentField;
462 }
463
464
465
466
467
468
469
470
471
472
473
474 private void processField(
475 ModelField field,
476 XmlFieldMetadata xmlFieldMetadata,
477 boolean addElse,
478 JSourceCode sc,
479 String objectName,
480 JClass jClass) {
481 String fieldTagName = resolveTagName(field, xmlFieldMetadata);
482
483 String capFieldName = capitalise(field.getName());
484
485 String singularName = singular(field.getName());
486
487 String alias;
488 if (StringUtils.isEmpty(field.getAlias())) {
489 alias = "null";
490 } else {
491 alias = "\"" + field.getAlias() + "\"";
492 }
493
494 String tagComparison = (addElse ? "else " : "") + "if ( checkFieldWithDuplicate( event, \"" + fieldTagName
495 + "\", " + alias + ", parsed ) )";
496
497 if (!(field instanceof ModelAssociation)) {
498 sc.add(tagComparison);
499
500 sc.add("{");
501 sc.indent();
502
503 writePrimitiveField(
504 field,
505 field.getType(),
506 objectName,
507 objectName,
508 "\"" + field.getName() + "\"",
509 "set" + capFieldName,
510 sc,
511 false);
512
513 sc.unindent();
514 sc.add("}");
515 } else {
516 ModelAssociation association = (ModelAssociation) field;
517
518 String associationName = association.getName();
519
520 if (association.isOneMultiplicity()) {
521 sc.add(tagComparison);
522
523 sc.add("{");
524 sc.indent();
525
526
527
528 sc.add(objectName
529 + ".set"
530 + capFieldName
531 + "( parse"
532 + association.getTo()
533 + "( parser, strict"
534 + trackingArgs
535 + " ) );");
536
537 sc.unindent();
538 sc.add("}");
539 } else {
540
541
542 XmlAssociationMetadata xmlAssociationMetadata =
543 (XmlAssociationMetadata) association.getAssociationMetadata(XmlAssociationMetadata.ID);
544
545 String type = association.getType();
546
547 if (ModelDefault.LIST.equals(type) || ModelDefault.SET.equals(type)) {
548 boolean inModel = isClassInModel(
549 association.getTo(), field.getModelClass().getModel());
550
551 sc.add((addElse ? "else " : "")
552 + "if ( checkFieldWithDuplicate( event, \""
553 + fieldTagName
554 + "\", "
555 + alias
556 + ", parsed ) )");
557
558 sc.add("{");
559 sc.indent();
560
561 sc.add("if ( !parser.getEvent().is( Event.ID.SequenceStart ) )");
562 sc.add("{");
563 sc.addIndented("throw new ParserException( \"Expected '"
564 + field.getName()
565 + "' data to start with a Sequence\", event.getStartMark(), \"\", null );");
566 sc.add("}");
567
568 JavaFieldMetadata javaFieldMetadata =
569 (JavaFieldMetadata) association.getMetadata(JavaFieldMetadata.ID);
570
571 String adder;
572
573 if (javaFieldMetadata.isGetter() && javaFieldMetadata.isSetter()) {
574 sc.add(type + " " + associationName + " = " + objectName + ".get" + capFieldName + "();");
575
576 sc.add("if ( " + associationName + " == null )");
577
578 sc.add("{");
579 sc.indent();
580
581 sc.add(associationName + " = " + association.getDefaultValue() + ";");
582
583 sc.add(objectName + ".set" + capFieldName + "( " + associationName + " );");
584
585 sc.unindent();
586 sc.add("}");
587
588 adder = associationName + ".add";
589 } else {
590 adder = objectName + ".add" + association.getTo();
591 }
592
593 if (!inModel && locationTracker != null) {
594 sc.add(locationTracker.getName() + " " + LOCATION_VAR + "s = " + objectName + ".get"
595 + capitalise(singular(locationField)) + "( \"" + field.getName()
596 + "\" );");
597 sc.add("if ( " + LOCATION_VAR + "s == null )");
598 sc.add("{");
599 sc.indent();
600 writeNewSetLocation(field, objectName, LOCATION_VAR + "s", sc);
601 sc.unindent();
602 sc.add("}");
603 }
604
605 if (inModel) {
606 sc.add("while ( !parser.peekEvent().is( Event.ID.SequenceEnd ) )");
607 sc.add("{");
608
609 sc.addIndented(
610 adder + "( parse" + association.getTo() + "( parser, strict" + trackingArgs + " ) );");
611
612 sc.add("}");
613
614 sc.add("parser.getEvent();");
615 } else {
616 String key;
617 if (ModelDefault.SET.equals(type)) {
618 key = "?";
619 } else {
620 key = (hasJavaSourceSupport(5) ? "Integer.valueOf" : "new java.lang.Integer") + "( "
621 + associationName + ".size() )";
622 }
623 writePrimitiveField(
624 association,
625 association.getTo(),
626 associationName,
627 LOCATION_VAR + "s",
628 key,
629 "add",
630 sc,
631 false);
632 }
633
634 sc.unindent();
635 sc.add("}");
636 } else {
637
638
639 sc.add(tagComparison);
640
641 sc.add("{");
642 sc.indent();
643
644 if (locationTracker != null) {
645 sc.add(locationTracker.getName() + " " + LOCATION_VAR + "s;");
646 writeNewSetLocation(field, objectName, LOCATION_VAR + "s", sc);
647 }
648
649 if (xmlAssociationMetadata.isMapExplode()) {
650 sc.add("if ( !parser.getEvent().is( Event.ID.SequenceStart ) )");
651 sc.add("{");
652 sc.addIndented("throw new ParserException( \"Expected '"
653 + field.getName()
654 + "' data to start with a Sequence\", event.getStartMark(), \"\", null );");
655 sc.add("}");
656
657 sc.add("while ( !parser.peekEvent().is( Event.ID.SequenceEnd ) )");
658
659 sc.add("{");
660 sc.indent();
661
662 sc.add("event = parser.getEvent();");
663
664 sc.add("");
665
666 sc.add("if ( !event.is( Event.ID.MappingStart ) )");
667 sc.add("{");
668 sc.addIndented("throw new ParserException( \"Expected '"
669 + fieldTagName
670 + "' item data to start with a Mapping\", event.getStartMark(), \"\", null );");
671 sc.add("}");
672
673 sc.add("String key = null;");
674
675 sc.add("String value = null;");
676
677 sc.add("Set<String> parsedPropertiesElements = new HashSet<String>();");
678
679 sc.add("while ( !( event = parser.getEvent() ).is( Event.ID.MappingEnd ) )");
680
681 sc.add("{");
682 sc.indent();
683
684 sc.add("if ( checkFieldWithDuplicate( event, \"key\", \"\", parsedPropertiesElements ) )");
685 sc.add("{");
686
687 String parserGetter = "( (ScalarEvent) parser.getEvent() ).getValue()";
688 if (xmlFieldMetadata.isTrim()) {
689 parserGetter = "getTrimmedValue( " + parserGetter + " )";
690 }
691
692 sc.addIndented("key = " + parserGetter + ";");
693
694 sc.add("}");
695 sc.add(
696 "else if ( checkFieldWithDuplicate( event, \"value\", \"\", parsedPropertiesElements ) )");
697 sc.add("{");
698
699 parserGetter = "( (ScalarEvent) parser.getEvent() ).getValue()";
700 if (xmlFieldMetadata.isTrim()) {
701 parserGetter = "getTrimmedValue( " + parserGetter + " )";
702 }
703
704 sc.addIndented("value = " + parserGetter + ";");
705
706 sc.add("}");
707
708 sc.add("else");
709
710 sc.add("{");
711
712 sc.addIndented("checkUnknownElement( event, parser, strict );");
713
714 sc.add("}");
715
716 sc.unindent();
717 sc.add("}");
718
719 sc.add(objectName + ".add" + capitalise(singularName) + "( key, value );");
720
721 sc.unindent();
722 sc.add("}");
723 } else {
724
725
726 sc.add("if ( !parser.getEvent().is( Event.ID.MappingStart ) )");
727 sc.add("{");
728 sc.addIndented("throw new ParserException( \"Expected '"
729 + field.getName()
730 + "' data to start with a Mapping\", event.getStartMark(), \"\", null );");
731 sc.add("}");
732
733 sc.add("while ( !parser.peekEvent().is( Event.ID.MappingEnd ) )");
734
735 sc.add("{");
736 sc.indent();
737
738 sc.add("String key = ( (ScalarEvent) parser.getEvent() ).getValue();");
739
740 writeNewSetLocation("key", LOCATION_VAR + "s", null, sc);
741
742 sc.add("String value = ( (ScalarEvent) parser.getEvent() ).getValue()"
743 + (xmlFieldMetadata.isTrim() ? ".trim()" : "") + ";");
744
745 sc.add(objectName + ".add" + capitalise(singularName) + "( key, value );");
746
747 sc.unindent();
748 sc.add("}");
749 }
750
751 sc.add("parser.getEvent();");
752
753 sc.unindent();
754 sc.add("}");
755 }
756 }
757 }
758 }
759
760 private void writeHelpers(JClass jClass) {
761 JMethod method = new JMethod("getTrimmedValue", new JClass("String"), null);
762 method.getModifiers().makePrivate();
763
764 method.addParameter(new JParameter(new JClass("String"), "s"));
765
766 JSourceCode sc = method.getSourceCode();
767
768 sc.add("if ( s != null )");
769
770 sc.add("{");
771 sc.addIndented("s = s.trim();");
772 sc.add("}");
773
774 sc.add("return s;");
775
776 jClass.addMethod(method);
777
778
779
780 method = new JMethod("getRequiredAttributeValue", new JClass("String"), null);
781 method.addException(new JClass("ParserException"));
782 method.getModifiers().makePrivate();
783
784 method.addParameter(new JParameter(new JClass("String"), "s"));
785 method.addParameter(new JParameter(new JClass("String"), "attribute"));
786 method.addParameter(new JParameter(new JClass("Parser"), "parser"));
787 method.addParameter(new JParameter(JClass.BOOLEAN, "strict"));
788
789 sc = method.getSourceCode();
790
791 sc.add("if ( s == null )");
792
793 sc.add("{");
794 sc.indent();
795
796 sc.add("if ( strict )");
797
798 sc.add("{");
799 sc.addIndented(
800 "throw new ParserException( \"Missing required value for attribute '\" + attribute + \"'\", parser.peekEvent().getStartMark(), \"\", null );");
801 sc.add("}");
802
803 sc.unindent();
804 sc.add("}");
805
806 sc.add("return s;");
807
808 jClass.addMethod(method);
809
810
811
812 method = new JMethod("checkFieldWithDuplicate", JType.BOOLEAN, null);
813 method.getModifiers().makePrivate();
814
815 method.addParameter(new JParameter(new JClass("Event"), "event"));
816 method.addParameter(new JParameter(new JClass("String"), "tagName"));
817 method.addParameter(new JParameter(new JClass("String"), "alias"));
818 method.addParameter(new JParameter(new JClass("Set"), "parsed"));
819 method.addException(new JClass("IOException"));
820
821 sc = method.getSourceCode();
822
823 sc.add("String currentName = ( (ScalarEvent) event ).getValue();");
824
825 sc.add("");
826
827 sc.add("if ( !( currentName.equals( tagName ) || currentName.equals( alias ) ) )");
828
829 sc.add("{");
830 sc.addIndented("return false;");
831 sc.add("}");
832
833 sc.add("if ( !parsed.add( tagName ) )");
834
835 sc.add("{");
836 sc.addIndented(
837 "throw new ParserException( \"Duplicated tag: '\" + tagName + \"'\", event.getStartMark(), \"\", null );");
838 sc.add("}");
839
840 sc.add("return true;");
841
842 jClass.addMethod(method);
843
844
845
846 method = new JMethod("checkUnknownElement", null, null);
847 method.getModifiers().makePrivate();
848
849 method.addParameter(new JParameter(new JClass("Event"), "event"));
850 method.addParameter(new JParameter(new JClass("Parser"), "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 ParserException( \"Unrecognised tag: '\" + ( (ScalarEvent) event ).getValue() + \"'\", event.getStartMark(), \"\", null );");
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("event = parser.getEvent();");
869 sc.add("if ( event.is( Event.ID.MappingStart ) )");
870 sc.add("{");
871 sc.addIndented("unrecognizedTagCount++;");
872 sc.add("}");
873 sc.add("else if ( event.is( Event.ID.MappingEnd ) )");
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("Parser"), "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 ParserException( \"\", parser.peekEvent().getStartMark(), \"Unknown attribute '\" + attribute + \"' for tag '\" + tagName + \"'\", parser.peekEvent().getEndMark() );");
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
913 method = new JMethod("getBooleanValue", JType.BOOLEAN, null);
914 method.getModifiers().makePrivate();
915
916 method.addParameter(new JParameter(new JClass("String"), "s"));
917
918 sc = method.getSourceCode();
919
920 sc.add("if ( s != null )");
921
922 sc.add("{");
923 sc.addIndented("return Boolean.valueOf( s ).booleanValue();");
924 sc.add("}");
925
926 sc.add("return false;");
927
928 jClass.addMethod(method);
929
930
931
932 method = new JMethod("getCharacterValue", JType.CHAR, null);
933 method.getModifiers().makePrivate();
934
935 method.addParameter(new JParameter(new JClass("String"), "s"));
936
937 sc = method.getSourceCode();
938
939 sc.add("if ( s != null )");
940
941 sc.add("{");
942 sc.addIndented("return s.charAt( 0 );");
943 sc.add("}");
944
945 sc.add("return 0;");
946
947 jClass.addMethod(method);
948
949
950
951 method = convertNumericalType("getIntegerValue", JType.INT, "Integer.valueOf( s ).intValue()", "an integer");
952
953 jClass.addMethod(method);
954
955
956
957 method = convertNumericalType(
958 "getShortValue", JType.SHORT, "Short.valueOf( s ).shortValue()", "a short integer");
959
960 jClass.addMethod(method);
961
962
963
964 method = convertNumericalType("getByteValue", JType.BYTE, "Byte.valueOf( s ).byteValue()", "a byte");
965
966 jClass.addMethod(method);
967
968
969
970 method = convertNumericalType("getLongValue", JType.LONG, "Long.valueOf( s ).longValue()", "a long integer");
971
972 jClass.addMethod(method);
973
974
975
976 method = convertNumericalType(
977 "getFloatValue", JType.FLOAT, "Float.valueOf( s ).floatValue()", "a floating point number");
978
979 jClass.addMethod(method);
980
981
982
983 method = convertNumericalType(
984 "getDoubleValue", JType.DOUBLE, "Double.valueOf( s ).doubleValue()", "a floating point number");
985
986 jClass.addMethod(method);
987
988
989
990 method = new JMethod("getDateValue", new JClass("java.util.Date"), null);
991 method.getModifiers().makePrivate();
992
993 method.addParameter(new JParameter(new JClass("String"), "s"));
994 method.addParameter(new JParameter(new JClass("String"), "dateFormat"));
995 method.addParameter(new JParameter(new JClass("Event"), "event"));
996
997 writeDateParsingHelper(
998 method.getSourceCode(),
999 "new ParserException( \"\", event.getStartMark(), e.getMessage(), event.getEndMark() )");
1000
1001 jClass.addMethod(method);
1002
1003
1004
1005 method = new JMethod("getDefaultValue", new JClass("String"), null);
1006 method.getModifiers().makePrivate();
1007
1008 method.addParameter(new JParameter(new JClass("String"), "s"));
1009 method.addParameter(new JParameter(new JClass("String"), "v"));
1010
1011 sc = method.getSourceCode();
1012
1013 sc.add("if ( s == null )");
1014
1015 sc.add("{");
1016 sc.addIndented("s = v;");
1017 sc.add("}");
1018
1019 sc.add("return s;");
1020
1021 jClass.addMethod(method);
1022 }
1023
1024 private void addTrackingParameters(JMethod method) {
1025 if (sourceTracker != null) {
1026 method.addParameter(new JParameter(new JClass(sourceTracker.getName()), SOURCE_PARAM));
1027 }
1028 }
1029
1030 private void writeNewSetLocation(ModelField field, String objectName, String trackerVariable, JSourceCode sc) {
1031 writeNewSetLocation("\"" + field.getName() + "\"", objectName, trackerVariable, sc);
1032 }
1033
1034 private void writeNewSetLocation(String key, String objectName, String trackerVariable, JSourceCode sc) {
1035 writeNewLocation(trackerVariable, sc);
1036 writeSetLocation(key, objectName, trackerVariable, sc);
1037 }
1038
1039 private void writeNewLocation(String trackerVariable, JSourceCode sc) {
1040 if (locationTracker == null) {
1041 return;
1042 }
1043
1044 String constr = "new " + locationTracker.getName() + "( parser.getLineNumber(), parser.getColumnNumber()";
1045 constr += (sourceTracker != null) ? ", " + SOURCE_PARAM : "";
1046 constr += " )";
1047
1048 sc.add(((trackerVariable != null) ? trackerVariable : LOCATION_VAR) + " = " + constr + ";");
1049 }
1050
1051 private void writeSetLocation(String key, String objectName, String trackerVariable, JSourceCode sc) {
1052 if (locationTracker == null) {
1053 return;
1054 }
1055
1056 String variable = (trackerVariable != null) ? trackerVariable : LOCATION_VAR;
1057
1058 sc.add(objectName + ".set" + capitalise(singular(locationField)) + "( " + key + ", " + variable + " );");
1059 }
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071 private void writePrimitiveField(
1072 ModelField field,
1073 String type,
1074 String objectName,
1075 String locatorName,
1076 String locationKey,
1077 String setterName,
1078 JSourceCode sc,
1079 boolean wrappedItem) {
1080 XmlFieldMetadata xmlFieldMetadata = (XmlFieldMetadata) field.getMetadata(XmlFieldMetadata.ID);
1081
1082 String tagName = resolveTagName(field, xmlFieldMetadata);
1083
1084 String parserGetter = "( (ScalarEvent) parser.getEvent() ).getValue()";
1085
1086
1087
1088
1089
1090
1091
1092 if (field.getDefaultValue() != null) {
1093 parserGetter = "getDefaultValue( " + parserGetter + ", \"" + field.getDefaultValue() + "\" )";
1094 }
1095
1096 if (xmlFieldMetadata.isTrim()) {
1097 parserGetter = "getTrimmedValue( " + parserGetter + " )";
1098 }
1099
1100 if ("boolean".equals(type)) {
1101 sc.add(objectName + "." + setterName + "( getBooleanValue( " + parserGetter + " ) );");
1102 } else if ("char".equals(type)) {
1103 sc.add(objectName + "." + setterName + "( getCharacterValue( " + parserGetter + ", \"" + tagName
1104 + "\" ) );");
1105 } else if ("double".equals(type)) {
1106 sc.add(objectName + "." + setterName + "( getDoubleValue( " + parserGetter + ", \"" + tagName
1107 + "\", parser.peekEvent(), strict ) );");
1108 } else if ("float".equals(type)) {
1109 sc.add(objectName + "." + setterName + "( getFloatValue( " + parserGetter + ", \"" + tagName
1110 + "\", parser.peekEvent(), strict ) );");
1111 } else if ("int".equals(type)) {
1112 sc.add(objectName + "." + setterName + "( getIntegerValue( " + parserGetter + ", \"" + tagName
1113 + "\", parser.peekEvent(), strict ) );");
1114 } else if ("long".equals(type)) {
1115 sc.add(objectName + "." + setterName + "( getLongValue( " + parserGetter + ", \"" + tagName
1116 + "\", parser.peekEvent(), strict ) );");
1117 } else if ("short".equals(type)) {
1118 sc.add(objectName + "." + setterName + "( getShortValue( " + parserGetter + ", \"" + tagName
1119 + "\", parser.peekEvent(), strict ) );");
1120 } else if ("byte".equals(type)) {
1121 sc.add(objectName + "." + setterName + "( getByteValue( " + parserGetter + ", \"" + tagName
1122 + "\", parser.peekEvent(), strict ) );");
1123 } else if ("String".equals(type) || "Boolean".equals(type)) {
1124
1125 sc.add(objectName + "." + setterName + "( " + parserGetter + " );");
1126 } else if ("Date".equals(type)) {
1127 sc.add("String dateFormat = "
1128 + (xmlFieldMetadata.getFormat() != null ? "\"" + xmlFieldMetadata.getFormat() + "\"" : "null")
1129 + ";");
1130 sc.add(objectName + "." + setterName + "( getDateValue( " + parserGetter + ", \"" + tagName
1131 + "\", dateFormat, parser.peekEvent() ) );");
1132 } else {
1133 throw new IllegalArgumentException("Unknown type "
1134 + type
1135 + " for field "
1136 + field.getModelClass().getName()
1137 + "."
1138 + field.getName());
1139 }
1140 }
1141
1142 private JMethod convertNumericalType(String methodName, JType returnType, String expression, String typeDesc) {
1143 JMethod method = new JMethod(methodName, returnType, null);
1144 method.getModifiers().makePrivate();
1145
1146 method.addParameter(new JParameter(new JClass("String"), "s"));
1147 method.addParameter(new JParameter(new JClass("String"), "attribute"));
1148 method.addParameter(new JParameter(new JClass("Event"), "event"));
1149 method.addParameter(new JParameter(JType.BOOLEAN, "strict"));
1150
1151 JSourceCode sc = method.getSourceCode();
1152
1153 sc.add("if ( s != null )");
1154
1155 sc.add("{");
1156 sc.indent();
1157
1158 sc.add("try");
1159
1160 sc.add("{");
1161 sc.addIndented("return " + expression + ";");
1162 sc.add("}");
1163
1164 sc.add("catch ( NumberFormatException nfe )");
1165
1166 sc.add("{");
1167 sc.indent();
1168
1169 sc.add("if ( strict )");
1170
1171 sc.add("{");
1172 sc.addIndented(
1173 "throw new ParserException( \"\", event.getStartMark(), \"Unable to parse element '\" + attribute + \"', must be "
1174 + typeDesc
1175 + " but was '\" + s + \"'\", event.getEndMark() );");
1176 sc.add("}");
1177
1178 sc.unindent();
1179 sc.add("}");
1180
1181 sc.unindent();
1182 sc.add("}");
1183
1184 sc.add("return 0;");
1185
1186 return method;
1187 }
1188 }