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.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.metadata.JavaFieldMetadata;
45 import org.codehaus.modello.plugins.xml.metadata.XmlAssociationMetadata;
46 import org.codehaus.modello.plugins.xml.metadata.XmlFieldMetadata;
47
48
49
50
51 @Named("snakeyaml-writer")
52 public class SnakeYamlWriterGenerator extends AbstractSnakeYamlGenerator {
53
54 public void generate(Model model, Properties parameters) throws ModelloException {
55 initialize(model, parameters);
56
57 try {
58 generateSnakeYamlWriter();
59 } catch (IOException ex) {
60 throw new ModelloException("Exception while generating SnakeYaml Writer.", ex);
61 }
62 }
63
64 private void generateSnakeYamlWriter() throws ModelloException, IOException {
65 Model objectModel = getModel();
66
67 String packageName =
68 objectModel.getDefaultPackageName(isPackageWithVersion(), getGeneratedVersion()) + ".io.snakeyaml";
69
70 String marshallerName = getFileName("SnakeYamlWriter");
71
72 JSourceWriter sourceWriter = newJSourceWriter(packageName, marshallerName);
73
74 JClass jClass = new JClass(packageName + '.' + marshallerName);
75 initHeader(jClass);
76
77 jClass.addImport("org.yaml.snakeyaml.DumperOptions");
78 jClass.addImport("org.yaml.snakeyaml.DumperOptions.Version");
79 jClass.addImport("org.yaml.snakeyaml.DumperOptions.FlowStyle");
80 jClass.addImport("org.yaml.snakeyaml.DumperOptions.ScalarStyle");
81 jClass.addImport("org.yaml.snakeyaml.emitter.Emitable");
82 jClass.addImport("org.yaml.snakeyaml.emitter.Emitter");
83 jClass.addImport("org.yaml.snakeyaml.error.Mark");
84 jClass.addImport("org.yaml.snakeyaml.events.DocumentEndEvent");
85 jClass.addImport("org.yaml.snakeyaml.events.DocumentStartEvent");
86 jClass.addImport("org.yaml.snakeyaml.events.ImplicitTuple");
87 jClass.addImport("org.yaml.snakeyaml.events.MappingEndEvent");
88 jClass.addImport("org.yaml.snakeyaml.events.MappingStartEvent");
89 jClass.addImport("org.yaml.snakeyaml.events.ScalarEvent");
90 jClass.addImport("org.yaml.snakeyaml.events.SequenceEndEvent");
91 jClass.addImport("org.yaml.snakeyaml.events.SequenceStartEvent");
92 jClass.addImport("org.yaml.snakeyaml.events.StreamEndEvent");
93 jClass.addImport("org.yaml.snakeyaml.events.StreamStartEvent");
94 jClass.addImport("java.io.IOException");
95 jClass.addImport("java.io.OutputStream");
96 jClass.addImport("java.io.OutputStreamWriter");
97 jClass.addImport("java.io.Writer");
98
99 addModelImports(jClass, null);
100
101 JField factoryField = new JField(new JClass("DumperOptions"), "dumperOptions");
102 factoryField.getModifiers().setFinal(true);
103 factoryField.setInitString("new DumperOptions()");
104 jClass.addField(factoryField);
105
106 JConstructor jacksonWriterConstructor = new JConstructor(jClass);
107 JSourceCode sc = jacksonWriterConstructor.getSourceCode();
108 sc.add("dumperOptions.setAllowUnicode( true );");
109 sc.add("dumperOptions.setPrettyFlow( true );");
110 sc.add("dumperOptions.setVersion( Version.V1_1 );");
111
112 jClass.addConstructor(jacksonWriterConstructor);
113
114 String root = objectModel.getRoot(getGeneratedVersion());
115
116
117
118
119
120 JMethod marshall = new JMethod("write");
121
122 String rootElementParameterName = uncapitalise(root);
123 marshall.addParameter(new JParameter(new JClass("Writer"), "writer"));
124 marshall.addParameter(new JParameter(new JClass(root), rootElementParameterName));
125
126 marshall.addException(new JClass("IOException"));
127
128 sc = marshall.getSourceCode();
129
130 sc.add("Emitable generator = new Emitter( writer, dumperOptions );");
131
132 sc.add("generator.emit( new StreamStartEvent( null, null ) );");
133
134 sc.add(
135 "generator.emit( new DocumentStartEvent( null, null, dumperOptions.isExplicitStart(), dumperOptions.getVersion(), dumperOptions.getTags() ) );");
136
137 sc.add("write" + root + "( " + rootElementParameterName + ", generator );");
138
139 sc.add("generator.emit( new DocumentEndEvent( null, null, dumperOptions.isExplicitEnd() ) );");
140
141 sc.add("generator.emit( new StreamEndEvent( null, null ) );");
142
143 jClass.addMethod(marshall);
144
145
146
147
148
149 marshall = new JMethod("write");
150
151 marshall.addParameter(new JParameter(new JClass("OutputStream"), "stream"));
152 marshall.addParameter(new JParameter(new JClass(root), rootElementParameterName));
153
154 marshall.addException(new JClass("IOException"));
155
156 sc = marshall.getSourceCode();
157
158 sc.add("write( new OutputStreamWriter( stream, "
159 + rootElementParameterName
160 + ".getModelEncoding() ), "
161 + rootElementParameterName
162 + " );");
163
164 jClass.addMethod(marshall);
165
166 writeAllClasses(objectModel, jClass);
167
168 jClass.print(sourceWriter);
169
170 sourceWriter.close();
171 }
172
173 private void writeAllClasses(Model objectModel, JClass jClass) throws ModelloException {
174 for (ModelClass clazz : getClasses(objectModel)) {
175 writeClass(clazz, jClass);
176 }
177 }
178
179 private void writeClass(ModelClass modelClass, JClass jClass) throws ModelloException {
180 String className = modelClass.getName();
181
182 String uncapClassName = uncapitalise(className);
183
184 JMethod marshall = new JMethod("write" + className);
185
186 marshall.addParameter(new JParameter(new JClass(className), uncapClassName));
187 marshall.addParameter(new JParameter(new JClass("Emitable"), "generator"));
188
189 marshall.addException(new JClass("IOException"));
190
191 marshall.getModifiers().makePrivate();
192
193 JSourceCode sc = marshall.getSourceCode();
194
195 sc.add("generator.emit( new MappingStartEvent( null, null, true, null, null, FlowStyle.BLOCK ) );");
196
197 ModelField contentField = null;
198
199 String contentValue = null;
200
201 List<ModelField> modelFields = getFieldsForXml(modelClass, getGeneratedVersion());
202
203
204 for (ModelField field : modelFields) {
205 XmlFieldMetadata xmlFieldMetadata = (XmlFieldMetadata) field.getMetadata(XmlFieldMetadata.ID);
206
207 JavaFieldMetadata javaFieldMetadata = (JavaFieldMetadata) field.getMetadata(JavaFieldMetadata.ID);
208
209 String fieldTagName = resolveTagName(field, xmlFieldMetadata);
210
211 String type = field.getType();
212
213 String value = uncapClassName + "." + getPrefix(javaFieldMetadata) + capitalise(field.getName()) + "()";
214
215 if (xmlFieldMetadata.isContent()) {
216 contentField = field;
217 contentValue = value;
218 continue;
219 }
220
221 if (xmlFieldMetadata.isAttribute()) {
222 sc.add(getValueChecker(type, value, field));
223
224 sc.add("{");
225 sc.indent();
226
227 writeScalarKey(sc, fieldTagName);
228 writeScalar(sc, getValue(field.getType(), value, xmlFieldMetadata));
229
230 sc.unindent();
231 sc.add("}");
232 }
233 }
234
235 if (contentField != null) {
236 XmlFieldMetadata xmlFieldMetadata = (XmlFieldMetadata) contentField.getMetadata(XmlFieldMetadata.ID);
237 writeScalar(sc, getValue(contentField.getType(), contentValue, xmlFieldMetadata));
238 }
239
240 final boolean useJava5 = hasJavaSourceSupport(5);
241
242
243 for (ModelField field : modelFields) {
244 XmlFieldMetadata xmlFieldMetadata = (XmlFieldMetadata) field.getMetadata(XmlFieldMetadata.ID);
245
246 if (xmlFieldMetadata.isContent()) {
247
248 continue;
249 }
250
251 JavaFieldMetadata javaFieldMetadata = (JavaFieldMetadata) field.getMetadata(JavaFieldMetadata.ID);
252
253 String fieldTagName = resolveTagName(field, xmlFieldMetadata);
254
255 String type = field.getType();
256
257 String value = uncapClassName + "." + getPrefix(javaFieldMetadata) + capitalise(field.getName()) + "()";
258
259 if (xmlFieldMetadata.isAttribute()) {
260 continue;
261 }
262
263 if (field instanceof ModelAssociation) {
264 ModelAssociation association = (ModelAssociation) field;
265
266 if (association.isOneMultiplicity()) {
267 sc.add(getValueChecker(type, value, association));
268
269 sc.add("{");
270 sc.indent();
271
272 writeScalarKey(sc, fieldTagName);
273 sc.add("write" + association.getTo() + "( (" + association.getTo() + ") " + value
274 + ", generator );");
275
276 sc.unindent();
277 sc.add("}");
278 } else {
279
280
281 XmlAssociationMetadata xmlAssociationMetadata =
282 (XmlAssociationMetadata) association.getAssociationMetadata(XmlAssociationMetadata.ID);
283
284 type = association.getType();
285 String toType = association.getTo();
286
287 if (ModelDefault.LIST.equals(type) || ModelDefault.SET.equals(type)) {
288 sc.add(getValueChecker(type, value, association));
289
290 sc.add("{");
291 sc.indent();
292
293 writeScalarKey(sc, fieldTagName);
294 sc.add("generator.emit( new SequenceStartEvent( null, null, true, null, null, false ) );");
295
296 if (useJava5) {
297 sc.add("for ( " + toType + " o : " + value + " )");
298 } else {
299 sc.add("for ( java.util.Iterator it = " + value + ".iterator(); it.hasNext(); )");
300 }
301
302 sc.add("{");
303 sc.indent();
304
305 if (!useJava5) {
306 sc.add(toType + " o = (" + toType + " ) it.next();");
307 }
308
309 if (isClassInModel(association.getTo(), modelClass.getModel())) {
310 sc.add("write" + toType + "( o, generator );");
311 } else {
312 writeScalar(sc, "o");
313 }
314
315 sc.unindent();
316 sc.add("}");
317
318 sc.add("generator.emit( new SequenceEndEvent( null, null ) );");
319
320 sc.unindent();
321 sc.add("}");
322 } else {
323
324
325 sc.add(getValueChecker(type, value, field));
326
327 sc.add("{");
328 sc.indent();
329
330 writeScalarKey(sc, fieldTagName);
331
332 if (xmlAssociationMetadata.isMapExplode()) {
333 sc.add("generator.emit( new SequenceStartEvent( null, null, true, null, null, false ) );");
334 } else {
335 sc.add(
336 "generator.emit( new MappingStartEvent( null, null, true, null, null, FlowStyle.BLOCK ) );");
337 }
338
339 StringBuilder entryTypeBuilder = new StringBuilder("java.util.Map.Entry");
340
341 if (useJava5) {
342 entryTypeBuilder.append('<');
343
344 if (association.getType().equals(ModelDefault.PROPERTIES)) {
345 entryTypeBuilder.append("Object, Object");
346 } else {
347 entryTypeBuilder.append("String, ").append(association.getTo());
348 }
349
350 entryTypeBuilder.append('>');
351 }
352
353 if (useJava5) {
354 sc.add("for ( " + entryTypeBuilder + " entry : " + value + ".entrySet() )");
355 } else {
356 sc.add("for ( java.util.Iterator it = " + value
357 + ".entrySet().iterator(); it.hasNext(); )");
358 }
359
360 sc.add("{");
361 sc.indent();
362
363 if (!useJava5) {
364 sc.add(entryTypeBuilder + " entry = (" + entryTypeBuilder + ") it.next();");
365 }
366
367 sc.add("final String key = String.valueOf( entry.getKey() );");
368 sc.add("final String value = String.valueOf( entry.getValue() );");
369
370 if (xmlAssociationMetadata.isMapExplode()) {
371 sc.add(
372 "generator.emit( new MappingStartEvent( null, null, true, null, null, FlowStyle.BLOCK) );");
373 writeScalarKey(sc, "key");
374 writeScalar(sc, "key");
375 writeScalarKey(sc, "value");
376 writeScalar(sc, "value");
377 sc.add("generator.emit( new MappingEndEvent( null, null ) );");
378 } else {
379 writeScalar(sc, "key");
380 writeScalar(sc, "value");
381 }
382
383 sc.unindent();
384 sc.add("}");
385
386 if (xmlAssociationMetadata.isMapExplode()) {
387 sc.add("generator.emit( new SequenceEndEvent( null, null ) );");
388 } else {
389 sc.add("generator.emit( new MappingEndEvent( null, null ) );");
390 }
391
392 sc.unindent();
393 sc.add("}");
394 }
395 }
396 } else {
397 sc.add(getValueChecker(type, value, field));
398
399 sc.add("{");
400 sc.indent();
401
402 writeScalarKey(sc, fieldTagName);
403 writeScalar(sc, getValue(field.getType(), value, xmlFieldMetadata));
404
405 sc.unindent();
406 sc.add("}");
407 }
408 }
409
410 sc.add("generator.emit( new MappingEndEvent( null, null ) );");
411
412 jClass.addMethod(marshall);
413 }
414
415 private void writeScalarKey(JSourceCode sc, String key) {
416 writeScalar(sc, "\"" + key + "\"");
417 }
418
419 private void writeScalar(JSourceCode sc, String value) {
420 sc.add("{");
421 sc.indent();
422 sc.add("String anchor = null, tag = null;");
423 sc.add("Mark startMark = null, endMark = null;");
424 sc.add("ScalarStyle style = ScalarStyle.DOUBLE_QUOTED;");
425 sc.add("generator.emit( new ScalarEvent( anchor, tag, new ImplicitTuple( true, true ), "
426 + value
427 + ", startMark, endMark, style ) );");
428 sc.unindent();
429 sc.add("}");
430 }
431 }