View Javadoc

1   /*
2    * $Id: JsonData.java 21827 2011-05-06 17:35:25Z dandiep $
3    * --------------------------------------------------------------------------------------
4    * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
5    *
6    * The software in this package is published under the terms of the CPAL v1.0
7    * license, a copy of which has been included with this distribution in the
8    * LICENSE.txt file.
9    */
10  
11  package org.mule.module.json;
12  
13  import java.io.IOException;
14  import java.io.InputStream;
15  import java.io.Reader;
16  import java.io.Serializable;
17  import java.io.StringReader;
18  import java.net.URL;
19  import java.util.ArrayList;
20  import java.util.Iterator;
21  import java.util.List;
22  
23  import org.codehaus.jackson.JsonNode;
24  import org.codehaus.jackson.map.ObjectMapper;
25  
26  /**
27   * A wrapper for the {@link org.codehaus.jackson.JsonNode} object that
28   * allows for nested object keys i.e. user/name will return the name property on
29   * the user object.
30   * <p/>
31   * There is no 'xpath' for JSON yet (though I expect Jackson to do implement this at some point).  
32   * This class provides a simple way to navigate a Json data structure. To select a child entry use -
33   * <code>
34   * person/name
35   * </code>
36   * <p/>
37   * to access array data, use square braces with an index value i.e.
38   * <code>
39   * person/addresses[0]/postcode
40   * <p/>
41   * or
42   * <p/>
43   * [0]/arrayElement
44   * </code>
45   * <p/>
46   * Also, multi-dimensional arrays can be accessed using:
47   * <code>
48   * filters[1]/init[1][0]
49   * </code>
50   * <p/>
51   * if a Json property name contains a '/' the name needs to be quoted with single quotes i.e.
52   * <p/>
53   * <code>
54   * results/'http://foo.com'/value
55   * </code>
56   */
57  public class JsonData implements Serializable
58  {
59      private JsonNode node;
60  
61      public JsonData(JsonNode node)
62      {
63          this.node = node;
64      }
65  
66      public JsonData(URL node) throws IOException
67      {
68          this(node.openStream());
69      }
70  
71      public JsonData(InputStream node) throws IOException
72      {
73          this.node = new ObjectMapper().readTree(node);
74      }
75  
76      public JsonData(Reader node) throws IOException
77      {
78          this.node = new ObjectMapper().readTree(node);
79      }
80  
81      public JsonData(String node) throws IOException
82      {
83          this(new StringReader(node));
84      }
85  
86      public JsonNode get(int index)
87      {
88          return node.get(index);
89      }
90  
91      public boolean isArray()
92      {
93          return node.isArray();
94      }
95      
96      public JsonNode[] toArray() 
97      {
98          List<JsonNode> children = new ArrayList<JsonNode>();
99          for (Iterator<JsonNode> itr = node.getElements(); itr.hasNext();) 
100         {
101             children.add(itr.next());
102         }
103         return children.toArray(new JsonNode[children.size()]);
104     }
105 
106     public JsonNode get(String expression)
107     {
108         List<String> tokens = parseTokens(expression);
109 
110         JsonNode o = node;
111         for (String token : tokens)
112         {
113             if (token.startsWith("["))
114             {
115                 if (o.isArray())
116                 {
117                     int index = Integer.valueOf(token.substring(1, token.length() - 1));
118                     o = o.path(index);
119                 }
120                 else
121                 {
122                     throw new IllegalArgumentException("Current node is not an array, but expression is expecting one");
123                 }
124             }
125             else
126             {
127                 o = o.path(token);
128             }
129 
130             if (o.isMissingNode())
131             {
132                 throw new IllegalArgumentException("Not a valid element: " + token);
133             }
134         }
135 
136         return o;
137     }
138     
139     public String getAsString(String expression)
140     {
141         JsonNode node = get(expression);
142         if (node.isValueNode())
143         {
144             return node.getValueAsText();
145         }
146         else
147         {
148             return node.toString();
149         }
150     }
151     
152     public boolean hasNode(String key)
153     {
154         JsonNode result = node.path(key);
155         return result.isMissingNode() == false;
156     }
157 
158     protected List<String> parseTokens(String expresion)
159     {
160         List<String> tokens = new ArrayList<String>();
161         while (expresion.length() > 0)
162         {
163             int slash = expresion.indexOf("/");
164             int brace = expresion.indexOf("[");
165             //Handled quoted strings
166             if (expresion.charAt(0) == '\'')
167             {
168                 if (expresion.endsWith("'"))
169                 {
170                     tokens.add(expresion.substring(1, expresion.length() - 1));
171                     expresion = "";
172                 }
173                 else
174                 {
175                     int x = expresion.indexOf("'/");
176                     tokens.add(expresion.substring(1, x));
177                     expresion = expresion.substring(x + 2);
178                 }
179             }
180             else if (slash == -1 && brace == -1)
181             {
182                 tokens.add(expresion);
183                 expresion = "";
184             }
185             else if ((slash > -1 && slash < brace) || brace == -1)
186             {
187                 if (slash == 0)
188                 {
189                     if (expresion.charAt(1) == '\'')
190                     {
191                         int x = expresion.indexOf("'", 2);
192                         tokens.add(expresion.substring(2, x));
193                         expresion = expresion.substring(x + 1);
194                     }
195                     else if (expresion.charAt(1) == '[')
196                     {
197                         int i = expresion.indexOf("]", 1);
198                         tokens.add(expresion.substring(0, i));
199                         expresion = expresion.substring(i + 1);
200                     }
201                     else
202                     {
203                         expresion = expresion.substring(slash + 1);
204                     }
205                 }
206                 else
207                 {
208                     tokens.add(expresion.substring(0, slash));
209                     expresion = expresion.substring(slash + 1);
210                 }
211             }
212             else if (brace > 0)
213             {
214                 tokens.add(expresion.substring(0, brace));
215                 expresion = expresion.substring(brace);
216 
217             }
218             else
219             {
220                 int i = expresion.indexOf("]", brace);
221                 tokens.add(expresion.substring(0, i + 1));
222                 expresion = expresion.substring(i + 1);
223             }
224         }
225         return tokens;
226     }
227 
228     @Override
229     public boolean equals(Object obj)
230     {
231         return node.equals(obj);
232     }
233     
234     @Override
235     public int hashCode()
236     {
237         return node.hashCode();
238     }
239 
240     @Override
241     public String toString()
242     {
243         return node.toString();
244     }
245 }