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