• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2008, SnakeYAML
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5  * in compliance with the License. You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software distributed under the License
10  * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11  * or implied. See the License for the specific language governing permissions and limitations under
12  * the License.
13  */
14 package examples.jodatime;
15 
16 import java.util.Date;
17 import java.util.List;
18 import junit.framework.TestCase;
19 import org.joda.time.DateTime;
20 import org.joda.time.DateTimeZone;
21 import org.yaml.snakeyaml.DumperOptions;
22 import org.yaml.snakeyaml.DumperOptions.FlowStyle;
23 import org.yaml.snakeyaml.Yaml;
24 import org.yaml.snakeyaml.constructor.Construct;
25 import org.yaml.snakeyaml.constructor.Constructor;
26 import org.yaml.snakeyaml.events.Event;
27 import org.yaml.snakeyaml.events.ScalarEvent;
28 import org.yaml.snakeyaml.nodes.Node;
29 import org.yaml.snakeyaml.nodes.NodeId;
30 import org.yaml.snakeyaml.nodes.Tag;
31 
32 public class JodaTimeFlowStylesTest extends TestCase {
33 
34   private static final long timestamp = 1000000000000L;
35 
36   /**
37    * @see <a href="http://code.google.com/p/snakeyaml/issues/detail?id=128">issue 128</a>
38    */
testLoadBeanWithBlockFlow()39   public void testLoadBeanWithBlockFlow() {
40     MyBean bean = new MyBean();
41     bean.setId("id123");
42     DateTime etalon = new DateTime(timestamp, DateTimeZone.UTC);
43     bean.setDate(etalon);
44     DumperOptions options = new DumperOptions();
45     options.setDefaultFlowStyle(FlowStyle.BLOCK);
46     Yaml dumper = new Yaml(new JodaTimeRepresenter(), options);
47     // compare Nodes with flow style AUTO and flow style BLOCK
48     Node node1 = dumper.represent(bean);
49     DumperOptions options2 = new DumperOptions();
50     options2.setDefaultFlowStyle(FlowStyle.AUTO);
51     Yaml dumper2 = new Yaml(new JodaTimeRepresenter(), options2);
52     Node node2 = dumper2.represent(bean);
53     assertEquals(node2.toString(), node1.toString());
54     // compare Events with flow style AUTO and flow style BLOCK
55     List<Event> events1 = dumper.serialize(node1);
56     List<Event> events2 = dumper2.serialize(node2);
57     assertEquals(events2.size(), events1.size());
58     int i = 0;
59     for (Event etalonEvent : events2) {
60       assertEquals(etalonEvent, events1.get(i++));
61       if (etalonEvent instanceof ScalarEvent) {
62         ScalarEvent scalar = (ScalarEvent) etalonEvent;
63         if (scalar.getValue().equals("2001-09-09T01:46:40Z")) {
64           assertTrue(scalar.getImplicit().canOmitTagInPlainScalar());
65           assertFalse(scalar.getImplicit().canOmitTagInNonPlainScalar());
66         }
67       }
68     }
69     // Nodes and Events are the same. Only emitter may influence the output.
70     String doc1 = dumper.dump(bean);
71     // System.out.println(doc1);
72     /*
73      * 'date' must be used only with the explicit '!!timestamp' tag. Implicit tag will not work
74      * because 'date' is the JavaBean property and in this case the empty constructor of the class
75      * will be used. Since this constructor does not exist for JodaTime an exception will be thrown.
76      */
77     assertEquals("!!examples.jodatime.MyBean\ndate: 2001-09-09T01:46:40Z\nid: id123\n", doc1);
78     /*
79      * provided JodaTimeContructor will be ignored because 'date' is a JavaBean property and its
80      * class gets more priority then the implicit '!!timestamp' tag.
81      */
82     Yaml loader = new Yaml(new JodaTimeImplicitContructor());
83     try {
84       loader.load(doc1);
85     } catch (Exception e) {
86       assertTrue("The error must indicate that JodaTime cannot be created from the scalar value.",
87           e.getMessage().contains(
88               "No String constructor found. Exception=org.joda.time.DateTime.<init>(java.lang.String)"));
89     }
90     // we have to provide a special way to create JodaTime instances from
91     // scalars
92     Yaml loader2 = new Yaml(new JodaPropertyConstructor());
93     MyBean parsed = loader2.load(doc1);
94     assertEquals(etalon, parsed.getDate());
95   }
96 
97   /**
98    * !!timestamp must be used, without it the implicit tag will be ignored because 'date' is the
99    * JavaBean property.
100    *
101    * Since the timestamp contains ':' character it cannot use plain scalar style in the FLOW mapping
102    * style. Emitter suggests single quoted scalar style and that is why the explicit '!!timestamp'
103    * is present in the YAML document.
104    *
105    * @see <a href="http://code.google.com/p/snakeyaml/issues/detail?id=128">issue 128</a>
106    *
107    */
testLoadBeanWithAutoFlow()108   public void testLoadBeanWithAutoFlow() {
109     MyBean bean = new MyBean();
110     bean.setId("id123");
111     DateTime etalon = new DateTime(timestamp, DateTimeZone.UTC);
112     bean.setDate(etalon);
113     DumperOptions options = new DumperOptions();
114     options.setDefaultFlowStyle(FlowStyle.AUTO);
115     Yaml dumper = new Yaml(new JodaTimeRepresenter(), options);
116     String doc = dumper.dump(bean);
117     // System.out.println(doc);
118     assertEquals(
119         "!!examples.jodatime.MyBean {date: !!timestamp '2001-09-09T01:46:40Z', id: id123}\n", doc);
120     Yaml loader = new Yaml(new JodaTimeImplicitContructor());
121     MyBean parsed = loader.load(doc);
122     assertEquals(etalon, parsed.getDate());
123   }
124 
125   private class JodaPropertyConstructor extends Constructor {
126 
JodaPropertyConstructor()127     public JodaPropertyConstructor() {
128       yamlClassConstructors.put(NodeId.scalar, new TimeStampConstruct());
129     }
130 
131     class TimeStampConstruct extends Constructor.ConstructScalar {
132 
133       @Override
construct(Node nnode)134       public Object construct(Node nnode) {
135         if (nnode.getTag().equals(new Tag("tag:yaml.org,2002:timestamp"))) {
136           Construct dateConstructor = yamlConstructors.get(Tag.TIMESTAMP);
137           Date date = (Date) dateConstructor.construct(nnode);
138           return new DateTime(date, DateTimeZone.UTC);
139         } else {
140           return super.construct(nnode);
141         }
142       }
143 
144     }
145   }
146 }
147