-
Notifications
You must be signed in to change notification settings - Fork 4.3k
/
Streams.java
181 lines (159 loc) · 5.74 KB
/
Streams.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
/*
* Copyright (C) 2010 Google Inc.
*
* 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 com.google.gson.internal;
import com.google.gson.JsonElement;
import com.google.gson.JsonIOException;
import com.google.gson.JsonNull;
import com.google.gson.JsonParseException;
import com.google.gson.JsonParser;
import com.google.gson.JsonSyntaxException;
import com.google.gson.internal.bind.TypeAdapters;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
import com.google.gson.stream.JsonWriter;
import com.google.gson.stream.MalformedJsonException;
import java.io.EOFException;
import java.io.IOException;
import java.io.Writer;
import java.util.Objects;
/**
* Reads and writes GSON parse trees over streams.
*/
public final class Streams {
private Streams() {
throw new UnsupportedOperationException();
}
/**
* @deprecated
* This method is declared in an internal Gson class. Use the public API class {@link JsonParser}
* (note that {@code JsonParser} parses JSON in lenient mode), or obtain the {@code TypeAdapter}
* for {@code JsonElement} and use that for parsing:
* <pre>{@code
* TypeAdapter<JsonElement> adapter = gson.getAdapter(JsonElement.class);
* JsonElement element = adapter.read(...);
* }</pre>
*/
// Only keeping this internal method because third-party projects depend on it
@Deprecated
public static JsonElement parse(JsonReader reader) {
return parse(reader, false);
}
/**
* Takes a reader in any state and returns the next value as a JsonElement.
*
* @param requireEndDocument whether there must not be any trailing data after
* the JsonElement
*/
public static JsonElement parse(JsonReader reader, boolean requireEndDocument) throws JsonParseException {
boolean isEmpty = true;
try {
reader.peek();
isEmpty = false;
JsonElement element = TypeAdapters.JSON_ELEMENT.read(reader);
if (requireEndDocument && reader.peek() != JsonToken.END_DOCUMENT) {
throw new JsonSyntaxException("Did not consume the entire document.");
}
return element;
} catch (EOFException e) {
/*
* For compatibility with JSON 1.5 and earlier, we return a JsonNull for
* empty documents instead of throwing.
*/
if (isEmpty) {
return JsonNull.INSTANCE;
}
// The stream ended prematurely so it is likely a syntax error.
throw new JsonSyntaxException(e);
} catch (MalformedJsonException e) {
throw new JsonSyntaxException(e);
} catch (IOException e) {
throw new JsonIOException(e);
} catch (NumberFormatException e) {
throw new JsonSyntaxException(e);
}
}
/**
* Writes the JSON element to the writer, recursively.
*/
public static void write(JsonElement element, JsonWriter writer) throws IOException {
TypeAdapters.JSON_ELEMENT.write(writer, element);
}
public static Writer writerForAppendable(Appendable appendable) {
return appendable instanceof Writer ? (Writer) appendable : new AppendableWriter(appendable);
}
/**
* Adapts an {@link Appendable} so it can be passed anywhere a {@link Writer}
* is used.
*/
private static final class AppendableWriter extends Writer {
private final Appendable appendable;
private final CurrentWrite currentWrite = new CurrentWrite();
AppendableWriter(Appendable appendable) {
this.appendable = appendable;
}
@Override public void write(char[] chars, int offset, int length) throws IOException {
currentWrite.setChars(chars);
appendable.append(currentWrite, offset, offset + length);
}
@Override public void flush() {}
@Override public void close() {}
// Override these methods for better performance
// They would otherwise unnecessarily create Strings or char arrays
@Override public void write(int i) throws IOException {
appendable.append((char) i);
}
@Override public void write(String str, int off, int len) throws IOException {
// Appendable.append turns null -> "null", which is not desired here
Objects.requireNonNull(str);
appendable.append(str, off, off + len);
}
@Override public Writer append(CharSequence csq) throws IOException {
appendable.append(csq);
return this;
}
@Override public Writer append(CharSequence csq, int start, int end) throws IOException {
appendable.append(csq, start, end);
return this;
}
/**
* A mutable char sequence pointing at a single char[].
*/
private static class CurrentWrite implements CharSequence {
private char[] chars;
private String cachedString;
void setChars(char[] chars) {
this.chars = chars;
this.cachedString = null;
}
@Override public int length() {
return chars.length;
}
@Override public char charAt(int i) {
return chars[i];
}
@Override public CharSequence subSequence(int start, int end) {
return new String(chars, start, end - start);
}
// Must return string representation to satisfy toString() contract
@Override public String toString() {
if (cachedString == null) {
cachedString = new String(chars);
}
return cachedString;
}
}
}
}