@Override public @Nullable T fromJson(JsonReader reader) throws IOException { if (reader.peek() == JsonReader.Token.NULL) { throw new JsonDataException("Unexpected null at " + reader.getPath()); } else { return delegate.fromJson(reader); throw new JsonDataException("Unexpected null at " + writer.getPath()); } else { delegate.toJson(writer, value);
private void push(Object newTop) { if (stackSize == stack.length) { if (stackSize == 256) { throw new JsonDataException("Nesting too deep at " + getPath()); } scopes = Arrays.copyOf(scopes, scopes.length * 2); pathNames = Arrays.copyOf(pathNames, pathNames.length * 2); pathIndices = Arrays.copyOf(pathIndices, pathIndices.length * 2); stack = Arrays.copyOf(stack, stack.length * 2); } stack[stackSize++] = newTop; }
final void pushScope(int newTop) { if (stackSize == scopes.length) { if (stackSize == 256) { throw new JsonDataException("Nesting too deep at " + getPath()); } scopes = Arrays.copyOf(scopes, scopes.length * 2); pathNames = Arrays.copyOf(pathNames, pathNames.length * 2); pathIndices = Arrays.copyOf(pathIndices, pathIndices.length * 2); } scopes[stackSize++] = newTop; }
final JsonDataException typeMismatch(@Nullable Object value, Object expected) { if (value == null) { return new JsonDataException( "Expected " + expected + " but was null at path " + getPath()); } else { return new JsonDataException("Expected " + expected + " but was " + value + ", a " + value.getClass().getName() + ", at path " + getPath()); } }
/** Before pushing a value on the stack this confirms that the stack has capacity. */ final boolean checkStack() { if (stackSize != scopes.length) return false; if (stackSize == 256) { throw new JsonDataException("Nesting too deep at " + getPath() + ": circular reference?"); } scopes = Arrays.copyOf(scopes, scopes.length * 2); pathNames = Arrays.copyOf(pathNames, pathNames.length * 2); pathIndices = Arrays.copyOf(pathIndices, pathIndices.length * 2); if (this instanceof JsonValueWriter) { ((JsonValueWriter) this).stack = Arrays.copyOf(((JsonValueWriter) this).stack, ((JsonValueWriter) this).stack.length * 2); } return true; }
@Override public Character fromJson(JsonReader reader) throws IOException { String value = reader.nextString(); if (value.length() > 1) { throw new JsonDataException( String.format(ERROR_FORMAT, "a char", '"' + value + '"', reader.getPath())); } return value.charAt(0); }
static int rangeCheckNextInt(JsonReader reader, String typeMessage, int min, int max) throws IOException { int value = reader.nextInt(); if (value < min || value > max) { throw new JsonDataException( String.format(ERROR_FORMAT, typeMessage, value, reader.getPath())); } return value; }
@Override public void toJson(JsonWriter writer, @Nullable T value) throws IOException { if (value == null) { throw new JsonDataException("Unexpected null at " + writer.getPath()); } else { delegate.toJson(writer, value); } } @Override boolean isLenient() {
@FromJson Card fromJson(String card) { if (card.length() != 2) throw new JsonDataException("Unknown card: " + card); char rank = card.charAt(0); switch (card.charAt(1)) { case 'C': return new Card(rank, Suit.CLUBS); case 'D': return new Card(rank, Suit.DIAMONDS); case 'H': return new Card(rank, Suit.HEARTS); case 'S': return new Card(rank, Suit.SPADES); default: throw new JsonDataException("unknown suit: " + card); } } }
@FromJson @CardString Card fromJson(String card) { if (card.length() != 2) throw new JsonDataException("Unknown card: " + card); char rank = card.charAt(0); switch (card.charAt(1)) { case 'C': return new Card(rank, Suit.CLUBS); case 'D': return new Card(rank, Suit.DIAMONDS); case 'H': return new Card(rank, Suit.HEARTS); case 'S': return new Card(rank, Suit.SPADES); default: throw new JsonDataException("unknown suit: " + card); } } }
@Override public @Nullable T fromJson(JsonReader reader) throws IOException { if (reader.peek() == JsonReader.Token.NULL) { throw new JsonDataException("Unexpected null at " + reader.getPath()); } else { return delegate.fromJson(reader); } } @Override public void toJson(JsonWriter writer, @Nullable T value) throws IOException {
@Override public T fromJson(JsonReader reader) throws IOException { int index = reader.selectString(options); if (index != -1) return constants[index]; // We can consume the string safely, we are terminating anyway. String path = reader.getPath(); String name = reader.nextString(); throw new JsonDataException("Expected one of " + Arrays.asList(nameStrings) + " but was " + name + " at path " + path); }
@Override public void skipName() throws IOException { if (failOnUnknown) { throw new JsonDataException("Cannot skip unexpected " + peek() + " at " + getPath()); } Map.Entry<?, ?> peeked = require(Map.Entry.class, Token.NAME); // Swap the Map.Entry for its value on the stack. stack[stackSize - 1] = peeked.getValue(); pathNames[stackSize - 2] = "null"; }
@Override public Float fromJson(JsonReader reader) throws IOException { float value = (float) reader.nextDouble(); // Double check for infinity after float conversion; many doubles > Float.MAX if (!reader.isLenient() && Float.isInfinite(value)) { throw new JsonDataException("JSON forbids NaN and infinities: " + value + " at path " + reader.getPath()); } return value; }
@Override public @Nullable <T> T nextNull() throws IOException { int p = peeked; if (p == PEEKED_NONE) { p = doPeek(); } if (p == PEEKED_NULL) { peeked = PEEKED_NONE; pathIndices[stackSize - 1]++; return null; } else { throw new JsonDataException("Expected null but was " + peek() + " at path " + getPath()); } }
@CheckReturnValue public final @Nullable T fromJson(String string) throws IOException { JsonReader reader = JsonReader.of(new Buffer().writeUtf8(string)); T result = fromJson(reader); if (!isLenient() && reader.peek() != JsonReader.Token.END_DOCUMENT) { throw new JsonDataException("JSON document was not fully consumed."); } return result; }
@Override public void toJson(JsonWriter writer, Map<K, V> map) throws IOException { writer.beginObject(); for (Map.Entry<K, V> entry : map.entrySet()) { if (entry.getKey() == null) { throw new JsonDataException("Map key is null at " + writer.getPath()); } writer.promoteValueToName(); keyAdapter.toJson(writer, entry.getKey()); valueAdapter.toJson(writer, entry.getValue()); } writer.endObject(); }
@Override public void toJson(JsonWriter writer, @Nullable Object value) throws IOException { if (toAdapter == null) { delegate.toJson(writer, value); } else if (!toAdapter.nullable && value == null) { writer.nullValue(); } else { try { toAdapter.toJson(moshi, writer, value); } catch (InvocationTargetException e) { Throwable cause = e.getCause(); if (cause instanceof IOException) throw (IOException) cause; throw new JsonDataException(cause + " at " + writer.getPath(), cause); } } }
@Override public @Nullable T fromJson(JsonReader reader) throws IOException { int index = reader.selectString(options); if (index != -1) return constants[index]; String path = reader.getPath(); if (!useFallbackValue) { String name = reader.nextString(); throw new JsonDataException("Expected one of " + Arrays.asList(nameStrings) + " but was " + name + " at path " + path); } if (reader.peek() != JsonReader.Token.STRING) { throw new JsonDataException( "Expected a string but was " + reader.peek() + " at path " + path); } reader.skipValue(); return fallbackValue; }
@Override public void skipValue() throws IOException { if (failOnUnknown) { throw new JsonDataException("Cannot skip unexpected " + peek() + " at " + getPath()); } // If this element is in an object clear out the key. if (stackSize > 1) { pathNames[stackSize - 2] = "null"; } Object skipped = stackSize != 0 ? stack[stackSize - 1] : null; if (skipped instanceof JsonIterator) { throw new JsonDataException("Expected a value but was " + peek() + " at path " + getPath()); } if (skipped instanceof Map.Entry) { // We're skipping a name. Promote the map entry's value. Map.Entry<?, ?> entry = (Map.Entry<?, ?>) stack[stackSize - 1]; stack[stackSize - 1] = entry.getValue(); } else if (stackSize > 0) { // We're skipping a value. remove(); } else { throw new JsonDataException("Expected a value but was " + peek() + " at path " + getPath()); } }