• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 Google Inc.
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 
17 package com.google.gson.internal;
18 
19 import com.google.gson.JsonElement;
20 import com.google.gson.JsonIOException;
21 import com.google.gson.JsonNull;
22 import com.google.gson.JsonParseException;
23 import com.google.gson.JsonSyntaxException;
24 import com.google.gson.internal.bind.TypeAdapters;
25 import com.google.gson.stream.JsonReader;
26 import com.google.gson.stream.JsonWriter;
27 import com.google.gson.stream.MalformedJsonException;
28 import java.io.EOFException;
29 import java.io.IOException;
30 import java.io.Writer;
31 import java.util.Objects;
32 
33 /**
34  * Reads and writes GSON parse trees over streams.
35  */
36 public final class Streams {
Streams()37   private Streams() {
38     throw new UnsupportedOperationException();
39   }
40 
41   /**
42    * Takes a reader in any state and returns the next value as a JsonElement.
43    */
parse(JsonReader reader)44   public static JsonElement parse(JsonReader reader) throws JsonParseException {
45     boolean isEmpty = true;
46     try {
47       reader.peek();
48       isEmpty = false;
49       return TypeAdapters.JSON_ELEMENT.read(reader);
50     } catch (EOFException e) {
51       /*
52        * For compatibility with JSON 1.5 and earlier, we return a JsonNull for
53        * empty documents instead of throwing.
54        */
55       if (isEmpty) {
56         return JsonNull.INSTANCE;
57       }
58       // The stream ended prematurely so it is likely a syntax error.
59       throw new JsonSyntaxException(e);
60     } catch (MalformedJsonException e) {
61       throw new JsonSyntaxException(e);
62     } catch (IOException e) {
63       throw new JsonIOException(e);
64     } catch (NumberFormatException e) {
65       throw new JsonSyntaxException(e);
66     }
67   }
68 
69   /**
70    * Writes the JSON element to the writer, recursively.
71    */
write(JsonElement element, JsonWriter writer)72   public static void write(JsonElement element, JsonWriter writer) throws IOException {
73     TypeAdapters.JSON_ELEMENT.write(writer, element);
74   }
75 
writerForAppendable(Appendable appendable)76   public static Writer writerForAppendable(Appendable appendable) {
77     return appendable instanceof Writer ? (Writer) appendable : new AppendableWriter(appendable);
78   }
79 
80   /**
81    * Adapts an {@link Appendable} so it can be passed anywhere a {@link Writer}
82    * is used.
83    */
84   private static final class AppendableWriter extends Writer {
85     private final Appendable appendable;
86     private final CurrentWrite currentWrite = new CurrentWrite();
87 
AppendableWriter(Appendable appendable)88     AppendableWriter(Appendable appendable) {
89       this.appendable = appendable;
90     }
91 
write(char[] chars, int offset, int length)92     @Override public void write(char[] chars, int offset, int length) throws IOException {
93       currentWrite.setChars(chars);
94       appendable.append(currentWrite, offset, offset + length);
95     }
96 
flush()97     @Override public void flush() {}
close()98     @Override public void close() {}
99 
100     // Override these methods for better performance
101     // They would otherwise unnecessarily create Strings or char arrays
102 
write(int i)103     @Override public void write(int i) throws IOException {
104       appendable.append((char) i);
105     }
106 
write(String str, int off, int len)107     @Override public void write(String str, int off, int len) throws IOException {
108       // Appendable.append turns null -> "null", which is not desired here
109       Objects.requireNonNull(str);
110       appendable.append(str, off, off + len);
111     }
112 
append(CharSequence csq)113     @Override public Writer append(CharSequence csq) throws IOException {
114       appendable.append(csq);
115       return this;
116     }
117 
append(CharSequence csq, int start, int end)118     @Override public Writer append(CharSequence csq, int start, int end) throws IOException {
119       appendable.append(csq, start, end);
120       return this;
121     }
122 
123     /**
124      * A mutable char sequence pointing at a single char[].
125      */
126     private static class CurrentWrite implements CharSequence {
127       private char[] chars;
128       private String cachedString;
129 
setChars(char[] chars)130       void setChars(char[] chars) {
131         this.chars = chars;
132         this.cachedString = null;
133       }
134 
length()135       @Override public int length() {
136         return chars.length;
137       }
charAt(int i)138       @Override public char charAt(int i) {
139         return chars[i];
140       }
subSequence(int start, int end)141       @Override public CharSequence subSequence(int start, int end) {
142         return new String(chars, start, end - start);
143       }
144 
145       // Must return string representation to satisfy toString() contract
toString()146       @Override public String toString() {
147         if (cachedString == null) {
148           cachedString = new String(chars);
149         }
150         return cachedString;
151       }
152     }
153   }
154 }
155