package io.ebeaninternal.json;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import io.ebean.ModifyAwareType;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
class EJsonReader {
static final JsonFactory json = new JsonFactory();
@SuppressWarnings("unchecked")
static Map<String, Object> parseObject(String json, boolean modifyAware) throws IOException {
return (Map<String, Object>) parse(json, modifyAware);
}
@SuppressWarnings("unchecked")
static Map<String, Object> parseObject(String json) throws IOException {
return (Map<String, Object>) parse(json);
}
@SuppressWarnings("unchecked")
static Map<String, Object> parseObject(Reader reader) throws IOException {
return (Map<String, Object>) parse(reader);
}
@SuppressWarnings("unchecked")
static Map<String, Object> parseObject(Reader reader, boolean modifyAware) throws IOException {
return (Map<String, Object>) parse(reader, modifyAware);
}
@SuppressWarnings("unchecked")
static Map<String, Object> parseObject(JsonParser parser) throws IOException {
return (Map<String, Object>) parse(parser);
}
@SuppressWarnings("unchecked")
static Map<String, Object> parseObject(JsonParser parser, JsonToken token) throws IOException {
return (Map<String, Object>) parse(parser, token, false);
}
@SuppressWarnings("unchecked")
static <T> List<T> parseList(String json, boolean modifyAware) throws IOException {
return (List<T>) parse(json, modifyAware);
}
@SuppressWarnings("unchecked")
static List<Object> parseList(String json) throws IOException {
return (List<Object>) parse(json);
}
@SuppressWarnings("unchecked")
static List<Object> parseList(Reader reader) throws IOException {
return (List<Object>) parse(reader);
}
@SuppressWarnings("unchecked")
static List<Object> parseList(JsonParser parser, boolean modifyAware) throws IOException {
return (List<Object>) parse(parser, modifyAware);
}
static Object parse(String json) throws IOException {
if (json == null) {
return null;
}
return parse(new StringReader(json));
}
static Object parse(String json, boolean modifyAware) throws IOException {
if (json == null) {
return null;
}
return parse(new StringReader(json), modifyAware);
}
static Object parse(Reader reader) throws IOException {
return parse(json.createParser(reader));
}
static Object parse(Reader reader, boolean modifyAware) throws IOException {
return parse(json.createParser(reader), modifyAware);
}
static Object parse(JsonParser parser) throws IOException {
return parse(parser, null, false);
}
static Object parse(JsonParser parser, boolean modifyAware) throws IOException {
return parse(parser, null, modifyAware);
}
static Object parse(JsonParser parser, JsonToken token, boolean modifyAware) throws IOException {
return new EJsonReader(parser, modifyAware).parseJson(token);
}
private final JsonParser parser;
private final boolean modifyAware;
private final ModifyAwareFlag modifyAwareOwner;
private int depth;
private Stack stack;
private Context currentContext;
EJsonReader(JsonParser parser, boolean modifyAware) {
this.parser = parser;
this.modifyAware = modifyAware;
this.modifyAwareOwner = (modifyAware) ? new ModifyAwareFlag() : null;
}
private void startArray() {
depth++;
stack.push(currentContext);
currentContext = modifyAware ? new ArrayContext(modifyAwareOwner) : new ArrayContext();
}
private void startObject() {
depth++;
stack.push(currentContext);
currentContext = modifyAware ? new ObjectContext(modifyAwareOwner) : new ObjectContext();
}
private void endArray() {
end();
}
private void endObject() {
end();
}
private void end() {
depth--;
if (!stack.isEmpty()) {
currentContext = stack.pop(currentContext);
}
if (modifyAwareOwner != null) {
modifyAwareOwner.setMarkedDirty(false);
}
}
private void setValue(Object value) {
currentContext.setValue(value);
}
private void setValueNull() {
currentContext.setValueNull();
}
private Object parseJson(JsonToken token) throws IOException {
if (token == null) {
token = parser.nextToken();
switch (token) {
case VALUE_NULL:
return null;
case VALUE_FALSE:
return Boolean.FALSE;
case VALUE_TRUE:
return Boolean.TRUE;
case VALUE_STRING:
return parser.getText();
case VALUE_NUMBER_INT:
return parser.getLongValue();
case VALUE_NUMBER_FLOAT:
return parser.getDecimalValue();
}
}
stack = new Stack();
processJsonToken(token);
while (depth > 0) {
token = parser.nextToken();
processJsonToken(token);
}
return currentContext.getValue();
}
private void processJsonToken(JsonToken token) throws IOException {
switch (token) {
case START_ARRAY:
startArray();
break;
case START_OBJECT:
startObject();
break;
case FIELD_NAME:
currentContext.setKey(parser.getCurrentName());
break;
case VALUE_STRING:
setValue(parser.getValueAsString());
break;
case VALUE_NUMBER_INT:
setValue(parser.getLongValue());
break;
case VALUE_NUMBER_FLOAT:
setValue(parser.getDecimalValue());
break;
case VALUE_TRUE:
setValue(Boolean.TRUE);
break;
case VALUE_FALSE:
setValue(Boolean.FALSE);
break;
case VALUE_NULL:
setValueNull();
break;
case END_OBJECT:
endObject();
break;
case END_ARRAY:
endArray();
break;
default:
break;
}
}
private static final class Stack {
private Context head;
private void push(Context context) {
if (context != null) {
context.next = head;
head = context;
}
}
private Context pop(Context endingContext) {
if (head == null) {
throw new NoSuchElementException();
}
Context temp = head;
head = head.next;
temp.popContext(endingContext);
return temp;
}
private boolean isEmpty() {
return head == null;
}
}
private static abstract class Context {
Context next;
abstract void popContext(Context temp);
abstract Object getValue();
abstract void setKey(String key);
abstract void setValue(Object value);
abstract void setValueNull();
}
private static class ObjectContext extends Context {
private final Map<String, Object> map;
private String key;
ObjectContext() {
map = new LinkedHashMap<>();
}
ObjectContext(ModifyAwareType owner) {
map = new ModifyAwareMap<>(owner, new LinkedHashMap<>());
}
@Override
public void popContext(Context temp) {
setValue(temp.getValue());
}
@Override
Object getValue() {
return map;
}
@Override
void setKey(String key) {
this.key = key;
}
@Override
void setValue(Object value) {
map.put(key, value);
}
@Override
void setValueNull() {
map.put(key, null);
}
}
private static class ArrayContext extends Context {
private final List<Object> values;
ArrayContext() {
values = new ArrayList<>();
}
ArrayContext(ModifyAwareType owner) {
values = new ModifyAwareList<>(owner, new ArrayList<>());
}
@Override
public void popContext(Context temp) {
values.add(temp.getValue());
}
@Override
Object getValue() {
return values;
}
@Override
void setValue(Object value) {
values.add(value);
}
@Override
void setValueNull() {
}
@Override
void setKey(String key) {
}
}
}