1 package org.codehaus.modello.plugin.xpp3;
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.ModelloParameterConstants;
33 import org.codehaus.modello.model.Model;
34 import org.codehaus.modello.model.ModelAssociation;
35 import org.codehaus.modello.model.ModelClass;
36 import org.codehaus.modello.model.ModelDefault;
37 import org.codehaus.modello.model.ModelField;
38 import org.codehaus.modello.plugin.java.javasource.JClass;
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.JavaFieldMetadata;
46 import org.codehaus.modello.plugin.model.ModelClassMetadata;
47 import org.codehaus.modello.plugins.xml.metadata.XmlAssociationMetadata;
48 import org.codehaus.modello.plugins.xml.metadata.XmlFieldMetadata;
49 import org.codehaus.modello.plugins.xml.metadata.XmlModelMetadata;
50
51
52
53
54
55 @Named("xpp3-writer")
56 public class Xpp3WriterGenerator extends AbstractXpp3Generator {
57 private String extendedClassnameSuffix;
58
59 protected void prepareLocationTracking(JClass jClass) {
60
61 }
62
63 protected void writeLocationTracking(JSourceCode sc, String name, String key) {
64 if (isLocationTracking()) {
65 sc.add("writeLocationTracking( " + name + ", " + key + ", serializer );");
66 }
67 }
68
69 @Override
70 protected void initialize(Model model, Properties parameters) throws ModelloException {
71 super.initialize(model, parameters);
72
73 extendedClassnameSuffix = "Ex";
74 if (isLocationTracking()) {
75 extendedClassnameSuffix = parameters.getProperty(ModelloParameterConstants.EXTENDED_CLASSNAME_SUFFIX);
76 }
77 }
78
79 public void generate(Model model, Properties parameters) throws ModelloException {
80 initialize(model, parameters);
81
82 try {
83 generateXpp3Writer();
84 } catch (IOException ex) {
85 throw new ModelloException("Exception while generating XPP3 Writer.", ex);
86 }
87 }
88
89 private void generateXpp3Writer() throws ModelloException, IOException {
90 Model objectModel = getModel();
91
92 String packageName =
93 objectModel.getDefaultPackageName(isPackageWithVersion(), getGeneratedVersion()) + ".io.xpp3";
94
95 String marshallerName = getFileName("Xpp3Writer" + (isLocationTracking() ? extendedClassnameSuffix : ""));
96
97 JSourceWriter sourceWriter = newJSourceWriter(packageName, marshallerName);
98
99 JClass jClass = new JClass(packageName + '.' + marshallerName);
100 initHeader(jClass);
101 suppressAllWarnings(objectModel, jClass);
102
103 jClass.addImport("org.codehaus.plexus.util.xml.pull.XmlSerializer");
104 jClass.addImport("org.codehaus.plexus.util.xml.pull.MXSerializer");
105 jClass.addImport("java.io.OutputStream");
106 jClass.addImport("java.io.Writer");
107 jClass.addImport("java.util.Iterator");
108
109 JField namespaceField = new JField(new JClass("String"), "NAMESPACE");
110 namespaceField.getModifiers().setFinal(true);
111 namespaceField.getModifiers().setStatic(true);
112 namespaceField.setInitString("null");
113 jClass.addField(namespaceField);
114
115 JField commentField = new JField(new JClass("String"), "fileComment");
116 commentField.setInitString("null");
117 jClass.addField(commentField);
118
119
120 JMethod setComment = new JMethod("setFileComment");
121
122 setComment.addParameter(new JParameter(new JClass("String"), "fileComment"));
123 JSourceCode setCommentSourceCode = setComment.getSourceCode();
124 setCommentSourceCode.add("this.fileComment = fileComment;");
125 jClass.addMethod(setComment);
126
127 addModelImports(jClass, null);
128
129 String root = objectModel.getRoot(getGeneratedVersion());
130
131 ModelClass rootClass = objectModel.getClass(root, getGeneratedVersion());
132
133 String rootElement = resolveTagName(rootClass);
134
135
136
137
138
139 JMethod marshall = new JMethod("write");
140
141 String rootElementParameterName = uncapitalise(root);
142 marshall.addParameter(new JParameter(new JClass("Writer"), "writer"));
143 marshall.addParameter(new JParameter(new JClass(root), rootElementParameterName));
144
145 marshall.addException(new JClass("java.io.IOException"));
146
147 JSourceCode sc = marshall.getSourceCode();
148
149 sc.add("XmlSerializer serializer = new MXSerializer();");
150
151 sc.add(
152 "serializer.setProperty( \"http://xmlpull.org/v1/doc/properties.html#serializer-indentation\", \" \" );");
153
154 sc.add(
155 "serializer.setProperty( \"http://xmlpull.org/v1/doc/properties.html#serializer-line-separator\", \"\\n\" );");
156
157 sc.add("serializer.setOutput( writer );");
158
159 sc.add("serializer.startDocument( " + rootElementParameterName + ".getModelEncoding(), null );");
160
161 sc.add("write" + root + "( " + rootElementParameterName + ", \"" + rootElement + "\", serializer );");
162
163 sc.add("serializer.endDocument();");
164
165 jClass.addMethod(marshall);
166
167
168
169
170
171 marshall = new JMethod("write");
172
173 marshall.addParameter(new JParameter(new JClass("OutputStream"), "stream"));
174 marshall.addParameter(new JParameter(new JClass(root), rootElementParameterName));
175
176 marshall.addException(new JClass("java.io.IOException"));
177
178 sc = marshall.getSourceCode();
179
180 sc.add("XmlSerializer serializer = new MXSerializer();");
181
182 sc.add(
183 "serializer.setProperty( \"http://xmlpull.org/v1/doc/properties.html#serializer-indentation\", \" \" );");
184
185 sc.add(
186 "serializer.setProperty( \"http://xmlpull.org/v1/doc/properties.html#serializer-line-separator\", \"\\n\" );");
187
188 sc.add("serializer.setOutput( stream, " + rootElementParameterName + ".getModelEncoding() );");
189
190 sc.add("serializer.startDocument( " + rootElementParameterName + ".getModelEncoding(), null );");
191
192 sc.add("write" + root + "( " + rootElementParameterName + ", \"" + rootElement + "\", serializer );");
193
194 sc.add("serializer.endDocument();");
195
196 jClass.addMethod(marshall);
197
198 writeAllClasses(objectModel, jClass);
199
200 if (isLocationTracking()) {
201 prepareLocationTracking(jClass);
202 }
203
204 if (requiresDomSupport) {
205 createWriteDomMethod(jClass);
206 }
207
208 jClass.print(sourceWriter);
209
210 sourceWriter.close();
211 }
212
213 private void writeAllClasses(Model objectModel, JClass jClass) throws ModelloException {
214 for (ModelClass clazz : getClasses(objectModel)) {
215 writeClass(clazz, jClass);
216 }
217 }
218
219 private void writeClass(ModelClass modelClass, JClass jClass) throws ModelloException {
220 String className = modelClass.getName();
221
222 String uncapClassName = uncapitalise(className);
223
224 JMethod marshall = new JMethod("write" + className);
225
226 marshall.addParameter(new JParameter(new JClass(className), uncapClassName));
227 marshall.addParameter(new JParameter(new JClass("String"), "tagName"));
228 marshall.addParameter(new JParameter(new JClass("XmlSerializer"), "serializer"));
229
230 marshall.addException(new JClass("java.io.IOException"));
231
232 marshall.getModifiers().makePrivate();
233
234 JSourceCode sc = marshall.getSourceCode();
235
236 ModelClassMetadata classMetadata = (ModelClassMetadata) modelClass.getMetadata(ModelClassMetadata.ID);
237
238 String namespace = null;
239 XmlModelMetadata xmlModelMetadata =
240 (XmlModelMetadata) modelClass.getModel().getMetadata(XmlModelMetadata.ID);
241
242
243 if (classMetadata.isRootElement() && (xmlModelMetadata.getNamespace() != null)) {
244 sc.add("if ( this.fileComment != null )");
245 sc.add("{");
246 sc.add("serializer.comment(this.fileComment);");
247 sc.add("}");
248
249 namespace = xmlModelMetadata.getNamespace(getGeneratedVersion());
250 sc.add("serializer.setPrefix( \"\", \"" + namespace + "\" );");
251 }
252
253 if ((namespace != null) && (xmlModelMetadata.getSchemaLocation() != null)) {
254 String url = xmlModelMetadata.getSchemaLocation(getGeneratedVersion());
255
256 sc.add("serializer.setPrefix( \"xsi\", \"http://www.w3.org/2001/XMLSchema-instance\" );");
257
258 sc.add("serializer.startTag( NAMESPACE, tagName );");
259
260 sc.add("serializer.attribute( \"\", \"xsi:schemaLocation\", \"" + namespace + " " + url + "\" );");
261 } else {
262 sc.add("serializer.startTag( NAMESPACE, tagName );");
263 }
264
265 ModelField contentField = null;
266
267 String contentValue = null;
268
269 List<ModelField> modelFields = getFieldsForXml(modelClass, getGeneratedVersion());
270
271
272 for (ModelField field : modelFields) {
273 XmlFieldMetadata xmlFieldMetadata = (XmlFieldMetadata) field.getMetadata(XmlFieldMetadata.ID);
274
275 JavaFieldMetadata javaFieldMetadata = (JavaFieldMetadata) field.getMetadata(JavaFieldMetadata.ID);
276
277 String fieldTagName = resolveTagName(field, xmlFieldMetadata);
278
279 String type = field.getType();
280
281 String value = uncapClassName + "." + getPrefix(javaFieldMetadata) + capitalise(field.getName()) + "()";
282
283 if (xmlFieldMetadata.isContent()) {
284 contentField = field;
285 contentValue = value;
286 continue;
287 }
288
289 if (xmlFieldMetadata.isAttribute()) {
290 sc.add(getValueChecker(type, value, field));
291
292 sc.add("{");
293 sc.addIndented("serializer.attribute( NAMESPACE, \"" + fieldTagName + "\", "
294 + getValue(field.getType(), value, xmlFieldMetadata) + " );");
295 sc.add("}");
296 }
297 }
298
299 if (contentField != null) {
300 XmlFieldMetadata xmlFieldMetadata = (XmlFieldMetadata) contentField.getMetadata(XmlFieldMetadata.ID);
301 sc.add("serializer.text( " + getValue(contentField.getType(), contentValue, xmlFieldMetadata) + " );");
302 }
303
304
305 for (ModelField field : modelFields) {
306 XmlFieldMetadata xmlFieldMetadata = (XmlFieldMetadata) field.getMetadata(XmlFieldMetadata.ID);
307
308 if (xmlFieldMetadata.isContent()) {
309
310 continue;
311 }
312
313 JavaFieldMetadata javaFieldMetadata = (JavaFieldMetadata) field.getMetadata(JavaFieldMetadata.ID);
314
315 String fieldTagName = resolveTagName(field, xmlFieldMetadata);
316
317 String type = field.getType();
318
319 String value = uncapClassName + "." + getPrefix(javaFieldMetadata) + capitalise(field.getName()) + "()";
320
321 if (xmlFieldMetadata.isAttribute()) {
322 continue;
323 }
324
325 if (field instanceof ModelAssociation) {
326 ModelAssociation association = (ModelAssociation) field;
327
328 String associationName = association.getName();
329
330 if (association.isOneMultiplicity()) {
331 sc.add(getValueChecker(type, value, association));
332
333 sc.add("{");
334 sc.addIndented("write" + association.getTo() + "( (" + association.getTo() + ") " + value + ", \""
335 + fieldTagName + "\", serializer );");
336 sc.add("}");
337 } else {
338
339
340 XmlAssociationMetadata xmlAssociationMetadata =
341 (XmlAssociationMetadata) association.getAssociationMetadata(XmlAssociationMetadata.ID);
342
343 String valuesTagName = resolveTagName(fieldTagName, xmlAssociationMetadata);
344
345 type = association.getType();
346 String toType = association.getTo();
347
348 boolean wrappedItems = xmlAssociationMetadata.isWrappedItems();
349
350 if (ModelDefault.LIST.equals(type) || ModelDefault.SET.equals(type)) {
351 boolean isList = ModelDefault.LIST.equals(type);
352
353 sc.add(getValueChecker(type, value, association));
354
355 sc.add("{");
356 sc.indent();
357
358 if (wrappedItems) {
359 sc.add("serializer.startTag( NAMESPACE, " + "\"" + fieldTagName + "\" );");
360 }
361
362 if (isLocationTracking() && !isClassInModel(association.getTo(), modelClass.getModel())) {
363 sc.add(locationTracker.getName() + " location = " + uncapClassName + ".getLocation( \""
364 + fieldTagName + "\" );");
365 if (isList) {
366 sc.add("int n = 0;");
367 }
368 }
369
370 sc.add("for ( Iterator iter = " + value + ".iterator(); iter.hasNext(); )");
371
372 sc.add("{");
373 sc.indent();
374
375 if (isClassInModel(association.getTo(), modelClass.getModel())) {
376 sc.add(toType + " o = (" + toType + ") iter.next();");
377
378 sc.add("write" + toType + "( o, \"" + valuesTagName + "\", serializer );");
379 } else {
380 String variable = singular(uncapitalise(field.getName()));
381
382 sc.add(toType + " " + variable + " = (" + toType + ") iter.next();");
383
384 sc.add("serializer.startTag( NAMESPACE, \"" + valuesTagName + "\" ).text( " + variable
385 + " ).endTag( NAMESPACE, \"" + valuesTagName + "\" );");
386
387 writeLocationTracking(sc, "location", isList ? "Integer.valueOf( n++ )" : variable);
388 }
389
390 sc.unindent();
391 sc.add("}");
392
393 if (wrappedItems) {
394 sc.add("serializer.endTag( NAMESPACE, \"" + fieldTagName + "\" );");
395 }
396
397 sc.unindent();
398 sc.add("}");
399 } else {
400
401
402 sc.add(getValueChecker(type, value, field));
403
404 sc.add("{");
405 sc.indent();
406
407 if (wrappedItems) {
408 sc.add("serializer.startTag( NAMESPACE, \"" + fieldTagName + "\" );");
409 }
410
411 if (isLocationTracking()) {
412 sc.add(locationTracker.getName() + " location = " + uncapClassName + ".getLocation( \""
413 + fieldTagName + "\" );");
414 }
415
416 sc.add("for ( Iterator iter = " + value + ".keySet().iterator(); iter.hasNext(); )");
417
418 sc.add("{");
419 sc.indent();
420
421 sc.add("String key = (String) iter.next();");
422
423 sc.add("String value = (String) " + value + ".get( key );");
424
425 if (xmlAssociationMetadata.isMapExplode()) {
426 sc.add("serializer.startTag( NAMESPACE, \"" + singular(associationName) + "\" );");
427 sc.add(
428 "serializer.startTag( NAMESPACE, \"key\" ).text( key ).endTag( NAMESPACE, \"key\" );");
429 sc.add(
430 "serializer.startTag( NAMESPACE, \"value\" ).text( value ).endTag( NAMESPACE, \"value\" );");
431 sc.add("serializer.endTag( NAMESPACE, \"" + singular(associationName) + "\" );");
432 } else {
433 sc.add("serializer.startTag( NAMESPACE, key ).text( value ).endTag( NAMESPACE, key );");
434 }
435
436 writeLocationTracking(sc, "location", "key");
437
438 sc.unindent();
439 sc.add("}");
440
441 if (wrappedItems) {
442 sc.add("serializer.endTag( NAMESPACE, \"" + fieldTagName + "\" );");
443 }
444
445 sc.unindent();
446 sc.add("}");
447 }
448 }
449 } else {
450 sc.add(getValueChecker(type, value, field));
451
452 sc.add("{");
453 if ("DOM".equals(field.getType())) {
454 if (domAsXpp3) {
455 jClass.addImport("org.codehaus.plexus.util.xml.Xpp3Dom");
456
457 if (isLocationTracking()) {
458 sc.addIndented("writeXpp3DomToSerializer( (Xpp3Dom) " + value + ", serializer );");
459 } else {
460 sc.addIndented("((Xpp3Dom) " + value + ").writeToSerializer( NAMESPACE, serializer );");
461 }
462 } else {
463 sc.addIndented("writeDom( (org.w3c.dom.Element) " + value + ", serializer );");
464 }
465
466 requiresDomSupport = true;
467 } else {
468 sc.addIndented("serializer.startTag( NAMESPACE, " + "\"" + fieldTagName + "\" ).text( "
469 + getValue(field.getType(), value, xmlFieldMetadata) + " ).endTag( NAMESPACE, " + "\""
470 + fieldTagName + "\" );");
471 sc.indent();
472 writeLocationTracking(sc, uncapClassName, '"' + fieldTagName + '"');
473 sc.unindent();
474 }
475 sc.add("}");
476 }
477 }
478
479 sc.add("serializer.endTag( NAMESPACE, tagName );");
480
481 jClass.addMethod(marshall);
482 }
483
484 private void createWriteDomMethod(JClass jClass) {
485 if (domAsXpp3) {
486 return;
487 }
488 String type = "org.w3c.dom.Element";
489 JMethod method = new JMethod("writeDom");
490 method.getModifiers().makePrivate();
491
492 method.addParameter(new JParameter(new JType(type), "dom"));
493 method.addParameter(new JParameter(new JClass("XmlSerializer"), "serializer"));
494
495 method.addException(new JClass("java.io.IOException"));
496
497 JSourceCode sc = method.getSourceCode();
498
499
500 sc.add("serializer.startTag( NAMESPACE, dom.getTagName() );");
501
502
503 sc.add("org.w3c.dom.NamedNodeMap attributes = dom.getAttributes();");
504 sc.add("for ( int i = 0; i < attributes.getLength(); i++ )");
505 sc.add("{");
506
507 sc.indent();
508 sc.add("org.w3c.dom.Node attribute = attributes.item( i );");
509 sc.add("serializer.attribute( NAMESPACE, attribute.getNodeName(), attribute.getNodeValue() );");
510 sc.unindent();
511
512 sc.add("}");
513
514
515 sc.add("org.w3c.dom.NodeList children = dom.getChildNodes();");
516 sc.add("for ( int i = 0; i < children.getLength(); i++ )");
517 sc.add("{");
518 sc.indent();
519 sc.add("org.w3c.dom.Node node = children.item( i );");
520 sc.add("if ( node instanceof org.w3c.dom.Element)");
521 sc.add("{");
522 sc.addIndented("writeDom( (org.w3c.dom.Element) children.item( i ), serializer );");
523 sc.add("}");
524 sc.add("else");
525 sc.add("{");
526 sc.addIndented("serializer.text( node.getTextContent() );");
527 sc.add("}");
528 sc.unindent();
529 sc.add("}");
530
531 sc.add("serializer.endTag( NAMESPACE, dom.getTagName() );");
532
533 jClass.addMethod(method);
534 }
535 }