mirror of
https://github.com/ebean-orm/ebean.git
synced 2026-10-20 00:17:04 +00:00
Replace EJson internals with avaje JsonMapper
Reworks the DJsonService (the SpiJsonService SPI behind io.ebean.text.json.EJson) to use avaje JsonMapper instead of the bespoke EJsonReader/EJsonWriter, consolidating all read/write logic into a single JsonAdapter. Changes - New EbeanJsonAdapter — a JsonAdapter<Object> that materializes JSON into plain or modify-aware Map/List/Set, with two shared singletons (PLAIN, MODIFY_AWARE). Preserves existing EJson semantics: - Integral numbers → Long, decimals → BigDecimal - Write coverage for String/Integer/Long/Double/Float/BigDecimal/Boolean/Map/Collection with a toString() fallback for other types (UUID, enum, etc.) - Modify-aware loads share a single ModifyAwareFlag owner per root, reset to non-dirty once after the load completes - DJsonService now builds one JsonMapper + two JsonMapper.Type<Object> and routes parse/write through them. Null serialization is retained via a serializeNulls(true) writer; null/blank-input guards, token-honoring entry points, and parseSet (modify-aware asSet()) are preserved. - EJsonReader/EJsonWriter are now unused and should be deleted (couldn't remove them in this environment). Why Simplifies Ebean's JSON handling by reusing avaje-json-core's JsonMapper rather than maintaining a parallel reader/writer, while keeping behavior identical.
This commit is contained in:
@@ -3,10 +3,13 @@ package io.ebeaninternal.json;
|
||||
import io.avaje.json.JsonReader;
|
||||
import io.avaje.json.JsonReader.Token;
|
||||
import io.avaje.json.JsonWriter;
|
||||
import io.avaje.json.mapper.JsonMapper;
|
||||
import io.avaje.json.stream.JsonStream;
|
||||
import io.ebean.service.SpiJsonService;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.io.StringWriter;
|
||||
import java.io.Writer;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashSet;
|
||||
@@ -16,98 +19,136 @@ import java.util.Set;
|
||||
|
||||
/**
|
||||
* Utility that converts between JSON content and simple java Maps/Lists.
|
||||
* <p>
|
||||
* Backed by avaje {@link JsonMapper} using {@link EbeanJsonAdapter} which
|
||||
* preserves Ebean's modify-aware collection and number semantics.
|
||||
*/
|
||||
public final class DJsonService implements SpiJsonService {
|
||||
|
||||
private static final JsonStream JSON_STREAM = JsonStream.builder().build();
|
||||
private static final JsonMapper MAPPER = JsonMapper.builder().jsonStream(JSON_STREAM).build();
|
||||
|
||||
private static final JsonMapper.Type<Object> PLAIN = MAPPER.type(EbeanJsonAdapter.PLAIN);
|
||||
private static final JsonMapper.Type<Object> MODIFY_AWARE = MAPPER.type(EbeanJsonAdapter.MODIFY_AWARE);
|
||||
|
||||
private static JsonMapper.Type<Object> type(boolean modifyAware) {
|
||||
return modifyAware ? MODIFY_AWARE : PLAIN;
|
||||
}
|
||||
|
||||
private static boolean blank(String content) {
|
||||
return content == null || content.trim().isEmpty();
|
||||
}
|
||||
|
||||
private static String readAll(Reader reader) throws IOException {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
char[] buffer = new char[2048];
|
||||
int len;
|
||||
while ((len = reader.read(buffer)) != -1) {
|
||||
builder.append(buffer, 0, len);
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String write(Object object) throws IOException {
|
||||
return EJsonWriter.write(object);
|
||||
StringWriter writer = new StringWriter();
|
||||
write(object, writer);
|
||||
return writer.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(Object object, Writer writer) throws IOException {
|
||||
EJsonWriter.write(object, writer);
|
||||
JsonWriter jsonWriter = JSON_STREAM.writer(writer);
|
||||
jsonWriter.serializeNulls(true);
|
||||
PLAIN.toJson(object, jsonWriter);
|
||||
jsonWriter.flush();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(Object object, JsonWriter jsonWriter) throws IOException {
|
||||
EJsonWriter.write(object, jsonWriter);
|
||||
PLAIN.toJson(object, jsonWriter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeCollection(Collection<Object> collection, JsonWriter jsonWriter) throws IOException {
|
||||
EJsonWriter.writeCollection(collection, jsonWriter);
|
||||
EbeanJsonAdapter.writeCollection(jsonWriter, collection);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public Map<String, Object> parseObject(String json, boolean modifyAware) throws IOException {
|
||||
return EJsonReader.parseObject(json, modifyAware);
|
||||
return blank(json) ? null : (Map<String, Object>) type(modifyAware).fromJson(json);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> parseObject(String json) throws IOException {
|
||||
return EJsonReader.parseObject(json);
|
||||
return parseObject(json, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> parseObject(Reader reader, boolean modifyAware) throws IOException {
|
||||
return EJsonReader.parseObject(reader, modifyAware);
|
||||
return parseObject(readAll(reader), modifyAware);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> parseObject(Reader reader) throws IOException {
|
||||
return EJsonReader.parseObject(reader);
|
||||
return parseObject(reader, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public Map<String, Object> parseObject(JsonReader parser) throws IOException {
|
||||
return EJsonReader.parseObject(parser);
|
||||
return (Map<String, Object>) PLAIN.fromJson(parser);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public Map<String, Object> parseObject(JsonReader parser, Token token) throws IOException {
|
||||
return EJsonReader.parseObject(parser, token);
|
||||
return (Map<String, Object>) EbeanJsonAdapter.read(parser, token, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> List<T> parseList(String json, boolean modifyAware) throws IOException {
|
||||
return EJsonReader.parseList(json, modifyAware);
|
||||
return blank(json) ? null : (List<T>) type(modifyAware).fromJson(json);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public List<Object> parseList(String json) throws IOException {
|
||||
return EJsonReader.parseList(json);
|
||||
return (List<Object>) parseList(json, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Object> parseList(Reader reader) throws IOException {
|
||||
return EJsonReader.parseList(reader);
|
||||
return parseList(readAll(reader));
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public List<Object> parseList(JsonReader parser) throws IOException {
|
||||
return EJsonReader.parseList(parser, false);
|
||||
return (List<Object>) PLAIN.fromJson(parser);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> List<T> parseList(JsonReader parser, Token currentToken) throws IOException {
|
||||
return (List<T>) EJsonReader.parse(parser, currentToken, false);
|
||||
return (List<T>) EbeanJsonAdapter.read(parser, currentToken, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object parse(String json) throws IOException {
|
||||
return EJsonReader.parse(json);
|
||||
return blank(json) ? null : PLAIN.fromJson(json);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object parse(Reader reader) throws IOException {
|
||||
return EJsonReader.parse(reader);
|
||||
return parse(readAll(reader));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object parse(JsonReader parser) throws IOException {
|
||||
return EJsonReader.parse(parser);
|
||||
return PLAIN.fromJson(parser);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,204 +0,0 @@
|
||||
package io.ebeaninternal.json;
|
||||
|
||||
import io.avaje.json.JsonReader;
|
||||
import io.avaje.json.JsonReader.Token;
|
||||
import io.avaje.json.stream.JsonStream;
|
||||
import io.ebean.ModifyAwareType;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
final class EJsonReader {
|
||||
|
||||
private EJsonReader() {
|
||||
}
|
||||
|
||||
private static JsonReader reader(String content) {
|
||||
return JsonStream.builder().build().reader(content);
|
||||
}
|
||||
|
||||
@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(JsonReader parser) throws IOException {
|
||||
return (Map<String, Object>) parse(parser);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
static Map<String, Object> parseObject(JsonReader parser, Token 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(JsonReader parser, boolean modifyAware) throws IOException {
|
||||
return (List<Object>) parse(parser, null, modifyAware);
|
||||
}
|
||||
|
||||
static Object parse(String json) throws IOException {
|
||||
return parseRawJson(json, null);
|
||||
}
|
||||
|
||||
static Object parse(String json, boolean modifyAware) throws IOException {
|
||||
return parseRawJson(json, modifyAware ? new ModifyAwareFlag() : null);
|
||||
}
|
||||
|
||||
static Object parse(Reader reader) throws IOException {
|
||||
return parseRawJson(readAll(reader), null);
|
||||
}
|
||||
|
||||
static Object parse(Reader reader, boolean modifyAware) throws IOException {
|
||||
return parseRawJson(readAll(reader), modifyAware ? new ModifyAwareFlag() : null);
|
||||
}
|
||||
|
||||
static Object parse(JsonReader parser) throws IOException {
|
||||
return parse(parser, null, false);
|
||||
}
|
||||
|
||||
static Object parse(JsonReader parser, boolean modifyAware) throws IOException {
|
||||
return parse(parser, null, modifyAware);
|
||||
}
|
||||
|
||||
static Object parse(JsonReader parser, Token token, boolean modifyAware) throws IOException {
|
||||
ModifyAwareType owner = modifyAware ? new ModifyAwareFlag() : null;
|
||||
Token effectiveToken = token == null ? parser.currentToken() : token;
|
||||
if (effectiveToken == null) {
|
||||
return parseRawJson(parser.readRaw(), owner);
|
||||
}
|
||||
return parseValue(parser, effectiveToken, owner);
|
||||
}
|
||||
|
||||
private static Object parseValue(JsonReader parser, Token token, ModifyAwareType owner) throws IOException {
|
||||
if (token == null) {
|
||||
token = parser.currentToken();
|
||||
if (token == null) {
|
||||
if (parser.isNullValue()) {
|
||||
return null;
|
||||
}
|
||||
return parseRawJson(parser.readRaw(), owner);
|
||||
}
|
||||
}
|
||||
if (token == Token.BEGIN_OBJECT) {
|
||||
return parseObjectValue(parser, owner);
|
||||
}
|
||||
if (token == Token.BEGIN_ARRAY) {
|
||||
return parseArrayValue(parser, owner);
|
||||
}
|
||||
if (token == Token.NUMBER) {
|
||||
BigDecimal value = parser.readDecimal();
|
||||
return value.scale() <= 0 ? value.longValue() : value;
|
||||
}
|
||||
if (token == Token.STRING) {
|
||||
return parser.readString();
|
||||
}
|
||||
if (token == Token.BOOLEAN) {
|
||||
return parser.readBoolean();
|
||||
}
|
||||
if (token == Token.NULL) {
|
||||
parser.isNullValue();
|
||||
return null;
|
||||
}
|
||||
return parseRawJson(parser.readRaw(), owner);
|
||||
}
|
||||
|
||||
private static Object parseRawJson(String json, ModifyAwareType owner) throws IOException {
|
||||
if (json == null) {
|
||||
return null;
|
||||
}
|
||||
String content = json.trim();
|
||||
if (content.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
JsonReader parser = reader(content);
|
||||
Token token = parser.currentToken();
|
||||
return parseValue(parser, token, owner);
|
||||
}
|
||||
|
||||
private static String readAll(Reader reader) throws IOException {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
char[] buffer = new char[2048];
|
||||
int len;
|
||||
while ((len = reader.read(buffer)) != -1) {
|
||||
builder.append(buffer, 0, len);
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
private static Map<String, Object> parseObjectValue(JsonReader parser, ModifyAwareType owner) throws IOException {
|
||||
Map<String, Object> map = owner == null
|
||||
? new LinkedHashMap<>()
|
||||
: new ModifyAwareMap<>(owner, new LinkedHashMap<>());
|
||||
|
||||
parser.beginObject();
|
||||
while (parser.hasNextField()) {
|
||||
String fieldName = parser.nextField();
|
||||
map.put(fieldName, parseValue(parser, parser.currentToken(), owner));
|
||||
if (owner != null) {
|
||||
owner.setMarkedDirty(false);
|
||||
}
|
||||
}
|
||||
parser.endObject();
|
||||
if (owner != null) {
|
||||
owner.setMarkedDirty(false);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
private static List<Object> parseArrayValue(JsonReader parser, ModifyAwareType owner) throws IOException {
|
||||
List<Object> list = owner == null
|
||||
? new ArrayList<>()
|
||||
: new ModifyAwareList<>(owner, new ArrayList<>());
|
||||
|
||||
parser.beginArray();
|
||||
while (parser.hasNextElement()) {
|
||||
Token elementToken = parser.currentToken();
|
||||
Object elementValue = parseValue(parser, elementToken, owner);
|
||||
list.add(elementValue);
|
||||
if (owner != null) {
|
||||
owner.setMarkedDirty(false);
|
||||
}
|
||||
}
|
||||
parser.endArray();
|
||||
if (owner != null) {
|
||||
owner.setMarkedDirty(false);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
}
|
||||
@@ -1,149 +0,0 @@
|
||||
package io.ebeaninternal.json;
|
||||
|
||||
import io.avaje.json.stream.JsonStream;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.StringWriter;
|
||||
import java.io.Writer;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Utility to write simple java Maps/Lists as JSON.
|
||||
*/
|
||||
final class EJsonWriter {
|
||||
|
||||
private static final JsonStream JSON_STREAM = JsonStream.builder().build();
|
||||
|
||||
private EJsonWriter() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert object to Json content.
|
||||
*/
|
||||
static String write(Object object) throws IOException {
|
||||
StringWriter writer = new StringWriter();
|
||||
write(object, writer);
|
||||
return writer.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert object to Json content.
|
||||
*/
|
||||
static io.avaje.json.JsonWriter write(Object object, Writer writer) throws IOException {
|
||||
io.avaje.json.JsonWriter jsonWriter = JSON_STREAM.writer(writer);
|
||||
jsonWriter.serializeNulls(true);
|
||||
write(object, jsonWriter);
|
||||
jsonWriter.flush();
|
||||
return jsonWriter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert object to Json content.
|
||||
*/
|
||||
static void write(Object object, io.avaje.json.JsonWriter jsonWriter) throws IOException {
|
||||
if (object == null) {
|
||||
jsonWriter.nullValue();
|
||||
return;
|
||||
}
|
||||
if (object instanceof String) {
|
||||
jsonWriter.value((String) object);
|
||||
return;
|
||||
}
|
||||
if (object instanceof Integer) {
|
||||
jsonWriter.value((Integer) object);
|
||||
return;
|
||||
}
|
||||
if (object instanceof Long) {
|
||||
jsonWriter.value((Long) object);
|
||||
return;
|
||||
}
|
||||
if (object instanceof Double) {
|
||||
jsonWriter.value((Double) object);
|
||||
return;
|
||||
}
|
||||
if (object instanceof Float) {
|
||||
jsonWriter.value((Float) object);
|
||||
return;
|
||||
}
|
||||
if (object instanceof BigDecimal) {
|
||||
jsonWriter.value((BigDecimal) object);
|
||||
return;
|
||||
}
|
||||
if (object instanceof Boolean) {
|
||||
jsonWriter.value((Boolean) object);
|
||||
return;
|
||||
}
|
||||
if (object instanceof Map<?, ?>) {
|
||||
writeMap((Map<?, ?>) object, jsonWriter);
|
||||
return;
|
||||
}
|
||||
if (object instanceof Collection<?>) {
|
||||
writeCollection((Collection<?>) object, jsonWriter);
|
||||
return;
|
||||
}
|
||||
|
||||
jsonWriter.value(object.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Write map as Json content.
|
||||
*/
|
||||
private static void writeMap(Map<?, ?> map, io.avaje.json.JsonWriter jsonWriter) throws IOException {
|
||||
jsonWriter.beginObject();
|
||||
for (Map.Entry<?, ?> entry : map.entrySet()) {
|
||||
String fieldName = (String) entry.getKey();
|
||||
Object value = entry.getValue();
|
||||
jsonWriter.name(fieldName);
|
||||
write(value, jsonWriter);
|
||||
}
|
||||
jsonWriter.endObject();
|
||||
}
|
||||
|
||||
/**
|
||||
* Write list as Json content.
|
||||
*/
|
||||
static void writeCollection(Collection<?> list, io.avaje.json.JsonWriter jsonWriter) throws IOException {
|
||||
jsonWriter.beginArray();
|
||||
for (Object element : list) {
|
||||
write(element, jsonWriter);
|
||||
}
|
||||
jsonWriter.endArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert map to Json content.
|
||||
*/
|
||||
static String write(Map<String, Object> map) throws IOException {
|
||||
StringWriter writer = new StringWriter();
|
||||
write(map, writer);
|
||||
return writer.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert map to Json content.
|
||||
*/
|
||||
static io.avaje.json.JsonWriter write(Map<String, Object> map, Writer writer) throws IOException {
|
||||
io.avaje.json.JsonWriter jsonWriter = JSON_STREAM.writer(writer);
|
||||
jsonWriter.serializeNulls(true);
|
||||
write(map, jsonWriter);
|
||||
jsonWriter.flush();
|
||||
return jsonWriter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert map to Json content.
|
||||
*/
|
||||
static void write(Map<String, Object> map, io.avaje.json.JsonWriter jsonWriter) throws IOException {
|
||||
jsonWriter.beginObject();
|
||||
Iterator<Map.Entry<String, Object>> it = map.entrySet().iterator();
|
||||
while (it.hasNext()) {
|
||||
Map.Entry<String, Object> entry = it.next();
|
||||
jsonWriter.name(entry.getKey());
|
||||
write(entry.getValue(), jsonWriter);
|
||||
}
|
||||
jsonWriter.endObject();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,181 @@
|
||||
package io.ebeaninternal.json;
|
||||
|
||||
import io.avaje.json.JsonAdapter;
|
||||
import io.avaje.json.JsonReader;
|
||||
import io.avaje.json.JsonReader.Token;
|
||||
import io.avaje.json.JsonWriter;
|
||||
import io.avaje.json.stream.JsonStream;
|
||||
import io.ebean.ModifyAwareType;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Ebean specific {@link JsonAdapter} that materializes JSON into plain Java
|
||||
* Map/List/scalar values - optionally wrapped in modify-aware collections so
|
||||
* that mutations after load are tracked as dirty.
|
||||
* <p>
|
||||
* This consolidates the prior EJsonReader/EJsonWriter behavior into a single
|
||||
* adapter that plugs into avaje {@code JsonMapper}.
|
||||
*/
|
||||
final class EbeanJsonAdapter implements JsonAdapter<Object> {
|
||||
|
||||
static final EbeanJsonAdapter PLAIN = new EbeanJsonAdapter(false);
|
||||
static final EbeanJsonAdapter MODIFY_AWARE = new EbeanJsonAdapter(true);
|
||||
|
||||
private static final JsonStream JSON_STREAM = JsonStream.builder().build();
|
||||
|
||||
private final boolean modifyAware;
|
||||
|
||||
private EbeanJsonAdapter(boolean modifyAware) {
|
||||
this.modifyAware = modifyAware;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object fromJson(JsonReader reader) {
|
||||
return read(reader, null, modifyAware);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toJson(JsonWriter writer, Object value) {
|
||||
write(writer, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a value honoring an explicitly supplied current token (or current token when null).
|
||||
*/
|
||||
static Object read(JsonReader parser, Token token, boolean modifyAware) {
|
||||
ModifyAwareType owner = modifyAware ? new ModifyAwareFlag() : null;
|
||||
Token effectiveToken = token == null ? parser.currentToken() : token;
|
||||
Object value;
|
||||
if (effectiveToken == null) {
|
||||
value = parseRawJson(parser.readRaw(), owner);
|
||||
} else {
|
||||
value = parseValue(parser, effectiveToken, owner);
|
||||
}
|
||||
if (owner != null) {
|
||||
owner.setMarkedDirty(false);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
private static Object parseValue(JsonReader parser, Token token, ModifyAwareType owner) {
|
||||
if (token == null) {
|
||||
token = parser.currentToken();
|
||||
if (token == null) {
|
||||
if (parser.isNullValue()) {
|
||||
return null;
|
||||
}
|
||||
return parseRawJson(parser.readRaw(), owner);
|
||||
}
|
||||
}
|
||||
switch (token) {
|
||||
case BEGIN_OBJECT:
|
||||
return parseObjectValue(parser, owner);
|
||||
case BEGIN_ARRAY:
|
||||
return parseArrayValue(parser, owner);
|
||||
case NUMBER:
|
||||
BigDecimal value = parser.readDecimal();
|
||||
return value.scale() <= 0 ? value.longValue() : value;
|
||||
case STRING:
|
||||
return parser.readString();
|
||||
case BOOLEAN:
|
||||
return parser.readBoolean();
|
||||
case NULL:
|
||||
parser.isNullValue();
|
||||
return null;
|
||||
default:
|
||||
return parseRawJson(parser.readRaw(), owner);
|
||||
}
|
||||
}
|
||||
|
||||
private static Object parseRawJson(String json, ModifyAwareType owner) {
|
||||
if (json == null) {
|
||||
return null;
|
||||
}
|
||||
String content = json.trim();
|
||||
if (content.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
try (JsonReader parser = JSON_STREAM.reader(content)) {
|
||||
return parseValue(parser, parser.currentToken(), owner);
|
||||
}
|
||||
}
|
||||
|
||||
private static Map<String, Object> parseObjectValue(JsonReader parser, ModifyAwareType owner) {
|
||||
Map<String, Object> map = owner == null
|
||||
? new LinkedHashMap<>()
|
||||
: new ModifyAwareMap<>(owner, new LinkedHashMap<>());
|
||||
|
||||
parser.beginObject();
|
||||
while (parser.hasNextField()) {
|
||||
String fieldName = parser.nextField();
|
||||
map.put(fieldName, parseValue(parser, parser.currentToken(), owner));
|
||||
}
|
||||
parser.endObject();
|
||||
return map;
|
||||
}
|
||||
|
||||
private static List<Object> parseArrayValue(JsonReader parser, ModifyAwareType owner) {
|
||||
List<Object> list = owner == null
|
||||
? new ArrayList<>()
|
||||
: new ModifyAwareList<>(owner, new ArrayList<>());
|
||||
|
||||
parser.beginArray();
|
||||
while (parser.hasNextElement()) {
|
||||
list.add(parseValue(parser, parser.currentToken(), owner));
|
||||
}
|
||||
parser.endArray();
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the value to an existing JsonWriter (used for the raw stream paths).
|
||||
*/
|
||||
static void write(JsonWriter jsonWriter, Object object) {
|
||||
if (object == null) {
|
||||
jsonWriter.nullValue();
|
||||
} else if (object instanceof String) {
|
||||
jsonWriter.value((String) object);
|
||||
} else if (object instanceof Integer) {
|
||||
jsonWriter.value((Integer) object);
|
||||
} else if (object instanceof Long) {
|
||||
jsonWriter.value((Long) object);
|
||||
} else if (object instanceof Double) {
|
||||
jsonWriter.value((Double) object);
|
||||
} else if (object instanceof Float) {
|
||||
jsonWriter.value((Float) object);
|
||||
} else if (object instanceof BigDecimal) {
|
||||
jsonWriter.value((BigDecimal) object);
|
||||
} else if (object instanceof Boolean) {
|
||||
jsonWriter.value((Boolean) object);
|
||||
} else if (object instanceof Map<?, ?>) {
|
||||
writeMap(jsonWriter, (Map<?, ?>) object);
|
||||
} else if (object instanceof Collection<?>) {
|
||||
writeCollection(jsonWriter, (Collection<?>) object);
|
||||
} else {
|
||||
jsonWriter.value(object.toString());
|
||||
}
|
||||
}
|
||||
|
||||
private static void writeMap(JsonWriter jsonWriter, Map<?, ?> map) {
|
||||
jsonWriter.beginObject();
|
||||
for (Map.Entry<?, ?> entry : map.entrySet()) {
|
||||
jsonWriter.name((String) entry.getKey());
|
||||
write(jsonWriter, entry.getValue());
|
||||
}
|
||||
jsonWriter.endObject();
|
||||
}
|
||||
|
||||
static void writeCollection(JsonWriter jsonWriter, Collection<?> collection) {
|
||||
jsonWriter.beginArray();
|
||||
for (Object element : collection) {
|
||||
write(jsonWriter, element);
|
||||
}
|
||||
jsonWriter.endArray();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user