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 org.yaml.snakeyaml.issues.issue29;
17 
18 import java.beans.IntrospectionException;
19 import java.util.ArrayList;
20 import java.util.Arrays;
21 import java.util.Comparator;
22 import java.util.HashMap;
23 import java.util.List;
24 import java.util.Map;
25 import java.util.Set;
26 import java.util.TreeSet;
27 
28 import junit.framework.TestCase;
29 
30 import org.yaml.snakeyaml.Yaml;
31 import org.yaml.snakeyaml.introspector.BeanAccess;
32 import org.yaml.snakeyaml.introspector.Property;
33 import org.yaml.snakeyaml.nodes.NodeTuple;
34 import org.yaml.snakeyaml.nodes.ScalarNode;
35 import org.yaml.snakeyaml.nodes.SequenceNode;
36 import org.yaml.snakeyaml.nodes.Tag;
37 import org.yaml.snakeyaml.representer.Representer;
38 
39 public class FlexibleScalarStylesInJavaBeanTest extends TestCase {
testDifferentStyles()40     public void testDifferentStyles() {
41         BigJavaBean bean1 = new BigJavaBean(1, "simple", "line 1\nline2\nzipcode", "short text1");
42         List<Integer> numbers1 = new ArrayList<Integer>(Arrays.asList(1, 2, 3));
43         bean1.setNumbers(numbers1);
44         Map<String, String> data1 = new HashMap<String, String>();
45         data1.put("key1", "value1");
46         data1.put("key2", "value2");
47         bean1.setData(data1);
48         //
49         BigJavaBean bean2 = new BigJavaBean(1, "second", "line 111\nline 222\nzipcode 12345\n\n",
50                 "info: semicolon is used");
51         List<Integer> numbers2 = new ArrayList<Integer>(Arrays.asList(4, 5, 6, 777, 888, 999, 1000));
52         bean2.setNumbers(numbers2);
53         Map<String, String> data2 = new HashMap<String, String>();
54         data2.put("key21", "value12");
55         data2.put("key22", "value with\ntwo lines");
56         bean2.setData(data2);
57         //
58         List<BigJavaBean> list = new ArrayList<BigJavaBean>();
59         list.add(bean1);
60         list.add(bean2);
61         Yaml yaml = new Yaml(new MyRepresenter());
62         yaml.setBeanAccess(BeanAccess.FIELD);
63         String output = yaml.dump(list);
64         // System.out.println(output);
65         // parse back
66         @SuppressWarnings("unchecked")
67         List<BigJavaBean> parsed = (List<BigJavaBean>) yaml.load(output);
68         assertEquals(2, parsed.size());
69         assertEquals(bean1, parsed.get(0));
70         assertEquals(bean2, parsed.get(1));
71 
72     }
73 
74     private class MyRepresenter extends Representer {
75         /*
76          * Change the default order. Important data goes first.
77          */
78         @Override
getProperties(Class<? extends Object> type)79         protected Set<Property> getProperties(Class<? extends Object> type)
80                 throws IntrospectionException {
81             if (type.isAssignableFrom(BigJavaBean.class)) {
82                 Set<Property> standard = super.getProperties(type);
83                 Set<Property> sorted = new TreeSet<Property>(new PropertyComparator());
84                 sorted.addAll(standard);
85                 return sorted;
86             } else {
87                 return super.getProperties(type);
88             }
89         }
90 
91         private class PropertyComparator implements Comparator<Property> {
compare(Property o1, Property o2)92             public int compare(Property o1, Property o2) {
93                 // important go first
94                 List<String> order = new ArrayList<String>(Arrays.asList("id", "name",
95                         "description", "address"));
96                 for (String name : order) {
97                     int c = compareByName(o1, o2, name);
98                     if (c != 0) {
99                         return c;
100                     }
101                 }
102                 // all the rest
103                 return o1.compareTo(o2);
104             }
105 
compareByName(Property o1, Property o2, String name)106             private int compareByName(Property o1, Property o2, String name) {
107                 if (o1.getName().equals(name)) {
108                     return -1;
109                 } else if (o2.getName().equals(name)) {
110                     return 1;
111                 }
112                 return 0;// compare further
113             }
114         }
115 
116         @Override
representJavaBeanProperty(Object javaBean, Property property, Object propertyValue, Tag customTag)117         protected NodeTuple representJavaBeanProperty(Object javaBean, Property property,
118                 Object propertyValue, Tag customTag) {
119             if (javaBean instanceof BigJavaBean) {
120                 BigJavaBean bean = (BigJavaBean) javaBean;
121                 NodeTuple standard = super.representJavaBeanProperty(javaBean, property,
122                         propertyValue, customTag);
123                 if (property.getName().equals("numbers")) {
124                     // when the list is small, make it block collection style
125                     if (bean.getNumbers().size() < 5) {
126                         SequenceNode n = (SequenceNode) standard.getValueNode();
127                         return new NodeTuple(standard.getKeyNode(), new SequenceNode(n.getTag(),
128                                 true, n.getValue(), n.getStartMark(), n.getEndMark(), false));
129                     }
130                 }
131                 if (property.getName().equals("description")) {
132                     // if description contains ':' use folded scalar style and
133                     // not single quoted scalar style
134                     if (bean.getDescription().indexOf(':') > 0) {
135                         ScalarNode n = (ScalarNode) standard.getValueNode();
136                         return new NodeTuple(standard.getKeyNode(), new ScalarNode(n.getTag(),
137                                 n.getValue(), n.getStartMark(), n.getEndMark(), '>'));
138                     }
139                 }
140                 return standard;
141             } else {
142                 return super
143                         .representJavaBeanProperty(javaBean, property, propertyValue, customTag);
144             }
145         }
146     }
147 }
148