/** * Copyright (c) 2008, SnakeYAML * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except * in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under the License * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express * or implied. See the License for the specific language governing permissions and limitations under * the License. */ package examples.jodatime; import java.util.Date; import java.util.List; import junit.framework.TestCase; import org.joda.time.DateTime; import org.joda.time.DateTimeZone; import org.yaml.snakeyaml.DumperOptions; import org.yaml.snakeyaml.DumperOptions.FlowStyle; import org.yaml.snakeyaml.LoaderOptions; import org.yaml.snakeyaml.Yaml; import org.yaml.snakeyaml.constructor.Construct; import org.yaml.snakeyaml.constructor.Constructor; import org.yaml.snakeyaml.events.Event; import org.yaml.snakeyaml.events.ScalarEvent; import org.yaml.snakeyaml.nodes.Node; import org.yaml.snakeyaml.nodes.NodeId; import org.yaml.snakeyaml.nodes.Tag; public class JodaTimeFlowStylesTest extends TestCase { private static final long timestamp = 1000000000000L; /** * @see issue 128 */ public void testLoadBeanWithBlockFlow() { MyBean bean = new MyBean(); bean.setId("id123"); DateTime etalon = new DateTime(timestamp, DateTimeZone.UTC); bean.setDate(etalon); DumperOptions options = new DumperOptions(); options.setDefaultFlowStyle(FlowStyle.BLOCK); Yaml dumper = new Yaml(new JodaTimeRepresenter(), options); // compare Nodes with flow style AUTO and flow style BLOCK Node node1 = dumper.represent(bean); DumperOptions options2 = new DumperOptions(); options2.setDefaultFlowStyle(FlowStyle.AUTO); Yaml dumper2 = new Yaml(new JodaTimeRepresenter(), options2); Node node2 = dumper2.represent(bean); assertEquals(node2.toString(), node1.toString()); // compare Events with flow style AUTO and flow style BLOCK List events1 = dumper.serialize(node1); List events2 = dumper2.serialize(node2); assertEquals(events2.size(), events1.size()); int i = 0; for (Event etalonEvent : events2) { assertEquals(etalonEvent, events1.get(i++)); if (etalonEvent instanceof ScalarEvent) { ScalarEvent scalar = (ScalarEvent) etalonEvent; if (scalar.getValue().equals("2001-09-09T01:46:40Z")) { assertTrue(scalar.getImplicit().canOmitTagInPlainScalar()); assertFalse(scalar.getImplicit().canOmitTagInNonPlainScalar()); } } } // Nodes and Events are the same. Only emitter may influence the output. String doc1 = dumper.dump(bean); // System.out.println(doc1); /* * 'date' must be used only with the explicit '!!timestamp' tag. Implicit tag will not work * because 'date' is the JavaBean property and in this case the empty constructor of the class * will be used. Since this constructor does not exist for JodaTime an exception will be thrown. */ assertEquals("!!examples.jodatime.MyBean\ndate: 2001-09-09T01:46:40Z\nid: id123\n", doc1); /* * provided JodaTimeContructor will be ignored because 'date' is a JavaBean property and its * class gets more priority then the implicit '!!timestamp' tag. */ Yaml loader = new Yaml(new JodaTimeImplicitContructor()); try { loader.load(doc1); } catch (Exception e) { assertTrue("The error must indicate that JodaTime cannot be created from the scalar value.", e.getMessage().contains( "No String constructor found. Exception=org.joda.time.DateTime.(java.lang.String)")); } // we have to provide a special way to create JodaTime instances from // scalars Yaml loader2 = new Yaml(new JodaPropertyConstructor()); MyBean parsed = loader2.load(doc1); assertEquals(etalon, parsed.getDate()); } /** * !!timestamp must be used, without it the implicit tag will be ignored because 'date' is the * JavaBean property. * * Since the timestamp contains ':' character it cannot use plain scalar style in the FLOW mapping * style. Emitter suggests single quoted scalar style and that is why the explicit '!!timestamp' * is present in the YAML document. * * @see issue 128 * */ public void testLoadBeanWithAutoFlow() { MyBean bean = new MyBean(); bean.setId("id123"); DateTime etalon = new DateTime(timestamp, DateTimeZone.UTC); bean.setDate(etalon); DumperOptions options = new DumperOptions(); options.setDefaultFlowStyle(FlowStyle.AUTO); Yaml dumper = new Yaml(new JodaTimeRepresenter(), options); String doc = dumper.dump(bean); // System.out.println(doc); assertEquals( "!!examples.jodatime.MyBean {date: !!timestamp '2001-09-09T01:46:40Z', id: id123}\n", doc); Yaml loader = new Yaml(new JodaTimeImplicitContructor()); MyBean parsed = loader.load(doc); assertEquals(etalon, parsed.getDate()); } private class JodaPropertyConstructor extends Constructor { public JodaPropertyConstructor() { super(new LoaderOptions()); yamlClassConstructors.put(NodeId.scalar, new TimeStampConstruct()); } class TimeStampConstruct extends Constructor.ConstructScalar { @Override public Object construct(Node nnode) { if (nnode.getTag().equals(new Tag("tag:yaml.org,2002:timestamp"))) { Construct dateConstructor = yamlConstructors.get(Tag.TIMESTAMP); Date date = (Date) dateConstructor.construct(nnode); return new DateTime(date, DateTimeZone.UTC); } else { return super.construct(nnode); } } } } }