mirror of
https://github.com/fankes/moshi.git
synced 2025-10-19 16:09:21 +08:00
Small optimizations to JSON parsing.
Prefer LinkedHashMap for maps that will be queried heavily. Inline a single-line method to refill the buffer.
This commit is contained in:
@@ -304,7 +304,7 @@ final class BufferedSourceJsonReader extends JsonReader {
|
|||||||
break;
|
break;
|
||||||
case '=':
|
case '=':
|
||||||
checkLenient();
|
checkLenient();
|
||||||
if (fillBuffer(1) && buffer.getByte(0) == '>') {
|
if (source.request(1) && buffer.getByte(0) == '>') {
|
||||||
buffer.readByte(); // Consume '>'.
|
buffer.readByte(); // Consume '>'.
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -400,7 +400,7 @@ final class BufferedSourceJsonReader extends JsonReader {
|
|||||||
// Confirm that chars [1..length) match the keyword.
|
// Confirm that chars [1..length) match the keyword.
|
||||||
int length = keyword.length();
|
int length = keyword.length();
|
||||||
for (int i = 1; i < length; i++) {
|
for (int i = 1; i < length; i++) {
|
||||||
if (!fillBuffer(i + 1)) {
|
if (!source.request(i + 1)) {
|
||||||
return PEEKED_NONE;
|
return PEEKED_NONE;
|
||||||
}
|
}
|
||||||
c = buffer.getByte(i);
|
c = buffer.getByte(i);
|
||||||
@@ -409,7 +409,7 @@ final class BufferedSourceJsonReader extends JsonReader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fillBuffer(length + 1) && isLiteral(buffer.getByte(length))) {
|
if (source.request(length + 1) && isLiteral(buffer.getByte(length))) {
|
||||||
return PEEKED_NONE; // Don't match trues, falsey or nullsoft!
|
return PEEKED_NONE; // Don't match trues, falsey or nullsoft!
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -428,7 +428,7 @@ final class BufferedSourceJsonReader extends JsonReader {
|
|||||||
|
|
||||||
charactersOfNumber:
|
charactersOfNumber:
|
||||||
for (; true; i++) {
|
for (; true; i++) {
|
||||||
if (!fillBuffer(i + 1)) {
|
if (!source.request(i + 1)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -880,15 +880,6 @@ final class BufferedSourceJsonReader extends JsonReader {
|
|||||||
stack[stackSize++] = newTop;
|
stack[stackSize++] = newTop;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true once {@code limit - pos >= minimum}. If the data is
|
|
||||||
* exhausted before that many characters are available, this returns
|
|
||||||
* false.
|
|
||||||
*/
|
|
||||||
private boolean fillBuffer(int minimum) throws IOException {
|
|
||||||
return source.request(minimum);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the next character in the stream that is neither whitespace nor a
|
* Returns the next character in the stream that is neither whitespace nor a
|
||||||
* part of a comment. When this returns, the returned character is always at
|
* part of a comment. When this returns, the returned character is always at
|
||||||
@@ -905,7 +896,7 @@ final class BufferedSourceJsonReader extends JsonReader {
|
|||||||
* 'p' and 'l' after any (potentially indirect) call to the same method.
|
* 'p' and 'l' after any (potentially indirect) call to the same method.
|
||||||
*/
|
*/
|
||||||
int p = 0;
|
int p = 0;
|
||||||
while (fillBuffer(p + 1)) {
|
while (source.request(p + 1)) {
|
||||||
int c = buffer.getByte(p++);
|
int c = buffer.getByte(p++);
|
||||||
if (c == '\n' || c == ' ' || c == '\r' || c == '\t') {
|
if (c == '\n' || c == ' ' || c == '\r' || c == '\t') {
|
||||||
continue;
|
continue;
|
||||||
@@ -913,7 +904,7 @@ final class BufferedSourceJsonReader extends JsonReader {
|
|||||||
|
|
||||||
buffer.skip(p - 1);
|
buffer.skip(p - 1);
|
||||||
if (c == '/') {
|
if (c == '/') {
|
||||||
if (!fillBuffer(2)) {
|
if (!source.request(2)) {
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -981,7 +972,7 @@ final class BufferedSourceJsonReader extends JsonReader {
|
|||||||
*/
|
*/
|
||||||
private boolean skipTo(String toFind) throws IOException {
|
private boolean skipTo(String toFind) throws IOException {
|
||||||
outer:
|
outer:
|
||||||
for (; fillBuffer(toFind.length());) {
|
for (; source.request(toFind.length());) {
|
||||||
for (int c = 0; c < toFind.length(); c++) {
|
for (int c = 0; c < toFind.length(); c++) {
|
||||||
if (buffer.getByte(c) != toFind.charAt(c)) {
|
if (buffer.getByte(c) != toFind.charAt(c)) {
|
||||||
buffer.readByte();
|
buffer.readByte();
|
||||||
@@ -1009,14 +1000,14 @@ final class BufferedSourceJsonReader extends JsonReader {
|
|||||||
* @throws IOException if any unicode escape sequences are malformed.
|
* @throws IOException if any unicode escape sequences are malformed.
|
||||||
*/
|
*/
|
||||||
private char readEscapeCharacter() throws IOException {
|
private char readEscapeCharacter() throws IOException {
|
||||||
if (!fillBuffer(1)) {
|
if (!source.request(1)) {
|
||||||
throw syntaxError("Unterminated escape sequence");
|
throw syntaxError("Unterminated escape sequence");
|
||||||
}
|
}
|
||||||
|
|
||||||
byte escaped = buffer.readByte();
|
byte escaped = buffer.readByte();
|
||||||
switch (escaped) {
|
switch (escaped) {
|
||||||
case 'u':
|
case 'u':
|
||||||
if (!fillBuffer(4)) {
|
if (!source.request(4)) {
|
||||||
throw new EOFException("Unterminated escape sequence at path " + getPath());
|
throw new EOFException("Unterminated escape sequence at path " + getPath());
|
||||||
}
|
}
|
||||||
// Equivalent to Integer.parseInt(stringPool.get(buffer, pos, 4), 16);
|
// Equivalent to Integer.parseInt(stringPool.get(buffer, pos, 4), 16);
|
||||||
|
@@ -21,6 +21,7 @@ import java.lang.reflect.Field;
|
|||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Modifier;
|
import java.lang.reflect.Modifier;
|
||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
@@ -81,11 +82,11 @@ final class ClassJsonAdapter<T> extends JsonAdapter<T> {
|
|||||||
|
|
||||||
// Create the binding between field and JSON.
|
// Create the binding between field and JSON.
|
||||||
field.setAccessible(true);
|
field.setAccessible(true);
|
||||||
FieldBinding<Object> fieldBinding = new FieldBinding<>(field, adapter);
|
|
||||||
|
|
||||||
// Store it using the field's name. If there was already a field with this name, fail!
|
// Store it using the field's name. If there was already a field with this name, fail!
|
||||||
Json jsonAnnotation = field.getAnnotation(Json.class);
|
Json jsonAnnotation = field.getAnnotation(Json.class);
|
||||||
String name = jsonAnnotation != null ? jsonAnnotation.name() : field.getName();
|
String name = jsonAnnotation != null ? jsonAnnotation.name() : field.getName();
|
||||||
|
FieldBinding<Object> fieldBinding = new FieldBinding<>(name, field, adapter);
|
||||||
FieldBinding<?> replaced = fieldBindings.put(name, fieldBinding);
|
FieldBinding<?> replaced = fieldBindings.put(name, fieldBinding);
|
||||||
if (replaced != null) {
|
if (replaced != null) {
|
||||||
throw new IllegalArgumentException("Conflicting fields:\n"
|
throw new IllegalArgumentException("Conflicting fields:\n"
|
||||||
@@ -113,11 +114,13 @@ final class ClassJsonAdapter<T> extends JsonAdapter<T> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
private final ClassFactory<T> classFactory;
|
private final ClassFactory<T> classFactory;
|
||||||
private final Map<String, FieldBinding<?>> jsonFields;
|
private final Map<String, FieldBinding<?>> fieldsMap;
|
||||||
|
private final FieldBinding<?>[] fieldsArray;
|
||||||
|
|
||||||
ClassJsonAdapter(ClassFactory<T> classFactory, Map<String, FieldBinding<?>> jsonFields) {
|
ClassJsonAdapter(ClassFactory<T> classFactory, Map<String, FieldBinding<?>> fieldsMap) {
|
||||||
this.classFactory = classFactory;
|
this.classFactory = classFactory;
|
||||||
this.jsonFields = jsonFields;
|
this.fieldsMap = new LinkedHashMap<>(fieldsMap);
|
||||||
|
this.fieldsArray = fieldsMap.values().toArray(new FieldBinding[fieldsMap.size()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public T fromJson(JsonReader reader) throws IOException {
|
@Override public T fromJson(JsonReader reader) throws IOException {
|
||||||
@@ -139,7 +142,7 @@ final class ClassJsonAdapter<T> extends JsonAdapter<T> {
|
|||||||
reader.beginObject();
|
reader.beginObject();
|
||||||
while (reader.hasNext()) {
|
while (reader.hasNext()) {
|
||||||
String name = reader.nextName();
|
String name = reader.nextName();
|
||||||
FieldBinding<?> fieldBinding = jsonFields.get(name);
|
FieldBinding<?> fieldBinding = fieldsMap.get(name);
|
||||||
if (fieldBinding != null) {
|
if (fieldBinding != null) {
|
||||||
fieldBinding.read(reader, result);
|
fieldBinding.read(reader, result);
|
||||||
} else {
|
} else {
|
||||||
@@ -156,9 +159,9 @@ final class ClassJsonAdapter<T> extends JsonAdapter<T> {
|
|||||||
@Override public void toJson(JsonWriter writer, T value) throws IOException {
|
@Override public void toJson(JsonWriter writer, T value) throws IOException {
|
||||||
try {
|
try {
|
||||||
writer.beginObject();
|
writer.beginObject();
|
||||||
for (Map.Entry<String, FieldBinding<?>> entry : jsonFields.entrySet()) {
|
for (FieldBinding<?> fieldBinding : fieldsArray) {
|
||||||
writer.name(entry.getKey());
|
writer.name(fieldBinding.name);
|
||||||
entry.getValue().write(writer, value);
|
fieldBinding.write(writer, value);
|
||||||
}
|
}
|
||||||
writer.endObject();
|
writer.endObject();
|
||||||
} catch (IllegalAccessException e) {
|
} catch (IllegalAccessException e) {
|
||||||
@@ -171,10 +174,12 @@ final class ClassJsonAdapter<T> extends JsonAdapter<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static class FieldBinding<T> {
|
static class FieldBinding<T> {
|
||||||
private final Field field;
|
final String name;
|
||||||
private final JsonAdapter<T> adapter;
|
final Field field;
|
||||||
|
final JsonAdapter<T> adapter;
|
||||||
|
|
||||||
public FieldBinding(Field field, JsonAdapter<T> adapter) {
|
public FieldBinding(String name, Field field, JsonAdapter<T> adapter) {
|
||||||
|
this.name = name;
|
||||||
this.field = field;
|
this.field = field;
|
||||||
this.adapter = adapter;
|
this.adapter = adapter;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user