add new method JSON#parse(InputStream, Context)

This commit is contained in:
shaojin.wensj 2024-01-31 01:10:39 +08:00
parent 9493d46ba9
commit 69538bbca6
5 changed files with 288 additions and 14 deletions

View File

@ -246,6 +246,32 @@ public interface JSON {
} }
} }
/**
* Parses the json stream as a {@link JSONArray} or {@link JSONObject}.
* Returns {@code null} if received {@link String} is {@code null} or empty.
*
* @param in the specified stream to be parsed
* @param context the specified custom context
* @return either {@link JSONArray} or {@link JSONObject} or null
* @throws JSONException If a parsing error occurs
* @throws NullPointerException If received context is null
* @since 2.0.47
*/
static Object parse(InputStream in, JSONReader.Context context) {
if (in == null) {
return null;
}
ObjectReader<?> objectReader = context.getObjectReader(Object.class);
try (JSONReaderUTF8 reader = new JSONReaderUTF8(context, in)) {
Object object = objectReader.readObject(reader, null, null, 0);
if (reader.ch != EOI && (context.features & IgnoreCheckClose.mask) == 0) {
throw new JSONException(reader.info("input not end"));
}
return object;
}
}
/** /**
* Parses the json string as a {@link JSONObject}. Returns {@code null} * Parses the json string as a {@link JSONObject}. Returns {@code null}
* if received {@link String} is {@code null} or empty or its content is null. * if received {@link String} is {@code null} or empty or its content is null.
@ -570,6 +596,40 @@ public interface JSON {
} }
} }
/**
* Parses the json stream as a {@link JSONObject}. Returns {@code null} if
* received {@link InputStream} is {@code null} or closed or its content is null.
*
* @param input the specified stream to be parsed
* @param charset the specified charset of the stream
* @param context the specified custom context
* @return {@link JSONObject} or {@code null}
* @throws JSONException If a parsing error occurs
*
* @since 2.0.47
*/
static JSONObject parseObject(InputStream input, Charset charset, JSONReader.Context context) {
if (input == null) {
return null;
}
try (JSONReader reader = JSONReader.of(input, charset, context)) {
if (reader.isEnd()) {
return null;
}
JSONObject object = new JSONObject();
reader.read(object, 0);
if (reader.resolveTasks != null) {
reader.handleResolveTasks(object);
}
if (reader.ch != EOI && (context.features & IgnoreCheckClose.mask) == 0) {
throw new JSONException(reader.info("input not end"));
}
return object;
}
}
/** /**
* Parses the json stream of the url as a {@link JSONObject}. * Parses the json stream of the url as a {@link JSONObject}.
* Returns {@code null} if received {@link URL} is {@code null}. * Returns {@code null} if received {@link URL} is {@code null}.
@ -1861,6 +1921,76 @@ public interface JSON {
} }
} }
/**
* Parses the json stream as a {@link T}. Returns {@code null}
* if received {@link InputStream} is {@code null} or its content is null.
*
* @param input the specified stream to be parsed
* @param type the specified actual type of {@link T}
* @param context the specified custom context
* @return {@link T} or {@code null}
* @throws JSONException If a parsing error occurs
*/
@SuppressWarnings("unchecked")
static <T> T parseObject(InputStream input, Charset charset, Type type, JSONReader.Context context) {
if (input == null) {
return null;
}
boolean fieldBased = (context.features & JSONReader.Feature.FieldBased.mask) != 0;
ObjectReader<T> objectReader = context.provider.getObjectReader(type, fieldBased);
try (JSONReader reader = JSONReader.of(input, charset, context)) {
if (reader.isEnd()) {
return null;
}
T object = objectReader.readObject(reader, type, null, 0);
if (reader.resolveTasks != null) {
reader.handleResolveTasks(object);
}
if (reader.ch != EOI && (context.features & IgnoreCheckClose.mask) == 0) {
throw new JSONException(reader.info("input not end"));
}
return object;
}
}
/**
* Parses the json stream as a {@link T}. Returns {@code null}
* if received {@link InputStream} is {@code null} or its content is null.
*
* @param input the specified stream to be parsed
* @param type the specified actual type of {@link T}
* @param context the specified custom context
* @return {@link T} or {@code null}
* @throws JSONException If a parsing error occurs
*/
@SuppressWarnings("unchecked")
static <T> T parseObject(InputStream input, Charset charset, Class<T> type, JSONReader.Context context) {
if (input == null) {
return null;
}
boolean fieldBased = (context.features & JSONReader.Feature.FieldBased.mask) != 0;
ObjectReader<T> objectReader = context.provider.getObjectReader(type, fieldBased);
try (JSONReader reader = JSONReader.of(input, charset, context)) {
if (reader.isEnd()) {
return null;
}
T object = objectReader.readObject(reader, type, null, 0);
if (reader.resolveTasks != null) {
reader.handleResolveTasks(object);
}
if (reader.ch != EOI && (context.features & IgnoreCheckClose.mask) == 0) {
throw new JSONException(reader.info("input not end"));
}
return object;
}
}
/** /**
* Parses the json stream of the url as {@link T}. * Parses the json stream of the url as {@link T}.
* Returns {@code null} if received {@link URL} is {@code null}. * Returns {@code null} if received {@link URL} is {@code null}.
@ -2498,6 +2628,37 @@ public interface JSON {
} }
} }
/**
* Parses the json stream as a {@link JSONArray}. Returns {@code null}
* if received {@link InputStream} is {@code null} or its content is null.
*
* @param in the specified stream to be parsed
* @param charset the specified charset of the stream
* @param context the specified custom context
* @return {@link JSONArray} or {@code null}
* @throws JSONException If an I/O error or parsing error occurs
*/
static JSONArray parseArray(InputStream in, Charset charset, JSONReader.Context context) {
if (in == null) {
return null;
}
try (JSONReader reader = JSONReader.of(in, charset, context)) {
if (reader.nextIfNull()) {
return null;
}
JSONArray array = new JSONArray();
reader.read(array);
if (reader.resolveTasks != null) {
reader.handleResolveTasks(array);
}
if (reader.ch != EOI && (context.features & IgnoreCheckClose.mask) == 0) {
throw new JSONException(reader.info("input not end"));
}
return array;
}
}
/** /**
* Parses the json string as a list of {@link T}. Returns * Parses the json string as a list of {@link T}. Returns
* {@code null} if received {@link String} is {@code null} or empty. * {@code null} if received {@link String} is {@code null} or empty.

View File

@ -302,7 +302,6 @@ public interface JSONB {
static Object parse(byte[] jsonbBytes, JSONReader.Feature... features) { static Object parse(byte[] jsonbBytes, JSONReader.Feature... features) {
ObjectReaderProvider provider = defaultObjectReaderProvider; ObjectReaderProvider provider = defaultObjectReaderProvider;
JSONReader.Context context = new JSONReader.Context(provider, features); JSONReader.Context context = new JSONReader.Context(provider, features);
boolean fieldBased = (context.features & JSONReader.Feature.FieldBased.mask) != 0;
try (JSONReaderJSONB reader = new JSONReaderJSONB( try (JSONReaderJSONB reader = new JSONReaderJSONB(
context, context,
@ -310,9 +309,17 @@ public interface JSONB {
0, 0,
jsonbBytes.length) jsonbBytes.length)
) { ) {
ObjectReader objectReader = provider.getObjectReader(Object.class, fieldBased); Object object = reader.readAny();
if (reader.resolveTasks != null) {
reader.handleResolveTasks(object);
}
return object;
}
}
Object object = objectReader.readJSONBObject(reader, null, null, 0); static Object parse(InputStream in, JSONReader.Context context) {
try (JSONReaderJSONB reader = new JSONReaderJSONB(context, in)) {
Object object = reader.readAny();
if (reader.resolveTasks != null) { if (reader.resolveTasks != null) {
reader.handleResolveTasks(object); reader.handleResolveTasks(object);
} }
@ -323,7 +330,6 @@ public interface JSONB {
static Object parse(byte[] jsonbBytes, SymbolTable symbolTable, JSONReader.Feature... features) { static Object parse(byte[] jsonbBytes, SymbolTable symbolTable, JSONReader.Feature... features) {
ObjectReaderProvider provider = defaultObjectReaderProvider; ObjectReaderProvider provider = defaultObjectReaderProvider;
JSONReader.Context context = new JSONReader.Context(provider, symbolTable, features); JSONReader.Context context = new JSONReader.Context(provider, symbolTable, features);
boolean fieldBased = (context.features & JSONReader.Feature.FieldBased.mask) != 0;
try (JSONReaderJSONB reader = new JSONReaderJSONB( try (JSONReaderJSONB reader = new JSONReaderJSONB(
context, context,
@ -331,9 +337,7 @@ public interface JSONB {
0, 0,
jsonbBytes.length) jsonbBytes.length)
) { ) {
ObjectReader objectReader = provider.getObjectReader(Object.class, fieldBased); Object object = reader.readAny();
Object object = objectReader.readJSONBObject(reader, null, null, 0);
if (reader.resolveTasks != null) { if (reader.resolveTasks != null) {
reader.handleResolveTasks(object); reader.handleResolveTasks(object);
} }
@ -371,6 +375,16 @@ public interface JSONB {
} }
} }
static JSONObject parseObject(InputStream in, JSONReader.Context context) {
try (JSONReaderJSONB reader = new JSONReaderJSONB(context, in)) {
JSONObject object = (JSONObject) reader.readObject();
if (reader.resolveTasks != null) {
reader.handleResolveTasks(object);
}
return object;
}
}
static JSONArray parseArray(byte[] jsonbBytes) { static JSONArray parseArray(byte[] jsonbBytes) {
try (JSONReaderJSONB reader = new JSONReaderJSONB( try (JSONReaderJSONB reader = new JSONReaderJSONB(
new JSONReader.Context(JSONFactory.defaultObjectReaderProvider), new JSONReader.Context(JSONFactory.defaultObjectReaderProvider),
@ -386,6 +400,16 @@ public interface JSONB {
} }
} }
static JSONArray parseArray(InputStream in, JSONReader.Context context) {
try (JSONReaderJSONB reader = new JSONReaderJSONB(context, in)) {
JSONArray array = (JSONArray) reader.readArray();
if (reader.resolveTasks != null) {
reader.handleResolveTasks(array);
}
return array;
}
}
static <T> List<T> parseArray(byte[] jsonbBytes, Type type) { static <T> List<T> parseArray(byte[] jsonbBytes, Type type) {
if (jsonbBytes == null || jsonbBytes.length == 0) { if (jsonbBytes == null || jsonbBytes.length == 0) {
return null; return null;

View File

@ -2904,6 +2904,10 @@ public abstract class JSONReader
return new JSONReaderUTF16(context, is); return new JSONReaderUTF16(context, is);
} }
if (charset == StandardCharsets.US_ASCII) {
return new JSONReaderASCII(context, is);
}
throw new JSONException("not support charset " + charset); throw new JSONException("not support charset " + charset);
} }

View File

@ -3,6 +3,7 @@ package com.alibaba.fastjson2;
import com.alibaba.fastjson2.util.*; import com.alibaba.fastjson2.util.*;
import sun.misc.Unsafe; import sun.misc.Unsafe;
import java.io.InputStream;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import static com.alibaba.fastjson2.JSONFactory.*; import static com.alibaba.fastjson2.JSONFactory.*;
@ -18,6 +19,12 @@ final class JSONReaderASCII
nameAscii = true; nameAscii = true;
} }
JSONReaderASCII(Context ctx, InputStream is) {
super(ctx, is);
nameAscii = true;
str = null;
}
@Override @Override
public void next() { public void next() {
int offset = this.offset; int offset = this.offset;

View File

@ -1,11 +1,10 @@
package com.alibaba.fastjson2.features; package com.alibaba.fastjson2.features;
import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.*;
import com.alibaba.fastjson2.JSONB;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.JSONReader;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import java.io.ByteArrayInputStream;
import java.lang.reflect.Type;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
@ -25,13 +24,92 @@ public class TrimStringTest {
.getString("value")); .getString("value"));
assertEquals("a b", assertEquals("a b",
JSON.parseObject(utf8Bytes, 0, utf8Bytes.length, StandardCharsets.US_ASCII, JSONReader.Feature.TrimString) JSON.parseObject(
.getString("value")); utf8Bytes, 0, utf8Bytes.length, StandardCharsets.US_ASCII, JSONReader.Feature.TrimString
).getString("value")
);
assertEquals("a b",
JSON.parseObject(
new ByteArrayInputStream(utf8Bytes),
StandardCharsets.US_ASCII,
new JSONReader.Context(JSONReader.Feature.TrimString)
).getString("value")
);
assertEquals("a b",
((JSONObject) JSON.parse(
new ByteArrayInputStream(utf8Bytes),
new JSONReader.Context(JSONReader.Feature.TrimString)
)).getString("value")
);
assertEquals("a b",
JSON.parseObject(
new ByteArrayInputStream(utf8Bytes),
StandardCharsets.US_ASCII,
Bean.class,
new JSONReader.Context(JSONReader.Feature.TrimString)
).value
);
assertEquals("a b",
((Bean) JSON.parseObject(
new ByteArrayInputStream(utf8Bytes),
StandardCharsets.US_ASCII,
(Type) Bean.class,
new JSONReader.Context(JSONReader.Feature.TrimString)
)).value
);
assertEquals("a b",
JSON.parseArray(
new ByteArrayInputStream("[\" a b \"]".getBytes(StandardCharsets.UTF_8)),
StandardCharsets.US_ASCII,
new JSONReader.Context(JSONReader.Feature.TrimString)
).get(0)
);
} }
@Test @Test
public void testJSONB() { public void testJSONB() {
byte[] jsonbBytes = JSONObject.of("value", " a b ").toJSONBBytes(); byte[] jsonbBytes = JSONObject.of("value", " a b ").toJSONBBytes();
assertEquals("a b", JSONB.parseObject(jsonbBytes, JSONReader.Feature.TrimString).getString("value")); String result = "a b";
assertEquals(
result,
JSONB.parseObject(
new ByteArrayInputStream(jsonbBytes),
new JSONReader.Context(JSONReader.Feature.TrimString)
).getString("value")
);
assertEquals(
result,
((JSONObject) JSONB.parse(
jsonbBytes,
new JSONReader.Context(JSONReader.Feature.TrimString)
)).getString("value")
);
assertEquals(
result,
JSONB.parseObject(
jsonbBytes,
JSONReader.Feature.TrimString
).getString("value")
);
assertEquals(
result,
((JSONObject) JSONB.parse(
new ByteArrayInputStream(jsonbBytes),
new JSONReader.Context(JSONReader.Feature.TrimString)
)).getString("value")
);
assertEquals(
result,
JSONB.parseArray(
new ByteArrayInputStream(JSONArray.of(" a b ").toJSONBBytes()),
new JSONReader.Context(JSONReader.Feature.TrimString)
).getString(0)
);
}
public static class Bean {
public String value;
} }
} }