Speed up SkipValue (#3365)
* add simd-benchmark * checkstyle * add simdjson benchmark * fix checkstyle * fix benchmark * fix benchmark * fix benchmark * fast skip * bug fix * fieldClassSerializable for Record * fast skip * check style * simplify skipNumber * update benchmark * update benchmark * update benchmark * optimize skipValue * optimize skipValue * optimize skipValue
This commit is contained in:
parent
1e9204fa00
commit
c17a8d4a0d
@ -0,0 +1,26 @@
|
|||||||
|
package com.alibaba.fastjson2.benchmark.simdjson;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSON;
|
||||||
|
import com.alibaba.fastjson2.benchmark.eishay.EishayParseBinary;
|
||||||
|
import org.apache.commons.io.IOUtils;
|
||||||
|
import org.openjdk.jmh.infra.Blackhole;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
public class GithubEvents {
|
||||||
|
static final String file = "data/simd-json/github_events.json";
|
||||||
|
static byte[] bytes;
|
||||||
|
static {
|
||||||
|
try (InputStream is = EishayParseBinary.class.getClassLoader().getResourceAsStream(file)) {
|
||||||
|
String str = IOUtils.toString(is, "UTF-8");
|
||||||
|
bytes = str.getBytes();
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void fastjson2_parse(Blackhole bh) {
|
||||||
|
bh.consume(JSON.parseArray(bytes));
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
benchmark/src/main/resources/data/simd-json/twitter.json
Normal file
1
benchmark/src/main/resources/data/simd-json/twitter.json
Normal file
File diff suppressed because one or more lines are too long
@ -0,0 +1,22 @@
|
|||||||
|
package com.alibaba.fastjson2.benchmark.simdjson;
|
||||||
|
|
||||||
|
import static com.alibaba.fastjson2.benchmark.JMH.BH;
|
||||||
|
|
||||||
|
public class GithubEventsTest {
|
||||||
|
private static final GithubEvents benchmark = new GithubEvents();
|
||||||
|
|
||||||
|
public static void fastjson2_parse() {
|
||||||
|
for (int j = 0; j < 5; j++) {
|
||||||
|
long start = System.currentTimeMillis();
|
||||||
|
for (int i = 0; i < 1000 * 10; ++i) {
|
||||||
|
benchmark.fastjson2_parse(BH);
|
||||||
|
}
|
||||||
|
long millis = System.currentTimeMillis() - start;
|
||||||
|
System.out.println("GithubEvents-fastjson2_parse : " + millis);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
fastjson2_parse();
|
||||||
|
}
|
||||||
|
}
|
215
benchmark_21/pom.xml
Normal file
215
benchmark_21/pom.xml
Normal file
@ -0,0 +1,215 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<groupId>com.alibaba.fastjson2</groupId>
|
||||||
|
<artifactId>fastjson2-parent</artifactId>
|
||||||
|
<version>2.0.57-SNAPSHOT</version>
|
||||||
|
<relativePath>../pom.xml</relativePath>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<artifactId>fastjson2-benchmark_21</artifactId>
|
||||||
|
<name>fastjson2-benchmark_21</name>
|
||||||
|
<description>JMH Benchmark 21 for Fastjson2</description>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<maven.deploy.skip>true</maven.deploy.skip>
|
||||||
|
<maven.test.skip>true</maven.test.skip>
|
||||||
|
<uberjar.name>fastjson2-benchmarks</uberjar.name>
|
||||||
|
<maven.compiler.source>21</maven.compiler.source>
|
||||||
|
<maven.compiler.target>${maven.compiler.source}</maven.compiler.target>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba.fastjson2</groupId>
|
||||||
|
<artifactId>fastjson2-extension</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba</groupId>
|
||||||
|
<artifactId>fastjson</artifactId>
|
||||||
|
<version>${fastjson1x.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<!--
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.cainiao.ai</groupId>
|
||||||
|
<artifactId>seq-csv</artifactId>
|
||||||
|
<version>0.1.3</version>
|
||||||
|
</dependency>
|
||||||
|
-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.caucho</groupId>
|
||||||
|
<artifactId>hessian</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.dslplatform</groupId>
|
||||||
|
<artifactId>dsl-json</artifactId>
|
||||||
|
<version>2.0.2</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.esotericsoftware</groupId>
|
||||||
|
<artifactId>kryo</artifactId>
|
||||||
|
<version>5.6.0</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.fasterxml.jackson.core</groupId>
|
||||||
|
<artifactId>jackson-databind</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.erosb</groupId>
|
||||||
|
<artifactId>everit-json-schema</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.google.code.gson</groupId>
|
||||||
|
<artifactId>gson</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.google.protobuf</groupId>
|
||||||
|
<artifactId>protobuf-java</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.jayway.jsonpath</groupId>
|
||||||
|
<artifactId>json-path</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.networknt</groupId>
|
||||||
|
<artifactId>json-schema-validator</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.univocity</groupId>
|
||||||
|
<artifactId>univocity-parsers</artifactId>
|
||||||
|
<version>2.9.1</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>commons-io</groupId>
|
||||||
|
<artifactId>commons-io</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.github.wycst</groupId>
|
||||||
|
<artifactId>wast</artifactId>
|
||||||
|
<version>0.0.25</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>javax.annotation</groupId>
|
||||||
|
<artifactId>javax.annotation-api</artifactId>
|
||||||
|
<version>1.3.2</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>net.sourceforge.javacsv</groupId>
|
||||||
|
<artifactId>javacsv</artifactId>
|
||||||
|
<version>2.0</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.arrow</groupId>
|
||||||
|
<artifactId>arrow-vector</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.commons</groupId>
|
||||||
|
<artifactId>commons-lang3</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.fury</groupId>
|
||||||
|
<artifactId>fury-core</artifactId>
|
||||||
|
<version>0.9.0</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.msgpack</groupId>
|
||||||
|
<artifactId>jackson-dataformat-msgpack</artifactId>
|
||||||
|
<version>0.9.9</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.msgpack</groupId>
|
||||||
|
<artifactId>msgpack-core</artifactId>
|
||||||
|
<version>0.9.8</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.openjdk.jmh</groupId>
|
||||||
|
<artifactId>jmh-core</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.ow2.asm</groupId>
|
||||||
|
<artifactId>asm</artifactId>
|
||||||
|
<version>9.7.1</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.simdjson</groupId>
|
||||||
|
<artifactId>simdjson-java</artifactId>
|
||||||
|
<version>0.3.0</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.openjdk.jmh</groupId>
|
||||||
|
<artifactId>jmh-generator-annprocess</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.projectlombok</groupId>
|
||||||
|
<artifactId>lombok</artifactId>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>compile</id>
|
||||||
|
<phase>compile</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>compile</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
<execution>
|
||||||
|
<id>testCompile</id>
|
||||||
|
<phase>test-compile</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>testCompile</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-shade-plugin</artifactId>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<phase>package</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>shade</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<finalName>${uberjar.name}</finalName>
|
||||||
|
<transformers>
|
||||||
|
<transformer
|
||||||
|
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
|
||||||
|
<mainClass>org.openjdk.jmh.Main</mainClass>
|
||||||
|
</transformer>
|
||||||
|
<transformer
|
||||||
|
implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
|
||||||
|
</transformers>
|
||||||
|
<filters>
|
||||||
|
<filter>
|
||||||
|
<!--
|
||||||
|
Shading signed JARs will fail without this.
|
||||||
|
http://stackoverflow.com/questions/999489/invalid-signature-file-when-attempting-to-run-a-jar
|
||||||
|
-->
|
||||||
|
<artifact>*:*</artifact>
|
||||||
|
<excludes>
|
||||||
|
<exclude>META-INF/*.SF</exclude>
|
||||||
|
<exclude>META-INF/*.DSA</exclude>
|
||||||
|
<exclude>META-INF/*.RSA</exclude>
|
||||||
|
</excludes>
|
||||||
|
</filter>
|
||||||
|
</filters>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</project>
|
@ -0,0 +1,79 @@
|
|||||||
|
package com.alibaba.fastjson2.benchmark.simdjson;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSON;
|
||||||
|
import org.openjdk.jmh.annotations.Benchmark;
|
||||||
|
import org.openjdk.jmh.annotations.BenchmarkMode;
|
||||||
|
import org.openjdk.jmh.annotations.Level;
|
||||||
|
import org.openjdk.jmh.annotations.Mode;
|
||||||
|
import org.openjdk.jmh.annotations.OutputTimeUnit;
|
||||||
|
import org.openjdk.jmh.annotations.Param;
|
||||||
|
import org.openjdk.jmh.annotations.Scope;
|
||||||
|
import org.openjdk.jmh.annotations.Setup;
|
||||||
|
import org.openjdk.jmh.annotations.State;
|
||||||
|
import org.openjdk.jmh.runner.Runner;
|
||||||
|
import org.openjdk.jmh.runner.RunnerException;
|
||||||
|
import org.openjdk.jmh.runner.options.Options;
|
||||||
|
import org.openjdk.jmh.runner.options.OptionsBuilder;
|
||||||
|
import org.simdjson.JsonValue;
|
||||||
|
import org.simdjson.SimdJsonParser;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import static com.alibaba.fastjson2.benchmark.simdjson.SimdJsonPaddingUtil.padded;
|
||||||
|
|
||||||
|
@State(Scope.Benchmark)
|
||||||
|
@BenchmarkMode(Mode.Throughput)
|
||||||
|
@OutputTimeUnit(TimeUnit.SECONDS)
|
||||||
|
public class ParseBenchmark {
|
||||||
|
@Param({"/data/simd-json/twitter.json", "/data/simd-json/gsoc-2018.json", "/data/simd-json/github_events.json"})
|
||||||
|
String fileName;
|
||||||
|
|
||||||
|
private final SimdJsonParser simdJsonParser = new SimdJsonParser();
|
||||||
|
|
||||||
|
private byte[] buffer;
|
||||||
|
private byte[] bufferPadded;
|
||||||
|
|
||||||
|
@Setup(Level.Trial)
|
||||||
|
public void setup() throws IOException {
|
||||||
|
try (InputStream is = ParseBenchmark.class.getResourceAsStream(fileName)) {
|
||||||
|
byte[] buf = new byte[1024 * 1024 * 64];
|
||||||
|
int count = is.read(buf);
|
||||||
|
buffer = Arrays.copyOf(buf, count);
|
||||||
|
bufferPadded = padded(buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
public JsonValue simdjson() {
|
||||||
|
return simdJsonParser.parse(buffer, buffer.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
public Object fastjson() {
|
||||||
|
return JSON.parse(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
public Object wast() {
|
||||||
|
return io.github.wycst.wast.json.JSON.parse(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
public JsonValue simdjsonPadded() {
|
||||||
|
return simdJsonParser.parse(bufferPadded, buffer.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) throws RunnerException {
|
||||||
|
Options options = new OptionsBuilder()
|
||||||
|
.include(ParseBenchmark.class.getName())
|
||||||
|
.jvmArgsAppend("--add-opens=java.base/java.time=ALL-UNNAMED", "--add-modules=jdk.incubator.vector")
|
||||||
|
.mode(Mode.Throughput)
|
||||||
|
.timeUnit(TimeUnit.MILLISECONDS)
|
||||||
|
.forks(1)
|
||||||
|
.build();
|
||||||
|
new Runner(options).run();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,142 @@
|
|||||||
|
package com.alibaba.fastjson2.benchmark.simdjson;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSON;
|
||||||
|
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import org.openjdk.jmh.annotations.Benchmark;
|
||||||
|
import org.openjdk.jmh.annotations.BenchmarkMode;
|
||||||
|
import org.openjdk.jmh.annotations.Level;
|
||||||
|
import org.openjdk.jmh.annotations.Mode;
|
||||||
|
import org.openjdk.jmh.annotations.OutputTimeUnit;
|
||||||
|
import org.openjdk.jmh.annotations.Scope;
|
||||||
|
import org.openjdk.jmh.annotations.Setup;
|
||||||
|
import org.openjdk.jmh.annotations.State;
|
||||||
|
import org.openjdk.jmh.runner.Runner;
|
||||||
|
import org.openjdk.jmh.runner.RunnerException;
|
||||||
|
import org.openjdk.jmh.runner.options.Options;
|
||||||
|
import org.openjdk.jmh.runner.options.OptionsBuilder;
|
||||||
|
import org.simdjson.SimdJsonParser;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import static com.alibaba.fastjson2.benchmark.simdjson.SimdJsonPaddingUtil.padded;
|
||||||
|
|
||||||
|
@State(Scope.Benchmark)
|
||||||
|
@BenchmarkMode(Mode.Throughput)
|
||||||
|
@OutputTimeUnit(TimeUnit.SECONDS)
|
||||||
|
public class SchemaBasedParseAndSelectBenchmark {
|
||||||
|
private final SimdJsonParser simdJsonParser;
|
||||||
|
private final ObjectMapper objectMapper = new ObjectMapper()
|
||||||
|
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||||
|
|
||||||
|
public SchemaBasedParseAndSelectBenchmark() {
|
||||||
|
SimdJsonParser p = null;
|
||||||
|
try {
|
||||||
|
p = new SimdJsonParser();
|
||||||
|
} catch (Throwable e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
simdJsonParser = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte[] buffer;
|
||||||
|
private byte[] bufferPadded;
|
||||||
|
|
||||||
|
@Setup(Level.Trial)
|
||||||
|
public void setup() throws IOException {
|
||||||
|
try (InputStream is = ParseBenchmark.class.getResourceAsStream("/data/simd-json/twitter.json")) {
|
||||||
|
buffer = is.readAllBytes();
|
||||||
|
bufferPadded = padded(buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
public int countUniqueUsersWithDefaultProfile_simdjson() {
|
||||||
|
Set<String> defaultUsers = new HashSet<>();
|
||||||
|
SimdJsonTwitter twitter = simdJsonParser.parse(buffer, buffer.length, SimdJsonTwitter.class);
|
||||||
|
for (SimdJsonStatus status : twitter.statuses()) {
|
||||||
|
SimdJsonUser user = status.user();
|
||||||
|
if (user.default_profile()) {
|
||||||
|
defaultUsers.add(user.screen_name());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return defaultUsers.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
public int countUniqueUsersWithDefaultProfile_simdjsonPadded() {
|
||||||
|
Set<String> defaultUsers = new HashSet<>();
|
||||||
|
SimdJsonTwitter twitter = simdJsonParser.parse(bufferPadded, buffer.length, SimdJsonTwitter.class);
|
||||||
|
for (SimdJsonStatus status : twitter.statuses()) {
|
||||||
|
SimdJsonUser user = status.user();
|
||||||
|
if (user.default_profile()) {
|
||||||
|
defaultUsers.add(user.screen_name());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return defaultUsers.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
public int countUniqueUsersWithDefaultProfile_jackson() throws IOException {
|
||||||
|
Set<String> defaultUsers = new HashSet<>();
|
||||||
|
SimdJsonTwitter twitter = objectMapper.readValue(buffer, SimdJsonTwitter.class);
|
||||||
|
for (SimdJsonStatus status : twitter.statuses()) {
|
||||||
|
SimdJsonUser user = status.user();
|
||||||
|
if (user.default_profile()) {
|
||||||
|
defaultUsers.add(user.screen_name());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return defaultUsers.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
public int countUniqueUsersWithDefaultProfile_fastjson() {
|
||||||
|
Set<String> defaultUsers = new HashSet<>();
|
||||||
|
SimdJsonTwitter twitter = JSON.parseObject(buffer, SimdJsonTwitter.class);
|
||||||
|
for (SimdJsonStatus status : twitter.statuses()) {
|
||||||
|
SimdJsonUser user = status.user();
|
||||||
|
if (user.default_profile()) {
|
||||||
|
defaultUsers.add(user.screen_name());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return defaultUsers.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
public int countUniqueUsersWithDefaultProfile_wast() {
|
||||||
|
Set<String> defaultUsers = new HashSet<>();
|
||||||
|
SimdJsonTwitter twitter = io.github.wycst.wast.json.JSON.parseObject(buffer, SimdJsonTwitter.class);
|
||||||
|
for (SimdJsonStatus status : twitter.statuses()) {
|
||||||
|
SimdJsonUser user = status.user();
|
||||||
|
if (user.default_profile()) {
|
||||||
|
defaultUsers.add(user.screen_name());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return defaultUsers.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public record SimdJsonUser(boolean default_profile, String screen_name) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public record SimdJsonStatus(SimdJsonUser user) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public record SimdJsonTwitter(List<SimdJsonStatus> statuses) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) throws RunnerException {
|
||||||
|
Options options = new OptionsBuilder()
|
||||||
|
.include(SchemaBasedParseAndSelectBenchmark.class.getName())
|
||||||
|
.jvmArgsAppend("--add-opens=java.base/java.time=ALL-UNNAMED", "--add-modules=jdk.incubator.vector")
|
||||||
|
.mode(Mode.Throughput)
|
||||||
|
.timeUnit(TimeUnit.MILLISECONDS)
|
||||||
|
.forks(1)
|
||||||
|
.build();
|
||||||
|
new Runner(options).run();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
package com.alibaba.fastjson2.benchmark.simdjson;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||||
|
|
||||||
|
class SimdJsonPaddingUtil {
|
||||||
|
static byte[] padded(byte[] src) {
|
||||||
|
byte[] bufferPadded = new byte[src.length + 64];
|
||||||
|
System.arraycopy(src, 0, bufferPadded, 0, src.length);
|
||||||
|
return bufferPadded;
|
||||||
|
}
|
||||||
|
|
||||||
|
static byte[] padWithSpaces(String str) {
|
||||||
|
byte[] strBytes = str.getBytes(UTF_8);
|
||||||
|
byte[] padded = new byte[strBytes.length + 64];
|
||||||
|
Arrays.fill(padded, (byte) ' ');
|
||||||
|
System.arraycopy(strBytes, 0, padded, 0, strBytes.length);
|
||||||
|
return padded;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,39 @@
|
|||||||
|
package com.alibaba.fastjson2.benchmark.simdjson;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSON;
|
||||||
|
import org.apache.commons.io.IOUtils;
|
||||||
|
import org.openjdk.jmh.infra.Blackhole;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class Twitter {
|
||||||
|
static final String file = "data/simd-json/twitter.json";
|
||||||
|
static byte[] bytes;
|
||||||
|
static {
|
||||||
|
try (InputStream is = Twitter.class.getClassLoader().getResourceAsStream(file)) {
|
||||||
|
String str = IOUtils.toString(is, "UTF-8");
|
||||||
|
bytes = str.getBytes();
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void fastjson2_parse(Blackhole bh) {
|
||||||
|
bh.consume(JSON.parseObject(bytes, SimdJsonTwitter.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void wast_parse(Blackhole bh) {
|
||||||
|
bh.consume(io.github.wycst.wast.json.JSON.parseObject(bytes, SimdJsonTwitter.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
public record SimdJsonUser(boolean default_profile, String screen_name) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public record SimdJsonStatus(SimdJsonUser user) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public record SimdJsonTwitter(List<SimdJsonStatus> statuses) {
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -0,0 +1,23 @@
|
|||||||
|
package com.alibaba.fastjson2.benchmark;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSON;
|
||||||
|
import org.apache.commons.io.FileUtils;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.net.URL;
|
||||||
|
|
||||||
|
public class Gsoc2018Test {
|
||||||
|
@Test
|
||||||
|
public void test() throws Exception {
|
||||||
|
String[] paths = new String[] {
|
||||||
|
"data/simd-json/twitter.json", "data/simd-json/gsoc-2018.json", "data/simd-json/github_events.json"
|
||||||
|
};
|
||||||
|
for (String path : paths) {
|
||||||
|
URL resource = Thread.currentThread().getContextClassLoader().getResource(path);
|
||||||
|
File file = new File(resource.getFile());
|
||||||
|
byte[] str = FileUtils.readFileToByteArray(file);
|
||||||
|
JSON.parse(str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
package com.alibaba.fastjson2.benchmark;
|
||||||
|
|
||||||
|
import org.openjdk.jmh.infra.Blackhole;
|
||||||
|
|
||||||
|
public class JMH {
|
||||||
|
public static final Blackhole BH = new Blackhole("Today's password is swordfish. I understand instantiating Blackholes directly is dangerous.");
|
||||||
|
}
|
@ -0,0 +1,38 @@
|
|||||||
|
package com.alibaba.fastjson2.benchmark;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.benchmark.simdjson.Twitter;
|
||||||
|
|
||||||
|
import static com.alibaba.fastjson2.benchmark.JMH.BH;
|
||||||
|
|
||||||
|
public class TwitterTest {
|
||||||
|
private static final Twitter benchmark = new Twitter();
|
||||||
|
|
||||||
|
public static void fastjson2_parse() {
|
||||||
|
for (int j = 0; j < 5; j++) {
|
||||||
|
long start = System.currentTimeMillis();
|
||||||
|
for (int i = 0; i < 1000; ++i) {
|
||||||
|
benchmark.fastjson2_parse(BH);
|
||||||
|
}
|
||||||
|
long millis = System.currentTimeMillis() - start;
|
||||||
|
System.out.println("Twitter-fastjson2_parse : " + millis);
|
||||||
|
// zulu21.32.17 247 234
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void wast_parse() {
|
||||||
|
for (int j = 0; j < 5; j++) {
|
||||||
|
long start = System.currentTimeMillis();
|
||||||
|
for (int i = 0; i < 1000; ++i) {
|
||||||
|
benchmark.wast_parse(BH);
|
||||||
|
}
|
||||||
|
long millis = System.currentTimeMillis() - start;
|
||||||
|
System.out.println("Twitter-wast_parse : " + millis);
|
||||||
|
// zulu21.32.17 211
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
fastjson2_parse();
|
||||||
|
// wast_parse();
|
||||||
|
}
|
||||||
|
}
|
@ -446,6 +446,10 @@ public abstract class JSONReader
|
|||||||
return (context.features & MASK_IGNORE_NONE_SERIALIZABLE) != 0;
|
return (context.features & MASK_IGNORE_NONE_SERIALIZABLE) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean hasAutoTypeBeforeHandler() {
|
||||||
|
return context.autoTypeBeforeHandler != null;
|
||||||
|
}
|
||||||
|
|
||||||
public ObjectReader checkAutoType(Class expectClass, long expectClassHash, long features) {
|
public ObjectReader checkAutoType(Class expectClass, long expectClassHash, long features) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -4324,7 +4328,9 @@ public abstract class JSONReader
|
|||||||
protected static final long MASK_SUPPORT_AUTO_TYPE = 1L << 5;
|
protected static final long MASK_SUPPORT_AUTO_TYPE = 1L << 5;
|
||||||
protected static final long MASK_SUPPORT_SMART_MATCH = 1L << 6;
|
protected static final long MASK_SUPPORT_SMART_MATCH = 1L << 6;
|
||||||
protected static final long MASK_TRIM_STRING = 1L << 14;
|
protected static final long MASK_TRIM_STRING = 1L << 14;
|
||||||
|
protected static final long MASK_ALLOW_UN_QUOTED_FIELD_NAMES = 1L << 17;
|
||||||
protected static final long MASK_EMPTY_STRING_AS_NULL = 1L << 27;
|
protected static final long MASK_EMPTY_STRING_AS_NULL = 1L << 27;
|
||||||
|
protected static final long MASK_DISABLE_SINGLE_QUOTE = 1L << 31L;
|
||||||
protected static final long MASK_DISABLE_REFERENCE_DETECT = 1L << 33;
|
protected static final long MASK_DISABLE_REFERENCE_DETECT = 1L << 33;
|
||||||
|
|
||||||
public enum Feature {
|
public enum Feature {
|
||||||
@ -4352,7 +4358,7 @@ public abstract class JSONReader
|
|||||||
TrimString(MASK_TRIM_STRING),
|
TrimString(MASK_TRIM_STRING),
|
||||||
ErrorOnNotSupportAutoType(1 << 15),
|
ErrorOnNotSupportAutoType(1 << 15),
|
||||||
DuplicateKeyValueAsArray(1 << 16),
|
DuplicateKeyValueAsArray(1 << 16),
|
||||||
AllowUnQuotedFieldNames(1 << 17),
|
AllowUnQuotedFieldNames(MASK_ALLOW_UN_QUOTED_FIELD_NAMES),
|
||||||
NonStringKeyAsString(1 << 18),
|
NonStringKeyAsString(1 << 18),
|
||||||
/**
|
/**
|
||||||
* @since 2.0.13
|
* @since 2.0.13
|
||||||
@ -4449,7 +4455,7 @@ public abstract class JSONReader
|
|||||||
* Feature that disables the support for single quote.
|
* Feature that disables the support for single quote.
|
||||||
* @since 2.0.53
|
* @since 2.0.53
|
||||||
*/
|
*/
|
||||||
DisableSingleQuote(1L << 31L),
|
DisableSingleQuote(MASK_DISABLE_SINGLE_QUOTE),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @since 2.0.53
|
* @since 2.0.53
|
||||||
@ -4518,6 +4524,21 @@ public abstract class JSONReader
|
|||||||
this.ch = (char) savePoint.current;
|
this.ch = (char) savePoint.current;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final boolean checkNameBegin(int quote) {
|
||||||
|
long features = context.features;
|
||||||
|
if (quote == '\'' && ((features & MASK_DISABLE_SINGLE_QUOTE) != 0)) {
|
||||||
|
throw notSupportName();
|
||||||
|
}
|
||||||
|
if (quote != '"' && quote != '\'') {
|
||||||
|
if ((features & MASK_ALLOW_UN_QUOTED_FIELD_NAMES) != 0) {
|
||||||
|
readFieldNameHashCodeUnquote();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
throw notSupportName();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
final JSONException notSupportName() {
|
final JSONException notSupportName() {
|
||||||
return new JSONException(info("not support unquoted name"));
|
return new JSONException(info("not support unquoted name"));
|
||||||
}
|
}
|
||||||
@ -4534,6 +4555,10 @@ public abstract class JSONReader
|
|||||||
return new JSONException(info(message), cause);
|
return new JSONException(info(message), cause);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final JSONException error() {
|
||||||
|
throw new JSONValidException("error, offset " + offset + ", char " + (char) ch);
|
||||||
|
}
|
||||||
|
|
||||||
final JSONException error(int offset, int ch) {
|
final JSONException error(int offset, int ch) {
|
||||||
throw new JSONValidException("error, offset " + offset + ", char " + (char) ch);
|
throw new JSONValidException("error, offset " + offset + ", char " + (char) ch);
|
||||||
}
|
}
|
||||||
|
@ -17,8 +17,6 @@ import static com.alibaba.fastjson2.util.JDKUtils.*;
|
|||||||
final class JSONReaderASCII
|
final class JSONReaderASCII
|
||||||
extends JSONReaderUTF8 {
|
extends JSONReaderUTF8 {
|
||||||
final String str;
|
final String str;
|
||||||
static final int ESCAPE_INDEX_NOT_SET = -2;
|
|
||||||
private int nextEscapeIndex = ESCAPE_INDEX_NOT_SET;
|
|
||||||
|
|
||||||
JSONReaderASCII(Context ctx, String str, byte[] bytes, int offset, int length) {
|
JSONReaderASCII(Context ctx, String str, byte[] bytes, int offset, int length) {
|
||||||
super(ctx, bytes, offset, length);
|
super(ctx, bytes, offset, length);
|
||||||
@ -1359,7 +1357,7 @@ final class JSONReaderASCII
|
|||||||
if (index == -1) {
|
if (index == -1) {
|
||||||
throw error("invalid escape character EOI");
|
throw error("invalid escape character EOI");
|
||||||
}
|
}
|
||||||
int slashIndex = indexOfSlash(bytes, offset, end);
|
int slashIndex = indexOfSlash(this, bytes, offset, end);
|
||||||
if (slashIndex == -1 || slashIndex > index) {
|
if (slashIndex == -1 || slashIndex > index) {
|
||||||
offset = index + 1;
|
offset = index + 1;
|
||||||
} else {
|
} else {
|
||||||
@ -1400,14 +1398,6 @@ final class JSONReaderASCII
|
|||||||
return readStringNotMatch();
|
return readStringNotMatch();
|
||||||
}
|
}
|
||||||
|
|
||||||
private int indexOfSlash(byte[] bytes, int offset, int end) {
|
|
||||||
int slashIndex = nextEscapeIndex;
|
|
||||||
if (slashIndex == ESCAPE_INDEX_NOT_SET || (slashIndex != -1 && slashIndex < offset)) {
|
|
||||||
nextEscapeIndex = slashIndex = IOUtils.indexOfSlash(bytes, offset, end);
|
|
||||||
}
|
|
||||||
return slashIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected final void readString0() {
|
protected final void readString0() {
|
||||||
final byte[] bytes = this.bytes;
|
final byte[] bytes = this.bytes;
|
||||||
|
@ -2353,56 +2353,6 @@ final class JSONReaderUTF16
|
|||||||
return getFieldName();
|
return getFieldName();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public final boolean skipName() {
|
|
||||||
char quote = ch;
|
|
||||||
if (quote == '\'' && ((context.features & Feature.DisableSingleQuote.mask) != 0)) {
|
|
||||||
throw notSupportName();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (quote != '"' && quote != '\'') {
|
|
||||||
if ((context.features & Feature.AllowUnQuotedFieldNames.mask) != 0) {
|
|
||||||
readFieldNameHashCodeUnquote();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
throw notSupportName();
|
|
||||||
}
|
|
||||||
|
|
||||||
int offset = this.offset;
|
|
||||||
final char[] chars = this.chars;
|
|
||||||
for (; ; ) {
|
|
||||||
char ch = chars[offset++];
|
|
||||||
if (ch == '\\') {
|
|
||||||
ch = chars[offset];
|
|
||||||
offset += (ch == 'u' ? 5 : (ch == 'x' ? 3 : 1));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ch == quote) {
|
|
||||||
ch = offset == end ? EOI : chars[offset++];
|
|
||||||
|
|
||||||
while (ch <= ' ' && ((1L << ch) & SPACE) != 0) {
|
|
||||||
ch = offset == end ? EOI : chars[offset++];
|
|
||||||
}
|
|
||||||
if (ch != ':') {
|
|
||||||
throw syntaxError(ch);
|
|
||||||
}
|
|
||||||
|
|
||||||
ch = offset == end ? EOI : chars[offset++];
|
|
||||||
|
|
||||||
while (ch <= ' ' && ((1L << ch) & SPACE) != 0) {
|
|
||||||
ch = offset == end ? EOI : chars[offset++];
|
|
||||||
}
|
|
||||||
|
|
||||||
this.offset = offset;
|
|
||||||
this.ch = ch;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final int readInt32Value() {
|
public final int readInt32Value() {
|
||||||
char ch = this.ch;
|
char ch = this.ch;
|
||||||
@ -3163,207 +3113,440 @@ final class JSONReaderUTF16
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final void skipValue() {
|
public final boolean skipName() {
|
||||||
final char[] chars = this.chars;
|
this.offset = skipName(this, chars, offset, end);
|
||||||
char ch = this.ch;
|
return true;
|
||||||
int offset = this.offset, end = this.end;
|
}
|
||||||
comma = false;
|
|
||||||
|
|
||||||
switch_:
|
private static int skipName(JSONReaderUTF16 jsonReader, char[] chars, int offset, int end) {
|
||||||
switch (ch) {
|
char quote = jsonReader.ch;
|
||||||
case '-':
|
if (jsonReader.checkNameBegin(quote)) {
|
||||||
case '+':
|
return jsonReader.offset;
|
||||||
case '0':
|
}
|
||||||
case '1':
|
|
||||||
case '2':
|
for (; ; ) {
|
||||||
case '3':
|
char ch = chars[offset++];
|
||||||
case '4':
|
if (ch == '\\') {
|
||||||
case '5':
|
ch = chars[offset];
|
||||||
case '6':
|
offset += (ch == 'u' ? 5 : (ch == 'x' ? 3 : 1));
|
||||||
case '7':
|
continue;
|
||||||
case '8':
|
}
|
||||||
case '9':
|
|
||||||
case '.':
|
if (ch == quote) {
|
||||||
boolean sign = ch == '-' || ch == '+';
|
ch = offset == end ? EOI : chars[offset++];
|
||||||
if (sign) {
|
|
||||||
|
while (ch <= ' ' && ((1L << ch) & SPACE) != 0) {
|
||||||
|
ch = offset == end ? EOI : chars[offset++];
|
||||||
|
}
|
||||||
|
if (ch != ':') {
|
||||||
|
throw syntaxError(ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
ch = offset == end ? EOI : chars[offset++];
|
||||||
|
|
||||||
|
while (ch <= ' ' && ((1L << ch) & SPACE) != 0) {
|
||||||
|
ch = offset == end ? EOI : chars[offset++];
|
||||||
|
}
|
||||||
|
|
||||||
|
jsonReader.ch = ch;
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int skipNumber(JSONReaderUTF16 jsonReader, char[] bytes, int offset, int end) {
|
||||||
|
int ch = jsonReader.ch;
|
||||||
|
if (ch == '-' || ch == '+') {
|
||||||
|
if (offset < end) {
|
||||||
|
ch = bytes[offset++];
|
||||||
|
} else {
|
||||||
|
throw jsonReader.error();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
boolean dot = ch == '.';
|
||||||
|
boolean num = false;
|
||||||
|
if (!dot && (ch >= '0' && ch <= '9')) {
|
||||||
|
num = true;
|
||||||
|
do {
|
||||||
|
ch = offset == end ? EOI : bytes[offset++];
|
||||||
|
} while (ch >= '0' && ch <= '9');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (num && (ch == 'L' | ch == 'F' | ch == 'D' | ch == 'B' | ch == 'S')) {
|
||||||
|
ch = bytes[offset++];
|
||||||
|
} else {
|
||||||
|
boolean small = false;
|
||||||
|
if (ch == '.') {
|
||||||
|
small = true;
|
||||||
|
ch = offset == end ? EOI : bytes[offset++];
|
||||||
|
|
||||||
|
while (ch >= '0' && ch <= '9') {
|
||||||
|
ch = offset == end ? EOI : bytes[offset++];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!num && !small) {
|
||||||
|
throw numberError(offset, ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ch == 'e' || ch == 'E') {
|
||||||
|
ch = bytes[offset++];
|
||||||
|
|
||||||
|
boolean eSign = false;
|
||||||
|
if (ch == '+' || ch == '-') {
|
||||||
|
eSign = true;
|
||||||
if (offset < end) {
|
if (offset < end) {
|
||||||
ch = chars[offset++];
|
ch = bytes[offset++];
|
||||||
} else {
|
} else {
|
||||||
throw numberError(offset, ch);
|
throw numberError(offset, ch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
boolean dot = ch == '.';
|
|
||||||
boolean num = false;
|
if (ch >= '0' && ch <= '9') {
|
||||||
if (!dot && (ch >= '0' && ch <= '9')) {
|
|
||||||
num = true;
|
|
||||||
do {
|
do {
|
||||||
ch = offset == end ? EOI : chars[offset++];
|
ch = offset == end ? EOI : bytes[offset++];
|
||||||
} while (ch >= '0' && ch <= '9');
|
} while (ch >= '0' && ch <= '9');
|
||||||
}
|
} else if (eSign) {
|
||||||
|
|
||||||
if (num && (ch == 'L' || ch == 'F' || ch == 'D' || ch == 'B' || ch == 'S')) {
|
|
||||||
ch = chars[offset++];
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean small = false;
|
|
||||||
if (ch == '.') {
|
|
||||||
small = true;
|
|
||||||
ch = offset == end ? EOI : chars[offset++];
|
|
||||||
|
|
||||||
if (ch >= '0' && ch <= '9') {
|
|
||||||
do {
|
|
||||||
ch = offset == end ? EOI : chars[offset++];
|
|
||||||
} while (ch >= '0' && ch <= '9');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!num && !small) {
|
|
||||||
throw numberError(offset, ch);
|
throw numberError(offset, ch);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (ch == 'e' || ch == 'E') {
|
if (ch == 'F' || ch == 'D') {
|
||||||
ch = chars[offset++];
|
ch = offset == end ? EOI : bytes[offset++];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
boolean eSign = false;
|
while (ch <= ' ' && ((1L << ch) & SPACE) != 0) {
|
||||||
if (ch == '+' || ch == '-') {
|
ch = offset == end ? EOI : bytes[offset++];
|
||||||
eSign = true;
|
}
|
||||||
if (offset < end) {
|
|
||||||
ch = chars[offset++];
|
|
||||||
} else {
|
|
||||||
throw numberError(offset, ch);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ch >= '0' && ch <= '9') {
|
boolean comma = false;
|
||||||
do {
|
if (ch == ',') {
|
||||||
ch = offset == end ? EOI : chars[offset++];
|
comma = true;
|
||||||
} while (ch >= '0' && ch <= '9');
|
ch = offset == end ? EOI : bytes[offset++];
|
||||||
} else if (eSign) {
|
while (ch <= ' ' && ((1L << ch) & SPACE) != 0) {
|
||||||
throw numberError(offset, ch);
|
ch = offset == end ? EOI : bytes[offset++];
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (ch == 'L' || ch == 'F' || ch == 'D' || ch == 'B' || ch == 'S') {
|
if ((ch == '}' || ch == ']' || ch == EOI)) {
|
||||||
ch = offset == end ? EOI : chars[offset++];
|
throw jsonReader.error(offset, ch);
|
||||||
}
|
}
|
||||||
break;
|
} else if (ch != '}' && ch != ']' && ch != EOI) {
|
||||||
case 't':
|
throw jsonReader.error(offset, ch);
|
||||||
if (offset + 3 > end) {
|
}
|
||||||
throw error(offset, ch);
|
|
||||||
}
|
jsonReader.comma = comma;
|
||||||
if (chars[offset] != 'r' || chars[offset + 1] != 'u' || chars[offset + 2] != 'e') {
|
jsonReader.ch = (char) ch;
|
||||||
throw error(offset, ch);
|
return offset;
|
||||||
}
|
}
|
||||||
offset += 3;
|
|
||||||
ch = offset == end ? EOI : chars[offset++];
|
private static int skipString(JSONReaderUTF16 jsonReader, char[] chars, int offset, int end) {
|
||||||
break;
|
char quote = jsonReader.ch;
|
||||||
case 'f':
|
char ch = offset == end ? EOI : chars[offset++];
|
||||||
if (offset + 4 > end) {
|
for (; ; ) {
|
||||||
throw error(offset, ch);
|
if (ch == '\\') {
|
||||||
}
|
|
||||||
if (chars[offset] != 'a' || chars[offset + 1] != 'l' || chars[offset + 2] != 's' || chars[offset + 3] != 'e') {
|
|
||||||
throw error(offset, ch);
|
|
||||||
}
|
|
||||||
offset += 4;
|
|
||||||
ch = offset == end ? EOI : chars[offset++];
|
|
||||||
break;
|
|
||||||
case 'n':
|
|
||||||
if (offset + 3 > end) {
|
|
||||||
throw error(offset, ch);
|
|
||||||
}
|
|
||||||
if (chars[offset] != 'u' || chars[offset + 1] != 'l' || chars[offset + 2] != 'l') {
|
|
||||||
throw error(offset, ch);
|
|
||||||
}
|
|
||||||
offset += 3;
|
|
||||||
ch = offset == end ? EOI : chars[offset++];
|
|
||||||
break;
|
|
||||||
case '"':
|
|
||||||
case '\'': {
|
|
||||||
char quote = ch;
|
|
||||||
ch = chars[offset++];
|
ch = chars[offset++];
|
||||||
for (; ; ) {
|
if (ch == 'u') {
|
||||||
if (ch == '\\') {
|
offset += 4;
|
||||||
ch = chars[offset++];
|
} else if (ch == 'x') {
|
||||||
if (ch == 'u') {
|
offset += 2;
|
||||||
offset += 4;
|
} else if (ch != '\\' && ch != '"') {
|
||||||
} else if (ch == 'x') {
|
jsonReader.char1(ch);
|
||||||
offset += 2;
|
|
||||||
} else if (ch != '\\' && ch != '"') {
|
|
||||||
char1(ch);
|
|
||||||
}
|
|
||||||
ch = chars[offset++];
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ch == quote) {
|
|
||||||
ch = offset == end ? EOI : chars[offset++];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
ch = chars[offset++];
|
|
||||||
}
|
}
|
||||||
|
ch = chars[offset++];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ch == quote) {
|
||||||
|
ch = offset == end ? EOI : chars[offset++];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
|
||||||
if (ch == '[') {
|
ch = chars[offset++];
|
||||||
next();
|
|
||||||
for (int i = 0; ; ++i) {
|
|
||||||
if (this.ch == ']') {
|
|
||||||
comma = false;
|
|
||||||
offset = this.offset;
|
|
||||||
ch = offset == end ? EOI : chars[offset++];
|
|
||||||
break switch_;
|
|
||||||
}
|
|
||||||
if (i != 0 && !comma) {
|
|
||||||
throw valueError();
|
|
||||||
}
|
|
||||||
comma = false;
|
|
||||||
skipValue();
|
|
||||||
}
|
|
||||||
} else if (ch == '{') {
|
|
||||||
next();
|
|
||||||
for (; ; ) {
|
|
||||||
if (this.ch == '}') {
|
|
||||||
comma = false;
|
|
||||||
offset = this.offset;
|
|
||||||
ch = offset == end ? EOI : chars[offset++];
|
|
||||||
break switch_;
|
|
||||||
}
|
|
||||||
skipName();
|
|
||||||
skipValue();
|
|
||||||
}
|
|
||||||
} else if (ch == 'S' && nextIfSet()) {
|
|
||||||
skipValue();
|
|
||||||
} else {
|
|
||||||
throw error(offset, ch);
|
|
||||||
}
|
|
||||||
ch = this.ch;
|
|
||||||
offset = this.offset;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
while (ch <= ' ' && ((1L << ch) & SPACE) != 0) {
|
while (ch <= ' ' && ((1L << ch) & SPACE) != 0) {
|
||||||
ch = offset == end ? EOI : chars[offset++];
|
ch = offset == end ? EOI : chars[offset++];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean comma = false;
|
||||||
if (ch == ',') {
|
if (ch == ',') {
|
||||||
comma = true;
|
comma = true;
|
||||||
ch = offset == end ? EOI : chars[offset++];
|
ch = offset == end ? EOI : chars[offset++];
|
||||||
while (ch <= ' ' && ((1L << ch) & SPACE) != 0) {
|
while (ch <= ' ' && ((1L << ch) & SPACE) != 0) {
|
||||||
ch = offset == end ? EOI : chars[offset++];
|
ch = offset == end ? EOI : chars[offset++];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((ch == '}' || ch == ']' || ch == EOI)) {
|
||||||
|
throw jsonReader.error(offset, ch);
|
||||||
|
}
|
||||||
|
} else if (ch != '}' && ch != ']' && ch != EOI) {
|
||||||
|
throw jsonReader.error(offset, ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
jsonReader.comma = comma;
|
||||||
|
jsonReader.ch = (char) ch;
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int skipStringEscaped(JSONReaderUTF16 jsonReader, char[] bytes, int offset, int quote) {
|
||||||
|
int ch = bytes[offset++];
|
||||||
|
for (; ; ) {
|
||||||
|
if (ch == '\\') {
|
||||||
|
ch = bytes[offset++];
|
||||||
|
if (ch == 'u') {
|
||||||
|
offset += 4;
|
||||||
|
} else if (ch == 'x') {
|
||||||
|
offset += 2;
|
||||||
|
} else if (ch != '\\' && ch != '"') {
|
||||||
|
jsonReader.char1(ch);
|
||||||
|
}
|
||||||
|
ch = bytes[offset++];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (ch == quote) {
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
ch = bytes[offset++];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int skipObject(JSONReaderUTF16 jsonReader, char[] bytes, int offset, int end) {
|
||||||
|
offset = next(jsonReader, bytes, offset, end);
|
||||||
|
for (int i = 0; ; ++i) {
|
||||||
|
if (jsonReader.ch == '}') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (i != 0 && !jsonReader.comma) {
|
||||||
|
throw jsonReader.valueError();
|
||||||
|
}
|
||||||
|
offset = skipName(jsonReader, bytes, offset, end);
|
||||||
|
offset = skipValue(jsonReader, bytes, offset, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ch = offset == end ? EOI : bytes[offset++];
|
||||||
|
|
||||||
|
while (ch <= ' ' && ((1L << ch) & SPACE) != 0) {
|
||||||
|
ch = offset == end ? EOI : bytes[offset++];
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean comma = false;
|
||||||
|
if (ch == ',') {
|
||||||
|
comma = true;
|
||||||
|
ch = offset == end ? EOI : bytes[offset++];
|
||||||
|
while (ch <= ' ' && ((1L << ch) & SPACE) != 0) {
|
||||||
|
ch = offset == end ? EOI : bytes[offset++];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((ch == '}' || ch == ']' || ch == EOI)) {
|
||||||
|
throw jsonReader.error(offset, ch);
|
||||||
|
}
|
||||||
|
} else if (ch != '}' && ch != ']' && ch != EOI) {
|
||||||
|
throw jsonReader.error(offset, ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
jsonReader.comma = comma;
|
||||||
|
jsonReader.ch = (char) ch;
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int next(JSONReaderUTF16 jsonReader, char[] bytes, int offset, int end) {
|
||||||
|
int ch = offset >= end ? EOI : bytes[offset++];
|
||||||
|
while (ch == '\0' || (ch <= ' ' && ((1L << ch) & SPACE) != 0)) {
|
||||||
|
ch = offset == end ? EOI : bytes[offset++];
|
||||||
|
}
|
||||||
|
|
||||||
|
jsonReader.ch = (char) ch;
|
||||||
|
if (ch == '/') {
|
||||||
|
jsonReader.offset = offset;
|
||||||
|
jsonReader.skipComment();
|
||||||
|
return jsonReader.offset;
|
||||||
|
} else {
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int skipArray(JSONReaderUTF16 jsonReader, char[] bytes, int offset, int end) {
|
||||||
|
offset = next(jsonReader, bytes, offset, end);
|
||||||
|
for (int i = 0; ; ++i) {
|
||||||
|
if (jsonReader.ch == ']') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (i != 0 && !jsonReader.comma) {
|
||||||
|
throw jsonReader.valueError();
|
||||||
|
}
|
||||||
|
offset = skipValue(jsonReader, bytes, offset, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ch = offset == end ? EOI : bytes[offset++];
|
||||||
|
|
||||||
|
while (ch <= ' ' && ((1L << ch) & SPACE) != 0) {
|
||||||
|
ch = offset == end ? EOI : bytes[offset++];
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean comma = false;
|
||||||
|
if (ch == ',') {
|
||||||
|
comma = true;
|
||||||
|
ch = offset == end ? EOI : bytes[offset++];
|
||||||
|
while (ch <= ' ' && ((1L << ch) & SPACE) != 0) {
|
||||||
|
ch = offset == end ? EOI : bytes[offset++];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!comma && ch != '}' && ch != ']' && ch != EOI) {
|
if (!comma && ch != '}' && ch != ']' && ch != EOI) {
|
||||||
throw error(offset, ch);
|
throw jsonReader.error(offset, ch);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (comma && (ch == '}' || ch == ']' || ch == EOI)) {
|
if (comma && (ch == '}' || ch == ']' || ch == EOI)) {
|
||||||
throw error(offset, ch);
|
throw jsonReader.error(offset, ch);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.ch = ch;
|
jsonReader.comma = comma;
|
||||||
this.offset = offset;
|
jsonReader.ch = (char) ch;
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int skipFalse(JSONReaderUTF16 jsonReader, char[] bytes, int offset, int end) {
|
||||||
|
if (offset + 4 > end || IOUtils.notALSE(bytes, offset)) {
|
||||||
|
throw jsonReader.error();
|
||||||
|
}
|
||||||
|
offset += 4;
|
||||||
|
int ch = offset == end ? EOI : bytes[offset++];
|
||||||
|
|
||||||
|
while (ch <= ' ' && ((1L << ch) & SPACE) != 0) {
|
||||||
|
ch = offset == end ? EOI : bytes[offset++];
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean comma = false;
|
||||||
|
if (ch == ',') {
|
||||||
|
comma = true;
|
||||||
|
ch = offset == end ? EOI : bytes[offset++];
|
||||||
|
while (ch <= ' ' && ((1L << ch) & SPACE) != 0) {
|
||||||
|
ch = offset == end ? EOI : bytes[offset++];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((ch == '}' || ch == ']' || ch == EOI)) {
|
||||||
|
throw jsonReader.error(offset, ch);
|
||||||
|
}
|
||||||
|
} else if (ch != '}' && ch != ']' && ch != EOI) {
|
||||||
|
throw jsonReader.error(offset, ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
jsonReader.comma = comma;
|
||||||
|
jsonReader.ch = (char) ch;
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int skipTrue(JSONReaderUTF16 jsonReader, char[] bytes, int offset, int end) {
|
||||||
|
if (offset + 3 > end || IOUtils.notTRUE(bytes, offset - 1)) {
|
||||||
|
throw jsonReader.error();
|
||||||
|
}
|
||||||
|
offset += 3;
|
||||||
|
int ch = offset == end ? EOI : bytes[offset++];
|
||||||
|
|
||||||
|
while (ch <= ' ' && ((1L << ch) & SPACE) != 0) {
|
||||||
|
ch = offset == end ? EOI : bytes[offset++];
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean comma = false;
|
||||||
|
if (ch == ',') {
|
||||||
|
comma = true;
|
||||||
|
ch = offset == end ? EOI : bytes[offset++];
|
||||||
|
while (ch <= ' ' && ((1L << ch) & SPACE) != 0) {
|
||||||
|
ch = offset == end ? EOI : bytes[offset++];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((ch == '}' || ch == ']' || ch == EOI)) {
|
||||||
|
throw jsonReader.error(offset, ch);
|
||||||
|
}
|
||||||
|
} else if (ch != '}' && ch != ']' && ch != EOI) {
|
||||||
|
throw jsonReader.error(offset, ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
jsonReader.comma = comma;
|
||||||
|
jsonReader.ch = (char) ch;
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int skipNull(JSONReaderUTF16 jsonReader, char[] bytes, int offset, int end) {
|
||||||
|
if (offset + 3 > end || IOUtils.notNULL(bytes, offset - 1)) {
|
||||||
|
throw jsonReader.error();
|
||||||
|
}
|
||||||
|
offset += 3;
|
||||||
|
int ch = offset == end ? EOI : bytes[offset++];
|
||||||
|
|
||||||
|
while (ch <= ' ' && ((1L << ch) & SPACE) != 0) {
|
||||||
|
ch = offset == end ? EOI : bytes[offset++];
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean comma = false;
|
||||||
|
if (ch == ',') {
|
||||||
|
comma = true;
|
||||||
|
ch = offset == end ? EOI : bytes[offset++];
|
||||||
|
while (ch <= ' ' && ((1L << ch) & SPACE) != 0) {
|
||||||
|
ch = offset == end ? EOI : bytes[offset++];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((ch == '}' || ch == ']' || ch == EOI)) {
|
||||||
|
throw jsonReader.error(offset, ch);
|
||||||
|
}
|
||||||
|
} else if (ch != '}' && ch != ']' && ch != EOI) {
|
||||||
|
throw jsonReader.error(offset, ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
jsonReader.comma = comma;
|
||||||
|
jsonReader.ch = (char) ch;
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int skipSet(JSONReaderUTF16 jsonReader, char[] bytes, int offset, int end) {
|
||||||
|
if (nextIfSet(jsonReader, bytes, offset, end)) {
|
||||||
|
return skipArray(jsonReader, bytes, jsonReader.offset, end);
|
||||||
|
} else {
|
||||||
|
throw jsonReader.error();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean nextIfSet(JSONReaderUTF16 jsonReader, char[] chars, int offset, int end) {
|
||||||
|
if (offset + 1 < end && chars[offset] == 'e' && chars[offset + 1] == 't') {
|
||||||
|
offset += 2;
|
||||||
|
char ch = offset == end ? EOI : chars[offset++];
|
||||||
|
while (ch <= ' ' && ((1L << ch) & SPACE) != 0) {
|
||||||
|
ch = offset == end ? EOI : chars[offset++];
|
||||||
|
}
|
||||||
|
jsonReader.offset = offset;
|
||||||
|
jsonReader.ch = ch;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int skipValue(JSONReaderUTF16 jsonReader, char[] bytes, int offset, int end) {
|
||||||
|
switch (jsonReader.ch) {
|
||||||
|
case 't':
|
||||||
|
return skipTrue(jsonReader, bytes, offset, end);
|
||||||
|
case 'f':
|
||||||
|
return skipFalse(jsonReader, bytes, offset, end);
|
||||||
|
case 'n':
|
||||||
|
return skipNull(jsonReader, bytes, offset, end);
|
||||||
|
case '"':
|
||||||
|
case '\'':
|
||||||
|
return skipString(jsonReader, bytes, offset, end);
|
||||||
|
case '{':
|
||||||
|
return skipObject(jsonReader, bytes, offset, end);
|
||||||
|
case '[':
|
||||||
|
return skipArray(jsonReader, bytes, offset, end);
|
||||||
|
case 'S':
|
||||||
|
return skipSet(jsonReader, bytes, offset, end);
|
||||||
|
default:
|
||||||
|
return skipNumber(jsonReader, bytes, offset, end);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void skipValue() {
|
||||||
|
this.offset = skipValue(this, chars, offset, end);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -22,6 +22,8 @@ import static java.nio.charset.StandardCharsets.UTF_8;
|
|||||||
class JSONReaderUTF8
|
class JSONReaderUTF8
|
||||||
extends JSONReader {
|
extends JSONReader {
|
||||||
static final int REF = BIG_ENDIAN ? 0x24726566 : 0x66657224;
|
static final int REF = BIG_ENDIAN ? 0x24726566 : 0x66657224;
|
||||||
|
static final int ESCAPE_INDEX_NOT_SET = -2;
|
||||||
|
protected int nextEscapeIndex = ESCAPE_INDEX_NOT_SET;
|
||||||
|
|
||||||
protected final byte[] bytes;
|
protected final byte[] bytes;
|
||||||
protected final int length;
|
protected final int length;
|
||||||
@ -119,6 +121,14 @@ class JSONReaderUTF8
|
|||||||
next();
|
next();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int indexOfSlash(JSONReaderUTF8 jsonReader, byte[] bytes, int offset, int end) {
|
||||||
|
int slashIndex = jsonReader.nextEscapeIndex;
|
||||||
|
if (slashIndex == ESCAPE_INDEX_NOT_SET || (slashIndex != -1 && slashIndex < offset)) {
|
||||||
|
jsonReader.nextEscapeIndex = slashIndex = IOUtils.indexOfSlash(bytes, offset, end);
|
||||||
|
}
|
||||||
|
return slashIndex;
|
||||||
|
}
|
||||||
|
|
||||||
private void char_utf8(int ch, int offset) {
|
private void char_utf8(int ch, int offset) {
|
||||||
final byte[] bytes = this.bytes;
|
final byte[] bytes = this.bytes;
|
||||||
switch ((ch & 0xFF) >> 4) {
|
switch ((ch & 0xFF) >> 4) {
|
||||||
@ -4246,236 +4256,276 @@ class JSONReaderUTF8
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final boolean skipName() {
|
public final boolean skipName() {
|
||||||
char quote = ch;
|
this.offset = skipName(this, bytes, offset, end);
|
||||||
if (quote == '\'' && ((context.features & Feature.DisableSingleQuote.mask) != 0)) {
|
|
||||||
throw notSupportName();
|
|
||||||
}
|
|
||||||
if (quote != '"' && quote != '\'') {
|
|
||||||
if ((context.features & Feature.AllowUnQuotedFieldNames.mask) != 0) {
|
|
||||||
readFieldNameHashCodeUnquote();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
throw notSupportName();
|
|
||||||
}
|
|
||||||
|
|
||||||
int offset = this.offset;
|
|
||||||
final byte[] bytes = this.bytes;
|
|
||||||
for (; ; ) {
|
|
||||||
int ch = bytes[offset++];
|
|
||||||
if (ch == '\\') {
|
|
||||||
ch = bytes[offset];
|
|
||||||
offset += (ch == 'u' ? 5 : (ch == 'x' ? 3 : 1));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ch == quote) {
|
|
||||||
ch = offset == end ? EOI : bytes[offset++];
|
|
||||||
|
|
||||||
while (ch <= ' ' && ((1L << ch) & SPACE) != 0) {
|
|
||||||
ch = offset == end ? EOI : bytes[offset++];
|
|
||||||
}
|
|
||||||
if (ch != ':') {
|
|
||||||
throw syntaxError(ch);
|
|
||||||
}
|
|
||||||
|
|
||||||
ch = offset == end ? EOI : bytes[offset++];
|
|
||||||
|
|
||||||
while (ch <= ' ' && ((1L << ch) & SPACE) != 0) {
|
|
||||||
ch = offset == end ? EOI : bytes[offset++];
|
|
||||||
}
|
|
||||||
|
|
||||||
this.offset = offset;
|
|
||||||
this.ch = (char) ch;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private static int skipName(JSONReaderUTF8 jsonReader, byte[] bytes, int offset, int end) {
|
||||||
public final void skipValue() {
|
int quote = jsonReader.ch;
|
||||||
final byte[] bytes = this.bytes;
|
if (jsonReader.checkNameBegin(quote)) {
|
||||||
int ch = this.ch;
|
return jsonReader.offset;
|
||||||
int offset = this.offset, end = this.end;
|
}
|
||||||
comma = false;
|
|
||||||
|
|
||||||
switch_:
|
int index = IOUtils.indexOfQuote(bytes, quote, offset, end);
|
||||||
switch (ch) {
|
if (index == -1) {
|
||||||
case '-':
|
throw jsonReader.error("invalid escape character EOI");
|
||||||
case '+':
|
}
|
||||||
case '0':
|
|
||||||
case '1':
|
int ch;
|
||||||
case '2':
|
int slashIndex = indexOfSlash(jsonReader, bytes, offset, end);
|
||||||
case '3':
|
if (slashIndex == -1 || slashIndex > index) {
|
||||||
case '4':
|
offset = index + 1;
|
||||||
case '5':
|
ch = offset == end ? EOI : bytes[offset++];
|
||||||
case '6':
|
} else {
|
||||||
case '7':
|
offset = skipStringEscaped(jsonReader, bytes, slashIndex, quote);
|
||||||
case '8':
|
ch = offset == end ? EOI : bytes[offset++];
|
||||||
case '9':
|
}
|
||||||
case '.':
|
|
||||||
boolean sign = ch == '-' || ch == '+';
|
while (ch <= ' ' && ((1L << ch) & SPACE) != 0) {
|
||||||
if (sign) {
|
ch = offset == end ? EOI : bytes[offset++];
|
||||||
|
}
|
||||||
|
if (ch != ':') {
|
||||||
|
throw syntaxError(ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
ch = offset == end ? EOI : bytes[offset++];
|
||||||
|
|
||||||
|
while (ch <= ' ' && ((1L << ch) & SPACE) != 0) {
|
||||||
|
ch = offset == end ? EOI : bytes[offset++];
|
||||||
|
}
|
||||||
|
|
||||||
|
jsonReader.ch = (char) ch;
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int skipNumber(JSONReaderUTF8 jsonReader, byte[] bytes, int offset, int end) {
|
||||||
|
int ch = jsonReader.ch;
|
||||||
|
if (ch == '-' || ch == '+') {
|
||||||
|
if (offset < end) {
|
||||||
|
ch = bytes[offset++];
|
||||||
|
} else {
|
||||||
|
throw jsonReader.error();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
boolean dot = ch == '.';
|
||||||
|
boolean num = false;
|
||||||
|
if (!dot && (ch >= '0' && ch <= '9')) {
|
||||||
|
num = true;
|
||||||
|
do {
|
||||||
|
ch = offset == end ? EOI : bytes[offset++];
|
||||||
|
} while (ch >= '0' && ch <= '9');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (num && (ch == 'L' | ch == 'F' | ch == 'D' | ch == 'B' | ch == 'S')) {
|
||||||
|
ch = bytes[offset++];
|
||||||
|
} else {
|
||||||
|
boolean small = false;
|
||||||
|
if (ch == '.') {
|
||||||
|
small = true;
|
||||||
|
ch = offset == end ? EOI : bytes[offset++];
|
||||||
|
|
||||||
|
while (ch >= '0' && ch <= '9') {
|
||||||
|
ch = offset == end ? EOI : bytes[offset++];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!num && !small) {
|
||||||
|
throw numberError(offset, ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ch == 'e' || ch == 'E') {
|
||||||
|
ch = bytes[offset++];
|
||||||
|
|
||||||
|
boolean eSign = false;
|
||||||
|
if (ch == '+' || ch == '-') {
|
||||||
|
eSign = true;
|
||||||
if (offset < end) {
|
if (offset < end) {
|
||||||
ch = bytes[offset++];
|
ch = bytes[offset++];
|
||||||
} else {
|
} else {
|
||||||
throw numberError(offset, ch);
|
throw numberError(offset, ch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
boolean dot = ch == '.';
|
|
||||||
boolean num = false;
|
if (ch >= '0' && ch <= '9') {
|
||||||
if (!dot && (ch >= '0' && ch <= '9')) {
|
|
||||||
num = true;
|
|
||||||
do {
|
do {
|
||||||
ch = offset == end ? EOI : bytes[offset++];
|
ch = offset == end ? EOI : bytes[offset++];
|
||||||
} while (ch >= '0' && ch <= '9');
|
} while (ch >= '0' && ch <= '9');
|
||||||
}
|
} else if (eSign) {
|
||||||
|
|
||||||
if (num && (ch == 'L' || ch == 'F' || ch == 'D' || ch == 'B' || ch == 'S')) {
|
|
||||||
ch = bytes[offset++];
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean small = false;
|
|
||||||
if (ch == '.') {
|
|
||||||
small = true;
|
|
||||||
ch = offset == end ? EOI : bytes[offset++];
|
|
||||||
|
|
||||||
if (ch >= '0' && ch <= '9') {
|
|
||||||
do {
|
|
||||||
ch = offset == end ? EOI : bytes[offset++];
|
|
||||||
} while (ch >= '0' && ch <= '9');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!num && !small) {
|
|
||||||
throw numberError(offset, ch);
|
throw numberError(offset, ch);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ch == 'e' || ch == 'E') {
|
|
||||||
ch = bytes[offset++];
|
|
||||||
|
|
||||||
boolean eSign = false;
|
|
||||||
if (ch == '+' || ch == '-') {
|
|
||||||
eSign = true;
|
|
||||||
if (offset < end) {
|
|
||||||
ch = bytes[offset++];
|
|
||||||
} else {
|
|
||||||
throw numberError(offset, ch);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ch >= '0' && ch <= '9') {
|
|
||||||
do {
|
|
||||||
ch = offset == end ? EOI : bytes[offset++];
|
|
||||||
} while (ch >= '0' && ch <= '9');
|
|
||||||
} else if (eSign) {
|
|
||||||
throw numberError(offset, ch);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ch == 'L' || ch == 'F' || ch == 'D' || ch == 'B' || ch == 'S') {
|
|
||||||
ch = offset == end ? EOI : bytes[offset++];
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 't':
|
|
||||||
if (offset + 3 > end) {
|
|
||||||
throw error(offset, ch);
|
|
||||||
}
|
|
||||||
if (bytes[offset] != 'r' || bytes[offset + 1] != 'u' || bytes[offset + 2] != 'e') {
|
|
||||||
throw error(offset, ch);
|
|
||||||
}
|
|
||||||
offset += 3;
|
|
||||||
ch = offset == end ? EOI : bytes[offset++];
|
|
||||||
break;
|
|
||||||
case 'f':
|
|
||||||
if (offset + 4 > end) {
|
|
||||||
throw error(offset, ch);
|
|
||||||
}
|
|
||||||
if (bytes[offset] != 'a' || bytes[offset + 1] != 'l' || bytes[offset + 2] != 's' || bytes[offset + 3] != 'e') {
|
|
||||||
throw error(offset, ch);
|
|
||||||
}
|
|
||||||
offset += 4;
|
|
||||||
ch = offset == end ? EOI : bytes[offset++];
|
|
||||||
break;
|
|
||||||
case 'n':
|
|
||||||
if (offset + 3 > end) {
|
|
||||||
throw error(offset, ch);
|
|
||||||
}
|
|
||||||
if (bytes[offset] != 'u' || bytes[offset + 1] != 'l' || bytes[offset + 2] != 'l') {
|
|
||||||
throw error(offset, ch);
|
|
||||||
}
|
|
||||||
offset += 3;
|
|
||||||
ch = offset == end ? EOI : bytes[offset++];
|
|
||||||
break;
|
|
||||||
case '"':
|
|
||||||
case '\'': {
|
|
||||||
int quote = ch;
|
|
||||||
ch = bytes[offset++];
|
|
||||||
for (; ; ) {
|
|
||||||
if (ch == '\\') {
|
|
||||||
ch = bytes[offset++];
|
|
||||||
if (ch == 'u') {
|
|
||||||
offset += 4;
|
|
||||||
} else if (ch == 'x') {
|
|
||||||
offset += 2;
|
|
||||||
} else if (ch != '\\' && ch != '"') {
|
|
||||||
char1(ch);
|
|
||||||
}
|
|
||||||
ch = bytes[offset++];
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (ch == quote) {
|
|
||||||
ch = offset == end ? EOI : bytes[offset++];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
ch = bytes[offset++];
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
default:
|
|
||||||
if (ch == '[') {
|
if (ch == 'F' || ch == 'D') {
|
||||||
next();
|
ch = offset == end ? EOI : bytes[offset++];
|
||||||
for (int i = 0; ; ++i) {
|
}
|
||||||
if (this.ch == ']') {
|
|
||||||
comma = false;
|
|
||||||
offset = this.offset;
|
|
||||||
ch = offset == end ? EOI : bytes[offset++];
|
|
||||||
break switch_;
|
|
||||||
}
|
|
||||||
if (i != 0 && !comma) {
|
|
||||||
throw valueError();
|
|
||||||
}
|
|
||||||
comma = false;
|
|
||||||
skipValue();
|
|
||||||
}
|
|
||||||
} else if (ch == '{') {
|
|
||||||
next();
|
|
||||||
for (; ; ) {
|
|
||||||
if (this.ch == '}') {
|
|
||||||
comma = false;
|
|
||||||
offset = this.offset;
|
|
||||||
ch = offset == end ? EOI : bytes[offset++];
|
|
||||||
break switch_;
|
|
||||||
}
|
|
||||||
skipName();
|
|
||||||
skipValue();
|
|
||||||
}
|
|
||||||
} else if (ch == 'S' && nextIfSet()) {
|
|
||||||
skipValue();
|
|
||||||
} else {
|
|
||||||
throw error(offset, ch);
|
|
||||||
}
|
|
||||||
ch = this.ch;
|
|
||||||
offset = this.offset;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
while (ch <= ' ' && ((1L << ch) & SPACE) != 0) {
|
while (ch <= ' ' && ((1L << ch) & SPACE) != 0) {
|
||||||
ch = offset == end ? EOI : bytes[offset++];
|
ch = offset == end ? EOI : bytes[offset++];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean comma = false;
|
||||||
|
if (ch == ',') {
|
||||||
|
comma = true;
|
||||||
|
ch = offset == end ? EOI : bytes[offset++];
|
||||||
|
while (ch <= ' ' && ((1L << ch) & SPACE) != 0) {
|
||||||
|
ch = offset == end ? EOI : bytes[offset++];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((ch == '}' || ch == ']' || ch == EOI)) {
|
||||||
|
throw jsonReader.error(offset, ch);
|
||||||
|
}
|
||||||
|
} else if (ch != '}' && ch != ']' && ch != EOI) {
|
||||||
|
throw jsonReader.error(offset, ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
jsonReader.comma = comma;
|
||||||
|
jsonReader.ch = (char) ch;
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int skipString(JSONReaderUTF8 jsonReader, byte[] bytes, int offset, int end) {
|
||||||
|
int ch = jsonReader.ch;
|
||||||
|
int quote = ch;
|
||||||
|
int index = IOUtils.indexOfQuote(bytes, quote, offset, end);
|
||||||
|
if (index == -1) {
|
||||||
|
throw jsonReader.error("invalid escape character EOI");
|
||||||
|
}
|
||||||
|
int slashIndex = indexOfSlash(jsonReader, bytes, offset, end);
|
||||||
|
if (slashIndex == -1 || slashIndex > index) {
|
||||||
|
offset = index + 1;
|
||||||
|
ch = offset == end ? EOI : bytes[offset++];
|
||||||
|
} else {
|
||||||
|
offset = skipStringEscaped(jsonReader, bytes, slashIndex, quote);
|
||||||
|
ch = offset == end ? EOI : bytes[offset++];
|
||||||
|
}
|
||||||
|
|
||||||
|
while (ch <= ' ' && ((1L << ch) & SPACE) != 0) {
|
||||||
|
ch = offset == end ? EOI : bytes[offset++];
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean comma = false;
|
||||||
|
if (ch == ',') {
|
||||||
|
comma = true;
|
||||||
|
ch = offset == end ? EOI : bytes[offset++];
|
||||||
|
while (ch <= ' ' && ((1L << ch) & SPACE) != 0) {
|
||||||
|
ch = offset == end ? EOI : bytes[offset++];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((ch == '}' || ch == ']' || ch == EOI)) {
|
||||||
|
throw jsonReader.error(offset, ch);
|
||||||
|
}
|
||||||
|
} else if (ch != '}' && ch != ']' && ch != EOI) {
|
||||||
|
throw jsonReader.error(offset, ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
jsonReader.comma = comma;
|
||||||
|
jsonReader.ch = (char) ch;
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int skipStringEscaped(JSONReaderUTF8 jsonReader, byte[] bytes, int offset, int quote) {
|
||||||
|
int ch = bytes[offset++];
|
||||||
|
for (; ; ) {
|
||||||
|
if (ch == '\\') {
|
||||||
|
ch = bytes[offset++];
|
||||||
|
if (ch == 'u') {
|
||||||
|
offset += 4;
|
||||||
|
} else if (ch == 'x') {
|
||||||
|
offset += 2;
|
||||||
|
} else if (ch != '\\' && ch != '"') {
|
||||||
|
jsonReader.char1(ch);
|
||||||
|
}
|
||||||
|
ch = bytes[offset++];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (ch == quote) {
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
ch = bytes[offset++];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int skipObject(JSONReaderUTF8 jsonReader, byte[] bytes, int offset, int end) {
|
||||||
|
offset = next(jsonReader, bytes, offset, end);
|
||||||
|
for (int i = 0; ; ++i) {
|
||||||
|
if (jsonReader.ch == '}') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (i != 0 && !jsonReader.comma) {
|
||||||
|
throw jsonReader.valueError();
|
||||||
|
}
|
||||||
|
offset = skipName(jsonReader, bytes, offset, end);
|
||||||
|
offset = skipValue(jsonReader, bytes, offset, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ch = offset == end ? EOI : bytes[offset++];
|
||||||
|
|
||||||
|
while (ch <= ' ' && ((1L << ch) & SPACE) != 0) {
|
||||||
|
ch = offset == end ? EOI : bytes[offset++];
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean comma = false;
|
||||||
|
if (ch == ',') {
|
||||||
|
comma = true;
|
||||||
|
ch = offset == end ? EOI : bytes[offset++];
|
||||||
|
while (ch <= ' ' && ((1L << ch) & SPACE) != 0) {
|
||||||
|
ch = offset == end ? EOI : bytes[offset++];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((ch == '}' || ch == ']' || ch == EOI)) {
|
||||||
|
throw jsonReader.error(offset, ch);
|
||||||
|
}
|
||||||
|
} else if (ch != '}' && ch != ']' && ch != EOI) {
|
||||||
|
throw jsonReader.error(offset, ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
jsonReader.comma = comma;
|
||||||
|
jsonReader.ch = (char) ch;
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int next(JSONReaderUTF8 jsonReader, byte[] bytes, int offset, int end) {
|
||||||
|
int ch = offset >= end ? EOI : bytes[offset++];
|
||||||
|
while (ch == '\0' || (ch <= ' ' && ((1L << ch) & SPACE) != 0)) {
|
||||||
|
ch = offset == end ? EOI : bytes[offset++];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ch < 0) {
|
||||||
|
jsonReader.char_utf8(ch, offset);
|
||||||
|
return jsonReader.offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
jsonReader.ch = (char) ch;
|
||||||
|
if (ch == '/') {
|
||||||
|
jsonReader.offset = offset;
|
||||||
|
jsonReader.skipComment();
|
||||||
|
return jsonReader.offset;
|
||||||
|
} else {
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int skipArray(JSONReaderUTF8 jsonReader, byte[] bytes, int offset, int end) {
|
||||||
|
offset = next(jsonReader, bytes, offset, end);
|
||||||
|
for (int i = 0; ; ++i) {
|
||||||
|
if (jsonReader.ch == ']') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (i != 0 && !jsonReader.comma) {
|
||||||
|
throw jsonReader.valueError();
|
||||||
|
}
|
||||||
|
offset = skipValue(jsonReader, bytes, offset, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ch = offset == end ? EOI : bytes[offset++];
|
||||||
|
|
||||||
|
while (ch <= ' ' && ((1L << ch) & SPACE) != 0) {
|
||||||
|
ch = offset == end ? EOI : bytes[offset++];
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean comma = false;
|
||||||
if (ch == ',') {
|
if (ch == ',') {
|
||||||
comma = true;
|
comma = true;
|
||||||
ch = offset == end ? EOI : bytes[offset++];
|
ch = offset == end ? EOI : bytes[offset++];
|
||||||
@ -4485,15 +4535,158 @@ class JSONReaderUTF8
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!comma && ch != '}' && ch != ']' && ch != EOI) {
|
if (!comma && ch != '}' && ch != ']' && ch != EOI) {
|
||||||
throw error(offset, ch);
|
throw jsonReader.error(offset, ch);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (comma && (ch == '}' || ch == ']' || ch == EOI)) {
|
if (comma && (ch == '}' || ch == ']' || ch == EOI)) {
|
||||||
throw error(offset, ch);
|
throw jsonReader.error(offset, ch);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.ch = (char) ch;
|
jsonReader.comma = comma;
|
||||||
this.offset = offset;
|
jsonReader.ch = (char) ch;
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int skipFalse(JSONReaderUTF8 jsonReader, byte[] bytes, int offset, int end) {
|
||||||
|
if (offset + 4 > end || IOUtils.notALSE(bytes, offset)) {
|
||||||
|
throw jsonReader.error();
|
||||||
|
}
|
||||||
|
offset += 4;
|
||||||
|
int ch = offset == end ? EOI : bytes[offset++];
|
||||||
|
|
||||||
|
while (ch <= ' ' && ((1L << ch) & SPACE) != 0) {
|
||||||
|
ch = offset == end ? EOI : bytes[offset++];
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean comma = false;
|
||||||
|
if (ch == ',') {
|
||||||
|
comma = true;
|
||||||
|
ch = offset == end ? EOI : bytes[offset++];
|
||||||
|
while (ch <= ' ' && ((1L << ch) & SPACE) != 0) {
|
||||||
|
ch = offset == end ? EOI : bytes[offset++];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((ch == '}' || ch == ']' || ch == EOI)) {
|
||||||
|
throw jsonReader.error(offset, ch);
|
||||||
|
}
|
||||||
|
} else if (ch != '}' && ch != ']' && ch != EOI) {
|
||||||
|
throw jsonReader.error(offset, ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
jsonReader.comma = comma;
|
||||||
|
jsonReader.ch = (char) ch;
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int skipTrue(JSONReaderUTF8 jsonReader, byte[] bytes, int offset, int end) {
|
||||||
|
if (offset + 3 > end || IOUtils.notTRUE(bytes, offset - 1)) {
|
||||||
|
throw jsonReader.error();
|
||||||
|
}
|
||||||
|
offset += 3;
|
||||||
|
int ch = offset == end ? EOI : bytes[offset++];
|
||||||
|
|
||||||
|
while (ch <= ' ' && ((1L << ch) & SPACE) != 0) {
|
||||||
|
ch = offset == end ? EOI : bytes[offset++];
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean comma = false;
|
||||||
|
if (ch == ',') {
|
||||||
|
comma = true;
|
||||||
|
ch = offset == end ? EOI : bytes[offset++];
|
||||||
|
while (ch <= ' ' && ((1L << ch) & SPACE) != 0) {
|
||||||
|
ch = offset == end ? EOI : bytes[offset++];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((ch == '}' || ch == ']' || ch == EOI)) {
|
||||||
|
throw jsonReader.error(offset, ch);
|
||||||
|
}
|
||||||
|
} else if (ch != '}' && ch != ']' && ch != EOI) {
|
||||||
|
throw jsonReader.error(offset, ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
jsonReader.comma = comma;
|
||||||
|
jsonReader.ch = (char) ch;
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int skipNull(JSONReaderUTF8 jsonReader, byte[] bytes, int offset, int end) {
|
||||||
|
if (offset + 3 > end || IOUtils.notNULL(bytes, offset - 1)) {
|
||||||
|
throw jsonReader.error();
|
||||||
|
}
|
||||||
|
offset += 3;
|
||||||
|
int ch = offset == end ? EOI : bytes[offset++];
|
||||||
|
|
||||||
|
while (ch <= ' ' && ((1L << ch) & SPACE) != 0) {
|
||||||
|
ch = offset == end ? EOI : bytes[offset++];
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean comma = false;
|
||||||
|
if (ch == ',') {
|
||||||
|
comma = true;
|
||||||
|
ch = offset == end ? EOI : bytes[offset++];
|
||||||
|
while (ch <= ' ' && ((1L << ch) & SPACE) != 0) {
|
||||||
|
ch = offset == end ? EOI : bytes[offset++];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((ch == '}' || ch == ']' || ch == EOI)) {
|
||||||
|
throw jsonReader.error(offset, ch);
|
||||||
|
}
|
||||||
|
} else if (ch != '}' && ch != ']' && ch != EOI) {
|
||||||
|
throw jsonReader.error(offset, ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
jsonReader.comma = comma;
|
||||||
|
jsonReader.ch = (char) ch;
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int skipSet(JSONReaderUTF8 jsonReader, byte[] bytes, int offset, int end) {
|
||||||
|
if (nextIfSet(jsonReader, bytes, offset, end)) {
|
||||||
|
return skipArray(jsonReader, bytes, jsonReader.offset, end);
|
||||||
|
} else {
|
||||||
|
throw jsonReader.error();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean nextIfSet(JSONReaderUTF8 jsonReader, byte[] chars, int offset, int end) {
|
||||||
|
if (offset + 1 < end && chars[offset] == 'e' && chars[offset + 1] == 't') {
|
||||||
|
offset += 2;
|
||||||
|
int ch = offset == end ? EOI : chars[offset++];
|
||||||
|
while (ch <= ' ' && ((1L << ch) & SPACE) != 0) {
|
||||||
|
ch = offset == end ? EOI : chars[offset++];
|
||||||
|
}
|
||||||
|
jsonReader.offset = offset;
|
||||||
|
jsonReader.ch = (char) ch;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int skipValue(JSONReaderUTF8 jsonReader, byte[] bytes, int offset, int end) {
|
||||||
|
switch (jsonReader.ch) {
|
||||||
|
case 't':
|
||||||
|
return skipTrue(jsonReader, bytes, offset, end);
|
||||||
|
case 'f':
|
||||||
|
return skipFalse(jsonReader, bytes, offset, end);
|
||||||
|
case 'n':
|
||||||
|
return skipNull(jsonReader, bytes, offset, end);
|
||||||
|
case '"':
|
||||||
|
case '\'':
|
||||||
|
return skipString(jsonReader, bytes, offset, end);
|
||||||
|
case '{':
|
||||||
|
return skipObject(jsonReader, bytes, offset, end);
|
||||||
|
case '[':
|
||||||
|
return skipArray(jsonReader, bytes, offset, end);
|
||||||
|
case 'S':
|
||||||
|
return skipSet(jsonReader, bytes, offset, end);
|
||||||
|
default:
|
||||||
|
return skipNumber(jsonReader, bytes, offset, end);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void skipValue() {
|
||||||
|
this.offset = skipValue(this, bytes, offset, end);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -5740,9 +5933,10 @@ class JSONReaderUTF8
|
|||||||
}
|
}
|
||||||
if (ch < 0) {
|
if (ch < 0) {
|
||||||
char_utf8(ch, offset);
|
char_utf8(ch, offset);
|
||||||
|
} else {
|
||||||
|
this.offset = offset;
|
||||||
|
this.ch = (char) ch;
|
||||||
}
|
}
|
||||||
this.offset = offset;
|
|
||||||
this.ch = (char) ch;
|
|
||||||
return OffsetDateTime.of(
|
return OffsetDateTime.of(
|
||||||
yy + ((int) ymd & 0xFF),
|
yy + ((int) ymd & 0xFF),
|
||||||
(int) (ymd >> 24) & 0xFF,
|
(int) (ymd >> 24) & 0xFF,
|
||||||
|
@ -58,6 +58,7 @@ public class ASMUtils {
|
|||||||
public static final String TYPE_OBJECT_READER_10 = ObjectReader10.class.getName().replace('.', '/');
|
public static final String TYPE_OBJECT_READER_10 = ObjectReader10.class.getName().replace('.', '/');
|
||||||
public static final String TYPE_OBJECT_READER_11 = ObjectReader11.class.getName().replace('.', '/');
|
public static final String TYPE_OBJECT_READER_11 = ObjectReader11.class.getName().replace('.', '/');
|
||||||
public static final String TYPE_OBJECT_READER_12 = ObjectReader12.class.getName().replace('.', '/');
|
public static final String TYPE_OBJECT_READER_12 = ObjectReader12.class.getName().replace('.', '/');
|
||||||
|
public static final String TYPE_OBJECT_READER_NONE_DEFAULT_CONSTRUCTOR = ObjectReaderNoneDefaultConstructor.class.getName().replace('.', '/');
|
||||||
public static final String TYPE_BYTE_ARRAY_VALUE_CONSUMER = ByteArrayValueConsumer.class.getName().replace('.', '/');
|
public static final String TYPE_BYTE_ARRAY_VALUE_CONSUMER = ByteArrayValueConsumer.class.getName().replace('.', '/');
|
||||||
public static final String TYPE_CHAR_ARRAY_VALUE_CONSUMER = CharArrayValueConsumer.class.getName().replace('.', '/');
|
public static final String TYPE_CHAR_ARRAY_VALUE_CONSUMER = CharArrayValueConsumer.class.getName().replace('.', '/');
|
||||||
public static final String TYPE_TYPE_UTILS = TypeUtils.class.getName().replace('.', '/');
|
public static final String TYPE_TYPE_UTILS = TypeUtils.class.getName().replace('.', '/');
|
||||||
|
@ -77,6 +77,8 @@ class Frame {
|
|||||||
|
|
||||||
// Constants to manipulate the DIM field of an abstract type.
|
// Constants to manipulate the DIM field of an abstract type.
|
||||||
|
|
||||||
|
private static final int ARRAY_OF = +1 << DIM_SHIFT;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The constant to be added to an abstract type to get one with one less array dimension.
|
* The constant to be added to an abstract type to get one with one less array dimension.
|
||||||
*/
|
*/
|
||||||
@ -877,6 +879,7 @@ class Frame {
|
|||||||
case Opcodes.IASTORE:
|
case Opcodes.IASTORE:
|
||||||
case Opcodes.BASTORE:
|
case Opcodes.BASTORE:
|
||||||
case Opcodes.CASTORE:
|
case Opcodes.CASTORE:
|
||||||
|
case Opcodes.AASTORE:
|
||||||
pop(3);
|
pop(3);
|
||||||
break;
|
break;
|
||||||
case Opcodes.POP:
|
case Opcodes.POP:
|
||||||
@ -980,6 +983,15 @@ class Frame {
|
|||||||
push(LONG);
|
push(LONG);
|
||||||
push(TOP);
|
push(TOP);
|
||||||
break;
|
break;
|
||||||
|
case Opcodes.I2F:
|
||||||
|
pop(1);
|
||||||
|
push(FLOAT);
|
||||||
|
break;
|
||||||
|
case Opcodes.I2D:
|
||||||
|
pop(1);
|
||||||
|
push(DOUBLE);
|
||||||
|
push(TOP);
|
||||||
|
break;
|
||||||
case Opcodes.F2I:
|
case Opcodes.F2I:
|
||||||
case Opcodes.ARRAYLENGTH:
|
case Opcodes.ARRAYLENGTH:
|
||||||
case Opcodes.INSTANCEOF:
|
case Opcodes.INSTANCEOF:
|
||||||
@ -1022,6 +1034,15 @@ class Frame {
|
|||||||
case Opcodes.NEW:
|
case Opcodes.NEW:
|
||||||
push(UNINITIALIZED_KIND | symbolTable.addUninitializedType(argSymbol.value, arg));
|
push(UNINITIALIZED_KIND | symbolTable.addUninitializedType(argSymbol.value, arg));
|
||||||
break;
|
break;
|
||||||
|
case Opcodes.ANEWARRAY:
|
||||||
|
String arrayElementType = argSymbol.value;
|
||||||
|
pop();
|
||||||
|
if (arrayElementType.charAt(0) == '[') {
|
||||||
|
push(symbolTable, '[' + arrayElementType);
|
||||||
|
} else {
|
||||||
|
push(ARRAY_OF | REFERENCE_KIND | symbolTable.addType(arrayElementType));
|
||||||
|
}
|
||||||
|
break;
|
||||||
case Opcodes.CHECKCAST:
|
case Opcodes.CHECKCAST:
|
||||||
String castType = argSymbol.value;
|
String castType = argSymbol.value;
|
||||||
pop();
|
pop();
|
||||||
|
@ -293,6 +293,14 @@ public final class MethodWriter {
|
|||||||
visitInsn(Opcodes.I2L);
|
visitInsn(Opcodes.I2L);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void i2f() {
|
||||||
|
visitInsn(Opcodes.I2F);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void i2d() {
|
||||||
|
visitInsn(Opcodes.I2D);
|
||||||
|
}
|
||||||
|
|
||||||
public void lxor() {
|
public void lxor() {
|
||||||
visitInsn(Opcodes.LXOR);
|
visitInsn(Opcodes.LXOR);
|
||||||
}
|
}
|
||||||
@ -305,6 +313,10 @@ public final class MethodWriter {
|
|||||||
visitInsn(Opcodes.AALOAD);
|
visitInsn(Opcodes.AALOAD);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void aastore() {
|
||||||
|
visitInsn(Opcodes.AASTORE);
|
||||||
|
}
|
||||||
|
|
||||||
private void visitInsn(final int opcode) {
|
private void visitInsn(final int opcode) {
|
||||||
lastBytecodeOffset = code.length;
|
lastBytecodeOffset = code.length;
|
||||||
// Add the instruction to the bytecode of the method.
|
// Add the instruction to the bytecode of the method.
|
||||||
@ -455,6 +467,10 @@ public final class MethodWriter {
|
|||||||
visitTypeInsn(Opcodes.NEW, type);
|
visitTypeInsn(Opcodes.NEW, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void anewArray(final String type) {
|
||||||
|
visitTypeInsn(Opcodes.ANEWARRAY, type);
|
||||||
|
}
|
||||||
|
|
||||||
public void instanceOf(final String type) {
|
public void instanceOf(final String type) {
|
||||||
visitTypeInsn(Opcodes.INSTANCEOF, type);
|
visitTypeInsn(Opcodes.INSTANCEOF, type);
|
||||||
}
|
}
|
||||||
|
@ -91,6 +91,7 @@ public interface Opcodes {
|
|||||||
int DSTORE = 57; // -
|
int DSTORE = 57; // -
|
||||||
int ASTORE = 58; // -
|
int ASTORE = 58; // -
|
||||||
int IASTORE = 79; // visitInsn
|
int IASTORE = 79; // visitInsn
|
||||||
|
int AASTORE = 83; // -
|
||||||
int BASTORE = 84; // -
|
int BASTORE = 84; // -
|
||||||
int CASTORE = 85; // -
|
int CASTORE = 85; // -
|
||||||
int POP = 87; // visitInsn
|
int POP = 87; // visitInsn
|
||||||
@ -126,6 +127,8 @@ public interface Opcodes {
|
|||||||
int LXOR = 131; // -
|
int LXOR = 131; // -
|
||||||
int IINC = 132; // visitIincInsn
|
int IINC = 132; // visitIincInsn
|
||||||
int I2L = 133; // visitInsn
|
int I2L = 133; // visitInsn
|
||||||
|
int I2F = 134; // -
|
||||||
|
int I2D = 135; // -
|
||||||
int L2I = 136; //
|
int L2I = 136; //
|
||||||
int F2I = 139; // -
|
int F2I = 139; // -
|
||||||
int F2L = 140; // -
|
int F2L = 140; // -
|
||||||
@ -173,6 +176,8 @@ public interface Opcodes {
|
|||||||
int INVOKESTATIC = 184; // -
|
int INVOKESTATIC = 184; // -
|
||||||
int INVOKEINTERFACE = 185; // -
|
int INVOKEINTERFACE = 185; // -
|
||||||
int NEW = 187; // visitTypeInsn
|
int NEW = 187; // visitTypeInsn
|
||||||
|
int NEWARRAY = 188; // -
|
||||||
|
int ANEWARRAY = 189; // -
|
||||||
int ARRAYLENGTH = 190; // visitInsn
|
int ARRAYLENGTH = 190; // visitInsn
|
||||||
int ATHROW = 191; // -
|
int ATHROW = 191; // -
|
||||||
int CHECKCAST = 192; // visitTypeInsn
|
int CHECKCAST = 192; // visitTypeInsn
|
||||||
|
@ -70,8 +70,10 @@ public abstract class FieldReader<T>
|
|||||||
this.fieldName = fieldName;
|
this.fieldName = fieldName;
|
||||||
this.fieldType = fieldType;
|
this.fieldType = fieldType;
|
||||||
this.fieldClass = fieldClass;
|
this.fieldClass = fieldClass;
|
||||||
this.fieldClassSerializable = fieldClass != null && (Serializable.class.isAssignableFrom(fieldClass)
|
this.fieldClassSerializable = fieldClass != null
|
||||||
|| Modifier.isInterface(fieldClass.getModifiers()));
|
&& (Serializable.class.isAssignableFrom(fieldClass)
|
||||||
|
|| Modifier.isInterface(fieldClass.getModifiers())
|
||||||
|
|| BeanUtils.isRecord(fieldClass));
|
||||||
this.features = features;
|
this.features = features;
|
||||||
this.fieldNameHash = Fnv.hashCode64(fieldName);
|
this.fieldNameHash = Fnv.hashCode64(fieldName);
|
||||||
this.fieldNameHashLCase = Fnv.hashCode64LCase(fieldName);
|
this.fieldNameHashLCase = Fnv.hashCode64LCase(fieldName);
|
||||||
|
@ -0,0 +1,37 @@
|
|||||||
|
package com.alibaba.fastjson2.reader;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.schema.JSONSchema;
|
||||||
|
import com.alibaba.fastjson2.util.Fnv;
|
||||||
|
|
||||||
|
import java.lang.reflect.Parameter;
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
public class FieldReaderListParam
|
||||||
|
extends FieldReaderList {
|
||||||
|
final Parameter parameter;
|
||||||
|
final String paramName;
|
||||||
|
final long paramNameHash;
|
||||||
|
|
||||||
|
public FieldReaderListParam(
|
||||||
|
String fieldName,
|
||||||
|
Type fieldType,
|
||||||
|
String paramName,
|
||||||
|
Parameter parameter,
|
||||||
|
Class fieldClass,
|
||||||
|
Type itemType,
|
||||||
|
Class itemClass,
|
||||||
|
int ordinal,
|
||||||
|
long features,
|
||||||
|
String format,
|
||||||
|
Locale locale,
|
||||||
|
Object defaultValue,
|
||||||
|
JSONSchema schema
|
||||||
|
) {
|
||||||
|
super(fieldName, fieldType, fieldClass, itemType, itemClass, ordinal, features, format, locale, defaultValue, schema, null, null, null);
|
||||||
|
|
||||||
|
this.paramName = paramName;
|
||||||
|
this.paramNameHash = Fnv.hashCode64(paramName);
|
||||||
|
this.parameter = parameter;
|
||||||
|
}
|
||||||
|
}
|
@ -445,6 +445,21 @@ public class ObjectReaderAdapter<T>
|
|||||||
return fieldReader;
|
return fieldReader;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected final void readFieldValue(long hashCode, JSONReader jsonReader, long features, Map<Long, Object> map) {
|
||||||
|
FieldReader fieldReader = getFieldReader(hashCode);
|
||||||
|
if (fieldReader == null
|
||||||
|
&& jsonReader.isSupportSmartMatch(this.features | features)) {
|
||||||
|
long hashCodeL = jsonReader.getNameHashCodeLCase();
|
||||||
|
fieldReader = getFieldReaderLCase(hashCodeL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fieldReader != null) {
|
||||||
|
map.put(hashCode, fieldReader.readFieldValue(jsonReader));
|
||||||
|
} else {
|
||||||
|
jsonReader.skipValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected final void readFieldValue(long hashCode, JSONReader jsonReader, long features, Object object) {
|
protected final void readFieldValue(long hashCode, JSONReader jsonReader, long features, Object object) {
|
||||||
FieldReader fieldReader = getFieldReader(hashCode);
|
FieldReader fieldReader = getFieldReader(hashCode);
|
||||||
if (fieldReader == null
|
if (fieldReader == null
|
||||||
|
@ -10,6 +10,7 @@ import com.alibaba.fastjson2.util.TypeUtils;
|
|||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
@ -96,6 +97,26 @@ public abstract class ObjectReaderBean<T>
|
|||||||
processExtra(jsonReader, object, 0);
|
processExtra(jsonReader, object, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void processExtra(JSONReader jsonReader, Map<Long, Object> map, long features) {
|
||||||
|
if ((jsonReader.features(this.features | features) & JSONReader.Feature.SupportSmartMatch.mask) != 0) {
|
||||||
|
String fieldName = jsonReader.getFieldName();
|
||||||
|
if (fieldName.startsWith("is")) {
|
||||||
|
String fieldName1 = fieldName.substring(2);
|
||||||
|
long hashCode64LCase = Fnv.hashCode64LCase(fieldName1);
|
||||||
|
FieldReader fieldReader = getFieldReaderLCase(hashCode64LCase);
|
||||||
|
if (fieldReader != null) {
|
||||||
|
Class fieldClass = fieldReader.fieldClass;
|
||||||
|
if (fieldClass == Boolean.class || fieldClass == boolean.class) {
|
||||||
|
map.put(fieldReader.fieldNameHash, fieldReader.readFieldValue(jsonReader));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
jsonReader.skipValue();
|
||||||
|
}
|
||||||
|
|
||||||
protected void processExtra(JSONReader jsonReader, Object object, long features) {
|
protected void processExtra(JSONReader jsonReader, Object object, long features) {
|
||||||
if ((jsonReader.features(this.features | features) & JSONReader.Feature.SupportSmartMatch.mask) != 0) {
|
if ((jsonReader.features(this.features | features) & JSONReader.Feature.SupportSmartMatch.mask) != 0) {
|
||||||
String fieldName = jsonReader.getFieldName();
|
String fieldName = jsonReader.getFieldName();
|
||||||
|
@ -1273,18 +1273,14 @@ public class ObjectReaderCreator {
|
|||||||
creatorConstructor.getParameters(),
|
creatorConstructor.getParameters(),
|
||||||
parameterNames
|
parameterNames
|
||||||
);
|
);
|
||||||
return new ObjectReaderNoneDefaultConstructor(
|
return createNoneDefaultConstructorObjectReader(
|
||||||
objectClass,
|
objectClass,
|
||||||
beanInfo.typeKey,
|
beanInfo,
|
||||||
beanInfo.typeName,
|
|
||||||
beanInfo.readerFeatures,
|
|
||||||
constructorFunction,
|
constructorFunction,
|
||||||
alternateConstructors,
|
alternateConstructors,
|
||||||
parameterNames,
|
parameterNames,
|
||||||
paramFieldReaders,
|
paramFieldReaders,
|
||||||
fieldReaderArray,
|
fieldReaderArray
|
||||||
null,
|
|
||||||
null
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1344,6 +1340,30 @@ public class ObjectReaderCreator {
|
|||||||
return objectReader;
|
return objectReader;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected <T> ObjectReaderNoneDefaultConstructor createNoneDefaultConstructorObjectReader(
|
||||||
|
Class<T> objectClass,
|
||||||
|
BeanInfo beanInfo,
|
||||||
|
Function<Map<Long, Object>, T> constructorFunction,
|
||||||
|
List<Constructor> alternateConstructors,
|
||||||
|
String[] parameterNames,
|
||||||
|
FieldReader[] paramFieldReaders,
|
||||||
|
FieldReader[] fieldReaderArray
|
||||||
|
) {
|
||||||
|
return new ObjectReaderNoneDefaultConstructor(
|
||||||
|
objectClass,
|
||||||
|
beanInfo.typeKey,
|
||||||
|
beanInfo.typeName,
|
||||||
|
beanInfo.readerFeatures,
|
||||||
|
constructorFunction,
|
||||||
|
alternateConstructors,
|
||||||
|
parameterNames,
|
||||||
|
paramFieldReaders,
|
||||||
|
fieldReaderArray,
|
||||||
|
null,
|
||||||
|
null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public <T> FieldReader[] createFieldReaders(Class<T> objectClass) {
|
public <T> FieldReader[] createFieldReaders(Class<T> objectClass) {
|
||||||
return createFieldReaders(
|
return createFieldReaders(
|
||||||
objectClass,
|
objectClass,
|
||||||
@ -2199,6 +2219,33 @@ public class ObjectReaderCreator {
|
|||||||
fieldClassResolved = fieldClass;
|
fieldClassResolved = fieldClass;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Type itemType = null;
|
||||||
|
Class itemClass = null;
|
||||||
|
if (fieldTypeResolved instanceof ParameterizedType) {
|
||||||
|
ParameterizedType parameterizedType = (ParameterizedType) fieldTypeResolved;
|
||||||
|
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
|
||||||
|
if (actualTypeArguments.length == 1) {
|
||||||
|
itemType = actualTypeArguments[0];
|
||||||
|
itemClass = TypeUtils.getClass(itemClass);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (fieldClassResolved != null && Collection.class.isAssignableFrom(fieldClassResolved) && itemType != null) {
|
||||||
|
return new FieldReaderListParam(
|
||||||
|
fieldName,
|
||||||
|
fieldTypeResolved,
|
||||||
|
paramName,
|
||||||
|
parameter,
|
||||||
|
fieldClassResolved,
|
||||||
|
itemType,
|
||||||
|
itemClass,
|
||||||
|
ordinal,
|
||||||
|
features,
|
||||||
|
format,
|
||||||
|
locale,
|
||||||
|
defaultValue,
|
||||||
|
schema);
|
||||||
|
}
|
||||||
|
|
||||||
return new FieldReaderObjectParam(
|
return new FieldReaderObjectParam(
|
||||||
fieldName,
|
fieldName,
|
||||||
fieldTypeResolved,
|
fieldTypeResolved,
|
||||||
|
@ -23,7 +23,6 @@ import java.util.function.*;
|
|||||||
|
|
||||||
import static com.alibaba.fastjson2.internal.CodeGenUtils.fieldReader;
|
import static com.alibaba.fastjson2.internal.CodeGenUtils.fieldReader;
|
||||||
import static com.alibaba.fastjson2.internal.asm.ASMUtils.*;
|
import static com.alibaba.fastjson2.internal.asm.ASMUtils.*;
|
||||||
import static com.alibaba.fastjson2.internal.asm.Opcodes.*;
|
|
||||||
import static com.alibaba.fastjson2.reader.ObjectReader.HASH_TYPE;
|
import static com.alibaba.fastjson2.reader.ObjectReader.HASH_TYPE;
|
||||||
import static com.alibaba.fastjson2.util.JDKUtils.*;
|
import static com.alibaba.fastjson2.util.JDKUtils.*;
|
||||||
|
|
||||||
@ -46,10 +45,12 @@ public class ObjectReaderCreatorASM
|
|||||||
static final String METHOD_DESC_READ_FIELD_VALUE = "(" + DESC_JSON_READER + "Ljava/lang/Object;)V";
|
static final String METHOD_DESC_READ_FIELD_VALUE = "(" + DESC_JSON_READER + "Ljava/lang/Object;)V";
|
||||||
static final String GET_FIELD_READER_UL = "(J" + DESC_JSON_READER + "J)" + DESC_FIELD_READER;
|
static final String GET_FIELD_READER_UL = "(J" + DESC_JSON_READER + "J)" + DESC_FIELD_READER;
|
||||||
static final String READ_FIELD_READER_UL = "(J" + DESC_JSON_READER + "JLjava/lang/Object;)V";
|
static final String READ_FIELD_READER_UL = "(J" + DESC_JSON_READER + "JLjava/lang/Object;)V";
|
||||||
|
static final String READ_FIELD_READER_MAP = "(J" + DESC_JSON_READER + "JLjava/util/Map;)V";
|
||||||
static final String METHOD_DESC_ADD_RESOLVE_TASK = "(" + DESC_JSON_READER + "Ljava/lang/Object;Ljava/lang/String;)V";
|
static final String METHOD_DESC_ADD_RESOLVE_TASK = "(" + DESC_JSON_READER + "Ljava/lang/Object;Ljava/lang/String;)V";
|
||||||
static final String METHOD_DESC_ADD_RESOLVE_TASK_2 = "(" + DESC_JSON_READER + "Ljava/util/List;ILjava/lang/String;)V";
|
static final String METHOD_DESC_ADD_RESOLVE_TASK_2 = "(" + DESC_JSON_READER + "Ljava/util/List;ILjava/lang/String;)V";
|
||||||
static final String METHOD_DESC_CHECK_ARRAY_AUTO_TYPE = "(" + DESC_JSON_READER + ")" + DESC_OBJECT_READER;
|
static final String METHOD_DESC_CHECK_ARRAY_AUTO_TYPE = "(" + DESC_JSON_READER + ")" + DESC_OBJECT_READER;
|
||||||
static final String METHOD_DESC_PROCESS_EXTRA = "(" + DESC_JSON_READER + "Ljava/lang/Object;J)V";
|
static final String METHOD_DESC_PROCESS_EXTRA = "(" + DESC_JSON_READER + "Ljava/lang/Object;J)V";
|
||||||
|
static final String METHOD_DESC_PROCESS_EXTRA_2 = "(" + DESC_JSON_READER + "Ljava/util/Map;J)V";
|
||||||
|
|
||||||
static final String METHOD_DESC_JSON_READER_CHECK_ARRAY_AUTO_TYPE = "(" + DESC_JSON_READER + "J)" + DESC_OBJECT_READER;
|
static final String METHOD_DESC_JSON_READER_CHECK_ARRAY_AUTO_TYPE = "(" + DESC_JSON_READER + "J)" + DESC_OBJECT_READER;
|
||||||
static final String METHOD_DESC_READ_ARRAY_MAPPING_JSONB_OBJECT0 = "(" + DESC_JSON_READER + "Ljava/lang/Object;I)V";
|
static final String METHOD_DESC_READ_ARRAY_MAPPING_JSONB_OBJECT0 = "(" + DESC_JSON_READER + "Ljava/lang/Object;I)V";
|
||||||
@ -337,6 +338,150 @@ public class ObjectReaderCreatorASM
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected <T> ObjectReaderNoneDefaultConstructor createNoneDefaultConstructorObjectReader(
|
||||||
|
Class<T> objectClass,
|
||||||
|
BeanInfo beanInfo,
|
||||||
|
Function<Map<Long, Object>, T> constructorFunction,
|
||||||
|
List<Constructor> alternateConstructors,
|
||||||
|
String[] parameterNames,
|
||||||
|
FieldReader[] paramFieldReaders,
|
||||||
|
FieldReader[] fieldReaderArray
|
||||||
|
) {
|
||||||
|
ObjectReaderNoneDefaultConstructor objectReaderAdapter = new ObjectReaderNoneDefaultConstructor(
|
||||||
|
objectClass,
|
||||||
|
beanInfo.typeKey,
|
||||||
|
beanInfo.typeName,
|
||||||
|
beanInfo.readerFeatures,
|
||||||
|
constructorFunction,
|
||||||
|
alternateConstructors,
|
||||||
|
parameterNames,
|
||||||
|
paramFieldReaders,
|
||||||
|
fieldReaderArray,
|
||||||
|
null,
|
||||||
|
null
|
||||||
|
);
|
||||||
|
|
||||||
|
boolean match = true;
|
||||||
|
|
||||||
|
if (beanInfo.autoTypeBeforeHandler != null
|
||||||
|
|| fieldReaderArray.length != 0
|
||||||
|
|| !(constructorFunction instanceof ConstructorFunction)
|
||||||
|
|| !alternateConstructors.isEmpty()
|
||||||
|
|| classLoader.isExternalClass(objectClass)
|
||||||
|
|| (beanInfo.readerFeatures & JSONReader.Feature.SupportAutoType.mask) != 0
|
||||||
|
) {
|
||||||
|
match = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (match) {
|
||||||
|
for (FieldReader fieldReader : paramFieldReaders) {
|
||||||
|
if (fieldReader.getInitReader() != null) {
|
||||||
|
match = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fieldReader.defaultValue != null || fieldReader.schema != null) {
|
||||||
|
match = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Class fieldClass = fieldReader.fieldClass;
|
||||||
|
if (fieldClass != null && (!Modifier.isPublic(fieldClass.getModifiers()) || classLoader.isExternalClass(fieldClass))) {
|
||||||
|
match = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fieldReader instanceof FieldReaderMapField
|
||||||
|
&& ((FieldReaderMapField<?>) fieldReader).arrayToMapKey != null) {
|
||||||
|
match = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fieldReader instanceof FieldReaderMapMethod
|
||||||
|
&& ((FieldReaderMapMethod<?>) fieldReader).arrayToMapKey != null) {
|
||||||
|
match = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!match) {
|
||||||
|
return objectReaderAdapter;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean externalClass = objectClass != null && classLoader.isExternalClass(objectClass);
|
||||||
|
ClassWriter cw = new ClassWriter(
|
||||||
|
(e) -> objectClass.getName().equals(e) ? objectClass : null
|
||||||
|
);
|
||||||
|
|
||||||
|
beanInfo.readerFeatures |= FieldInfo.DISABLE_REFERENCE_DETECT;
|
||||||
|
ObjectWriteContext context = new ObjectWriteContext(beanInfo, objectClass, cw, externalClass, paramFieldReaders, null);
|
||||||
|
context.objectReaderAdapter = objectReaderAdapter;
|
||||||
|
|
||||||
|
genFields(paramFieldReaders, cw, TYPE_OBJECT_READER_NONE_DEFAULT_CONSTRUCTOR);
|
||||||
|
|
||||||
|
cw.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL + Opcodes.ACC_SUPER, context.classNameType, TYPE_OBJECT_READER_NONE_DEFAULT_CONSTRUCTOR, new String[]{});
|
||||||
|
|
||||||
|
{
|
||||||
|
String MD_INIT = "(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;JLjava/util/function/Function;Ljava/util/List;[Ljava/lang/String;[Lcom/alibaba/fastjson2/reader/FieldReader;[Lcom/alibaba/fastjson2/reader/FieldReader;[Ljava/lang/Class;[Ljava/lang/String;)V";
|
||||||
|
|
||||||
|
MethodWriter mw = cw.visitMethod(
|
||||||
|
Opcodes.ACC_PUBLIC,
|
||||||
|
"<init>",
|
||||||
|
MD_INIT,
|
||||||
|
fieldReaderArray.length <= 12 ? 32 : 128);
|
||||||
|
mw.aload(THIS);
|
||||||
|
mw.aload(1); // CLASS
|
||||||
|
mw.aload(2); // TYPE_KEY
|
||||||
|
mw.aload(3); // TYPE_NAME
|
||||||
|
mw.lload(4); // FEATURES
|
||||||
|
mw.aload(6); // CREATOR
|
||||||
|
mw.aload(7); // alternateConstructors
|
||||||
|
mw.aload(8); // paramNames
|
||||||
|
mw.aload(9); // paramFieldReaders
|
||||||
|
mw.aload(10); // setterFieldReaders
|
||||||
|
mw.aload(11); // seeAlso
|
||||||
|
mw.aload(12); // seeAlsoNames
|
||||||
|
mw.invokespecial(TYPE_OBJECT_READER_NONE_DEFAULT_CONSTRUCTOR, "<init>", MD_INIT);
|
||||||
|
|
||||||
|
int FIELD_READER_ARRAY = 9;
|
||||||
|
genInitFields(paramFieldReaders, context.classNameType, true, THIS, FIELD_READER_ARRAY, mw, TYPE_OBJECT_READER_NONE_DEFAULT_CONSTRUCTOR);
|
||||||
|
|
||||||
|
mw.return_();
|
||||||
|
mw.visitMaxs(3, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
String TYPE_OBJECT = objectClass == null ? ASMUtils.TYPE_OBJECT : ASMUtils.type(objectClass);
|
||||||
|
|
||||||
|
genMethodReadObject(context, beanInfo.readerFeatures, TYPE_OBJECT, paramFieldReaders, cw, context.classNameType);
|
||||||
|
|
||||||
|
byte[] code = cw.toByteArray();
|
||||||
|
try {
|
||||||
|
Class<?> readerClass = classLoader.defineClassPublic(context.classNameFull, code, 0, code.length);
|
||||||
|
|
||||||
|
Constructor<?> constructor = readerClass.getConstructors()[0];
|
||||||
|
return (ObjectReaderNoneDefaultConstructor) constructor
|
||||||
|
.newInstance(
|
||||||
|
objectClass,
|
||||||
|
beanInfo.typeKey,
|
||||||
|
beanInfo.typeName,
|
||||||
|
beanInfo.readerFeatures,
|
||||||
|
constructorFunction,
|
||||||
|
alternateConstructors,
|
||||||
|
parameterNames,
|
||||||
|
paramFieldReaders,
|
||||||
|
fieldReaderArray,
|
||||||
|
null,
|
||||||
|
null
|
||||||
|
);
|
||||||
|
} catch (Throwable e) {
|
||||||
|
throw new JSONException(
|
||||||
|
"create objectReader error"
|
||||||
|
+ (objectClass == null ? "" : ", objectType " + objectClass.getTypeName()), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T> ObjectReader<T> createObjectReader(
|
public <T> ObjectReader<T> createObjectReader(
|
||||||
Class<T> objectClass,
|
Class<T> objectClass,
|
||||||
@ -401,34 +546,7 @@ public class ObjectReaderCreatorASM
|
|||||||
(e) -> objectClass.getName().equals(e) ? objectClass : null
|
(e) -> objectClass.getName().equals(e) ? objectClass : null
|
||||||
);
|
);
|
||||||
|
|
||||||
ObjectWriteContext context = new ObjectWriteContext(beanInfo, objectClass, cw, externalClass, fieldReaderArray);
|
ObjectWriteContext context = new ObjectWriteContext(beanInfo, objectClass, cw, externalClass, fieldReaderArray, defaultConstructor);
|
||||||
|
|
||||||
String className = "ORG_" + seed.incrementAndGet() + "_" + fieldReaderArray.length + (objectClass == null ? "" : "_" + objectClass.getSimpleName());
|
|
||||||
String classNameType;
|
|
||||||
String classNameFull;
|
|
||||||
|
|
||||||
Package pkg = ObjectReaderCreatorASM.class.getPackage();
|
|
||||||
if (pkg != null) {
|
|
||||||
String packageName = pkg.getName();
|
|
||||||
int packageNameLength = packageName.length();
|
|
||||||
int charsLength = packageNameLength + 1 + className.length();
|
|
||||||
char[] chars = new char[charsLength];
|
|
||||||
packageName.getChars(0, packageName.length(), chars, 0);
|
|
||||||
chars[packageNameLength] = '.';
|
|
||||||
className.getChars(0, className.length(), chars, packageNameLength + 1);
|
|
||||||
classNameFull = new String(chars);
|
|
||||||
|
|
||||||
chars[packageNameLength] = '/';
|
|
||||||
for (int i = 0; i < packageNameLength; ++i) {
|
|
||||||
if (chars[i] == '.') {
|
|
||||||
chars[i] = '/';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
classNameType = new String(chars);
|
|
||||||
} else {
|
|
||||||
classNameType = className;
|
|
||||||
classNameFull = className;
|
|
||||||
}
|
|
||||||
|
|
||||||
final boolean generatedFields = fieldReaderArray.length < 128;
|
final boolean generatedFields = fieldReaderArray.length < 128;
|
||||||
|
|
||||||
@ -479,7 +597,7 @@ public class ObjectReaderCreatorASM
|
|||||||
genFields(fieldReaderArray, cw, objectReaderSuper);
|
genFields(fieldReaderArray, cw, objectReaderSuper);
|
||||||
}
|
}
|
||||||
|
|
||||||
cw.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL + Opcodes.ACC_SUPER, classNameType, objectReaderSuper, new String[]{});
|
cw.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL + Opcodes.ACC_SUPER, context.classNameType, objectReaderSuper, new String[]{});
|
||||||
|
|
||||||
{
|
{
|
||||||
final int CLASS = 1, SUPPLIER = 2, FIELD_READER_ARRAY = 3;
|
final int CLASS = 1, SUPPLIER = 2, FIELD_READER_ARRAY = 3;
|
||||||
@ -504,7 +622,7 @@ public class ObjectReaderCreatorASM
|
|||||||
mw.aload(FIELD_READER_ARRAY);
|
mw.aload(FIELD_READER_ARRAY);
|
||||||
mw.invokespecial(objectReaderSuper, "<init>", METHOD_DESC_ADAPTER_INIT);
|
mw.invokespecial(objectReaderSuper, "<init>", METHOD_DESC_ADAPTER_INIT);
|
||||||
|
|
||||||
genInitFields(fieldReaderArray, classNameType, generatedFields, THIS, FIELD_READER_ARRAY, mw, objectReaderSuper);
|
genInitFields(fieldReaderArray, context.classNameType, generatedFields, THIS, FIELD_READER_ARRAY, mw, objectReaderSuper);
|
||||||
|
|
||||||
mw.return_();
|
mw.return_();
|
||||||
mw.visitMaxs(3, 3);
|
mw.visitMaxs(3, 3);
|
||||||
@ -559,16 +677,16 @@ public class ObjectReaderCreatorASM
|
|||||||
boolean disableArrayMapping = context.disableSupportArrayMapping();
|
boolean disableArrayMapping = context.disableSupportArrayMapping();
|
||||||
boolean disableJSONB = context.disableJSONB();
|
boolean disableJSONB = context.disableJSONB();
|
||||||
|
|
||||||
ObjectReaderAdapter objectReaderAdapter = new ObjectReaderAdapter(objectClass, beanInfo.typeKey, beanInfo.typeName, readerFeatures, null, supplier, null, fieldReaderArray);
|
context.objectReaderAdapter = new ObjectReaderAdapter(objectClass, beanInfo.typeKey, beanInfo.typeName, readerFeatures, null, supplier, null, fieldReaderArray);
|
||||||
|
|
||||||
if (!disableJSONB) {
|
if (!disableJSONB) {
|
||||||
genMethodReadJSONBObject(context, defaultConstructor, readerFeatures, TYPE_OBJECT, fieldReaderArray, cw, classNameType, objectReaderAdapter);
|
genMethodReadJSONBObject(context, readerFeatures, TYPE_OBJECT, fieldReaderArray, cw, context.classNameType);
|
||||||
if (!disableArrayMapping) {
|
if (!disableArrayMapping) {
|
||||||
genMethodReadJSONBObjectArrayMapping(context, defaultConstructor, readerFeatures, TYPE_OBJECT, fieldReaderArray, cw, classNameType, objectReaderAdapter);
|
genMethodReadJSONBObjectArrayMapping(context, readerFeatures, TYPE_OBJECT, fieldReaderArray, cw, context.classNameType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
genMethodReadObject(context, defaultConstructor, readerFeatures, TYPE_OBJECT, fieldReaderArray, cw, classNameType, objectReaderAdapter);
|
genMethodReadObject(context, readerFeatures, TYPE_OBJECT, fieldReaderArray, cw, context.classNameType);
|
||||||
|
|
||||||
if (objectReaderSuper == TYPE_OBJECT_READER_ADAPTER
|
if (objectReaderSuper == TYPE_OBJECT_READER_ADAPTER
|
||||||
|| objectReaderSuper == TYPE_OBJECT_READER_1
|
|| objectReaderSuper == TYPE_OBJECT_READER_1
|
||||||
@ -584,14 +702,14 @@ public class ObjectReaderCreatorASM
|
|||||||
|| objectReaderSuper == TYPE_OBJECT_READER_11
|
|| objectReaderSuper == TYPE_OBJECT_READER_11
|
||||||
|| objectReaderSuper == TYPE_OBJECT_READER_12
|
|| objectReaderSuper == TYPE_OBJECT_READER_12
|
||||||
) {
|
) {
|
||||||
genMethodGetFieldReader(fieldReaderArray, cw, classNameType, objectReaderAdapter);
|
genMethodGetFieldReader(fieldReaderArray, cw, context.classNameType, context.objectReaderAdapter);
|
||||||
genMethodGetFieldReaderLCase(fieldReaderArray, cw, classNameType, objectReaderAdapter);
|
genMethodGetFieldReaderLCase(fieldReaderArray, cw, context.classNameType, context.objectReaderAdapter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
byte[] code = cw.toByteArray();
|
byte[] code = cw.toByteArray();
|
||||||
try {
|
try {
|
||||||
Class<?> readerClass = classLoader.defineClassPublic(classNameFull, code, 0, code.length);
|
Class<?> readerClass = classLoader.defineClassPublic(context.classNameFull, code, 0, code.length);
|
||||||
|
|
||||||
Constructor<?> constructor = readerClass.getConstructors()[0];
|
Constructor<?> constructor = readerClass.getConstructors()[0];
|
||||||
return (ObjectReaderBean) constructor
|
return (ObjectReaderBean) constructor
|
||||||
@ -839,7 +957,7 @@ public class ObjectReaderCreatorASM
|
|||||||
MethodWriter mw,
|
MethodWriter mw,
|
||||||
String objectReaderSuper
|
String objectReaderSuper
|
||||||
) {
|
) {
|
||||||
if (objectReaderSuper != TYPE_OBJECT_READER_ADAPTER || !generatedFields) {
|
if ((objectReaderSuper != TYPE_OBJECT_READER_ADAPTER && objectReaderSuper != TYPE_OBJECT_READER_NONE_DEFAULT_CONSTRUCTOR) || !generatedFields) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -853,7 +971,7 @@ public class ObjectReaderCreatorASM
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void genFields(FieldReader[] fieldReaderArray, ClassWriter cw, String objectReaderSuper) {
|
private void genFields(FieldReader[] fieldReaderArray, ClassWriter cw, String objectReaderSuper) {
|
||||||
if (objectReaderSuper == TYPE_OBJECT_READER_ADAPTER) {
|
if (objectReaderSuper == TYPE_OBJECT_READER_ADAPTER || objectReaderSuper == TYPE_OBJECT_READER_NONE_DEFAULT_CONSTRUCTOR) {
|
||||||
for (int i = 0; i < fieldReaderArray.length; i++) {
|
for (int i = 0; i < fieldReaderArray.length; i++) {
|
||||||
FieldWriter fv = cw.visitField(Opcodes.ACC_PUBLIC, fieldReader(i), DESC_FIELD_READER);
|
FieldWriter fv = cw.visitField(Opcodes.ACC_PUBLIC, fieldReader(i), DESC_FIELD_READER);
|
||||||
}
|
}
|
||||||
@ -873,16 +991,16 @@ public class ObjectReaderCreatorASM
|
|||||||
|
|
||||||
private <T> void genMethodReadJSONBObject(
|
private <T> void genMethodReadJSONBObject(
|
||||||
ObjectWriteContext context,
|
ObjectWriteContext context,
|
||||||
Constructor defaultConstructor,
|
|
||||||
long readerFeatures,
|
long readerFeatures,
|
||||||
String TYPE_OBJECT,
|
String TYPE_OBJECT,
|
||||||
FieldReader[] fieldReaderArray,
|
FieldReader[] fieldReaderArray,
|
||||||
ClassWriter cw,
|
ClassWriter cw,
|
||||||
String classNameType,
|
String classNameType
|
||||||
ObjectReaderAdapter objectReaderAdapter
|
|
||||||
) {
|
) {
|
||||||
Class objectClass = context.objectClass;
|
Class objectClass = context.objectClass;
|
||||||
boolean fieldBased = (readerFeatures & JSONReader.Feature.FieldBased.mask) != 0;
|
boolean fieldBased = (readerFeatures & JSONReader.Feature.FieldBased.mask) != 0;
|
||||||
|
Constructor defaultConstructor = context.defaultConstructor;
|
||||||
|
ObjectReaderAdapter objectReaderAdapter = context.objectReaderAdapter;
|
||||||
|
|
||||||
MethodWriter mw = cw.visitMethod(Opcodes.ACC_PUBLIC,
|
MethodWriter mw = cw.visitMethod(Opcodes.ACC_PUBLIC,
|
||||||
"readJSONBObject",
|
"readJSONBObject",
|
||||||
@ -961,16 +1079,13 @@ public class ObjectReaderCreatorASM
|
|||||||
mw.visitLabel(object_);
|
mw.visitLabel(object_);
|
||||||
}
|
}
|
||||||
|
|
||||||
genCreateObject(mw, context, classNameType, TYPE_OBJECT, FEATURES, fieldBased, defaultConstructor, objectReaderAdapter.creator);
|
genCreateObject(mw, context, classNameType, TYPE_OBJECT, FEATURES, fieldBased);
|
||||||
mw.astore(OBJECT);
|
mw.astore(OBJECT);
|
||||||
|
|
||||||
mw.aload(JSON_READER);
|
mw.aload(JSON_READER);
|
||||||
mw.invokevirtual(TYPE_JSON_READER, "nextIfObjectStart", "()Z");
|
mw.invokevirtual(TYPE_JSON_READER, "nextIfObjectStart", "()Z");
|
||||||
mw.pop();
|
mw.pop();
|
||||||
|
|
||||||
genCreateObject(mw, context, classNameType, TYPE_OBJECT, FEATURES, fieldBased, defaultConstructor, objectReaderAdapter.creator);
|
|
||||||
mw.astore(OBJECT);
|
|
||||||
|
|
||||||
// for (int i = 0; i < entry_cnt; ++i) {
|
// for (int i = 0; i < entry_cnt; ++i) {
|
||||||
Label for_start_i_ = new Label(), for_end_i_ = new Label(), for_inc_i_ = new Label();
|
Label for_start_i_ = new Label(), for_end_i_ = new Label(), for_inc_i_ = new Label();
|
||||||
if (!disableAutoType) {
|
if (!disableAutoType) {
|
||||||
@ -1259,14 +1374,13 @@ public class ObjectReaderCreatorASM
|
|||||||
|
|
||||||
private <T> void genMethodReadJSONBObjectArrayMapping(
|
private <T> void genMethodReadJSONBObjectArrayMapping(
|
||||||
ObjectWriteContext context,
|
ObjectWriteContext context,
|
||||||
Constructor defaultConstructor,
|
|
||||||
long readerFeatures,
|
long readerFeatures,
|
||||||
String TYPE_OBJECT,
|
String TYPE_OBJECT,
|
||||||
FieldReader[] fieldReaderArray,
|
FieldReader[] fieldReaderArray,
|
||||||
ClassWriter cw,
|
ClassWriter cw,
|
||||||
String classNameType,
|
String classNameType
|
||||||
ObjectReaderAdapter objectReaderAdapter
|
|
||||||
) {
|
) {
|
||||||
|
Constructor defaultConstructor = context.defaultConstructor;
|
||||||
boolean fieldBased = (readerFeatures & JSONReader.Feature.FieldBased.mask) != 0;
|
boolean fieldBased = (readerFeatures & JSONReader.Feature.FieldBased.mask) != 0;
|
||||||
|
|
||||||
MethodWriter mw = cw.visitMethod(Opcodes.ACC_PUBLIC,
|
MethodWriter mw = cw.visitMethod(Opcodes.ACC_PUBLIC,
|
||||||
@ -1305,7 +1419,7 @@ public class ObjectReaderCreatorASM
|
|||||||
mw.visitLabel(notNull_);
|
mw.visitLabel(notNull_);
|
||||||
}
|
}
|
||||||
|
|
||||||
genCreateObject(mw, context, classNameType, TYPE_OBJECT, FEATURES, fieldBased, defaultConstructor, objectReaderAdapter.creator);
|
genCreateObject(mw, context, classNameType, TYPE_OBJECT, FEATURES, fieldBased);
|
||||||
mw.astore(OBJECT);
|
mw.astore(OBJECT);
|
||||||
|
|
||||||
Label fieldEnd_ = new Label(), entryCountMatch_ = new Label();
|
Label fieldEnd_ = new Label(), entryCountMatch_ = new Label();
|
||||||
@ -1386,13 +1500,11 @@ public class ObjectReaderCreatorASM
|
|||||||
|
|
||||||
private <T> void genMethodReadObject(
|
private <T> void genMethodReadObject(
|
||||||
ObjectWriteContext context,
|
ObjectWriteContext context,
|
||||||
Constructor defaultConstructor,
|
|
||||||
long readerFeatures,
|
long readerFeatures,
|
||||||
String TYPE_OBJECT,
|
String TYPE_OBJECT,
|
||||||
FieldReader[] fieldReaderArray,
|
FieldReader[] fieldReaderArray,
|
||||||
ClassWriter cw,
|
ClassWriter cw,
|
||||||
String classNameType,
|
String classNameType
|
||||||
ObjectReaderAdapter objectReaderAdapter
|
|
||||||
) {
|
) {
|
||||||
boolean fieldBased = (readerFeatures & JSONReader.Feature.FieldBased.mask) != 0;
|
boolean fieldBased = (readerFeatures & JSONReader.Feature.FieldBased.mask) != 0;
|
||||||
|
|
||||||
@ -1493,13 +1605,62 @@ public class ObjectReaderCreatorASM
|
|||||||
mw.ifeq(notNull_);
|
mw.ifeq(notNull_);
|
||||||
|
|
||||||
mw.aconst_null();
|
mw.aconst_null();
|
||||||
mw.astore(OBJECT);
|
mw.areturn();
|
||||||
mw.goto_(end_);
|
|
||||||
|
|
||||||
mw.visitLabel(notNull_);
|
mw.visitLabel(notNull_);
|
||||||
|
|
||||||
genCreateObject(mw, context, classNameType, TYPE_OBJECT, FEATURES, fieldBased, defaultConstructor, objectReaderAdapter.creator);
|
if (context.objectReaderAdapter instanceof ObjectReaderNoneDefaultConstructor) {
|
||||||
mw.astore(OBJECT);
|
Label L0 = new Label(), L1 = new Label();
|
||||||
|
mw.aload(JSON_READER);
|
||||||
|
mw.invokevirtual(TYPE_JSON_READER, "hasAutoTypeBeforeHandler", "()Z");
|
||||||
|
mw.ifne(L0);
|
||||||
|
|
||||||
|
mw.lload(FEATURES);
|
||||||
|
mw.visitLdcInsn(JSONReader.Feature.SupportSmartMatch.mask | JSONReader.Feature.SupportAutoType.mask);
|
||||||
|
mw.land();
|
||||||
|
mw.lconst_0();
|
||||||
|
mw.lcmp();
|
||||||
|
mw.ifeq(L1);
|
||||||
|
|
||||||
|
mw.visitLabel(L0);
|
||||||
|
mw.aload(THIS);
|
||||||
|
mw.aload(JSON_READER);
|
||||||
|
mw.aload(FIELD_TYPE);
|
||||||
|
mw.aload(FIELD_NAME);
|
||||||
|
mw.lload(FEATURES);
|
||||||
|
mw.invokespecial(TYPE_OBJECT_READER_NONE_DEFAULT_CONSTRUCTOR, "readObject", METHOD_DESC_READ_OBJECT);
|
||||||
|
mw.areturn();
|
||||||
|
|
||||||
|
mw.visitLabel(L1);
|
||||||
|
|
||||||
|
for (FieldReader fieldReader : fieldReaderArray) {
|
||||||
|
Class fieldClass = fieldReader.fieldClass;
|
||||||
|
int var = mwc.var(fieldReader);
|
||||||
|
if (fieldClass == byte.class || fieldClass == short.class || fieldClass == int.class || fieldClass == boolean.class || fieldClass == char.class) {
|
||||||
|
mw.iconst_0();
|
||||||
|
mw.istore(var);
|
||||||
|
} else if (fieldClass == long.class) {
|
||||||
|
mw.lconst_0();
|
||||||
|
mw.lstore(var);
|
||||||
|
} else if (fieldClass == float.class) {
|
||||||
|
mw.iconst_0();
|
||||||
|
mw.i2f();
|
||||||
|
mw.fstore(var);
|
||||||
|
} else if (fieldClass == double.class) {
|
||||||
|
mw.iconst_0();
|
||||||
|
mw.i2d();
|
||||||
|
mw.dstore(var);
|
||||||
|
} else {
|
||||||
|
mw.aconst_null();
|
||||||
|
mw.astore(var);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mw.aconst_null();
|
||||||
|
mw.astore(mwc.var("map"));
|
||||||
|
} else {
|
||||||
|
genCreateObject(mw, context, classNameType, TYPE_OBJECT, FEATURES, fieldBased);
|
||||||
|
mw.astore(OBJECT);
|
||||||
|
}
|
||||||
|
|
||||||
// for (int i = 0; i < entry_cnt; ++i) {
|
// for (int i = 0; i < entry_cnt; ++i) {
|
||||||
Label for_start_i_ = new Label(), for_end_i_ = new Label(), for_inc_i_ = new Label();
|
Label for_start_i_ = new Label(), for_end_i_ = new Label(), for_inc_i_ = new Label();
|
||||||
@ -1556,17 +1717,24 @@ public class ObjectReaderCreatorASM
|
|||||||
|
|
||||||
mw.visitLabel(hashCode64Start);
|
mw.visitLabel(hashCode64Start);
|
||||||
|
|
||||||
mw.aload(JSON_READER);
|
if (switchGen && context.objectReaderAdapter instanceof ObjectReaderNoneDefaultConstructor) {
|
||||||
mw.invokevirtual(TYPE_JSON_READER, "readFieldNameHashCode", "()J");
|
mw.aload(JSON_READER);
|
||||||
mw.dup2();
|
mw.invokevirtual(TYPE_JSON_READER, "skipName", "()Z");
|
||||||
mw.lstore(HASH_CODE64);
|
mw.pop();
|
||||||
mw.visitLdcInsn(-1L);
|
} else {
|
||||||
mw.lcmp();
|
mw.aload(JSON_READER);
|
||||||
mw.ifeq(for_end_i_);
|
mw.invokevirtual(TYPE_JSON_READER, "readFieldNameHashCode", "()J");
|
||||||
|
mw.dup2();
|
||||||
|
mw.lstore(HASH_CODE64);
|
||||||
|
|
||||||
|
mw.visitLdcInsn(-1L);
|
||||||
|
mw.lcmp();
|
||||||
|
mw.ifeq(for_end_i_);
|
||||||
|
}
|
||||||
|
|
||||||
mw.visitLabel(hashCode64End);
|
mw.visitLabel(hashCode64End);
|
||||||
|
|
||||||
if (!disableAutoType) {
|
if (!disableAutoType && !(context.objectReaderAdapter instanceof ObjectReaderNoneDefaultConstructor)) {
|
||||||
Label noneAutoType_ = new Label();
|
Label noneAutoType_ = new Label();
|
||||||
|
|
||||||
// if (i != 0 && hash == HASH_TYPE && jsonReader.isSupportAutoType())
|
// if (i != 0 && hash == HASH_TYPE && jsonReader.isSupportAutoType())
|
||||||
@ -1598,19 +1766,24 @@ public class ObjectReaderCreatorASM
|
|||||||
|
|
||||||
// continue
|
// continue
|
||||||
if (switchGen) {
|
if (switchGen) {
|
||||||
mw.aload(THIS);
|
if (context.objectReaderAdapter instanceof ObjectReaderNoneDefaultConstructor) {
|
||||||
mw.lload(HASH_CODE64);
|
mw.aload(JSON_READER);
|
||||||
mw.aload(JSON_READER);
|
mw.invokevirtual(TYPE_JSON_READER, "skipValue", "()V");
|
||||||
mw.lload(FEATURES);
|
} else {
|
||||||
mw.aload(OBJECT);
|
mw.aload(THIS);
|
||||||
mw.invokevirtual(TYPE_OBJECT_READER_ADAPTER, "readFieldValue", READ_FIELD_READER_UL);
|
mw.lload(HASH_CODE64);
|
||||||
|
mw.aload(JSON_READER);
|
||||||
|
mw.lload(FEATURES);
|
||||||
|
mw.aload(OBJECT);
|
||||||
|
mw.invokevirtual(TYPE_OBJECT_READER_ADAPTER, "readFieldValue", READ_FIELD_READER_UL);
|
||||||
|
}
|
||||||
mw.goto_(for_inc_i_); // continue
|
mw.goto_(for_inc_i_); // continue
|
||||||
} else if (fieldReaderArray.length > 6) {
|
} else if (fieldReaderArray.length > 6) {
|
||||||
// use switch
|
// use switch
|
||||||
Map<Integer, List<Long>> map = new TreeMap();
|
Map<Integer, List<Long>> map = new TreeMap();
|
||||||
|
|
||||||
for (int i = 0; i < objectReaderAdapter.hashCodes.length; i++) {
|
for (int i = 0; i < context.objectReaderAdapter.hashCodes.length; i++) {
|
||||||
long hashCode64 = objectReaderAdapter.hashCodes[i];
|
long hashCode64 = context.objectReaderAdapter.hashCodes[i];
|
||||||
int hashCode32 = (int) (hashCode64 ^ (hashCode64 >>> 32));
|
int hashCode32 = (int) (hashCode64 ^ (hashCode64 >>> 32));
|
||||||
List<Long> hashCode64List = map.computeIfAbsent(hashCode32, k -> new ArrayList<>());
|
List<Long> hashCode64List = map.computeIfAbsent(hashCode32, k -> new ArrayList<>());
|
||||||
hashCode64List.add(hashCode64);
|
hashCode64List.add(hashCode64);
|
||||||
@ -1656,8 +1829,8 @@ public class ObjectReaderCreatorASM
|
|||||||
mw.lcmp();
|
mw.lcmp();
|
||||||
mw.ifne(next);
|
mw.ifne(next);
|
||||||
|
|
||||||
int m = Arrays.binarySearch(objectReaderAdapter.hashCodes, hashCode64);
|
int m = Arrays.binarySearch(context.objectReaderAdapter.hashCodes, hashCode64);
|
||||||
int index = objectReaderAdapter.mapping[m];
|
int index = context.objectReaderAdapter.mapping[m];
|
||||||
|
|
||||||
FieldReader fieldReader = fieldReaderArray[index];
|
FieldReader fieldReader = fieldReaderArray[index];
|
||||||
|
|
||||||
@ -1824,11 +1997,19 @@ public class ObjectReaderCreatorASM
|
|||||||
mw.visitLabel(processExtra_);
|
mw.visitLabel(processExtra_);
|
||||||
}
|
}
|
||||||
if (!switchGen) {
|
if (!switchGen) {
|
||||||
mw.aload(THIS);
|
if (context.objectReaderAdapter instanceof ObjectReaderNoneDefaultConstructor) {
|
||||||
mw.aload(JSON_READER);
|
mw.aload(THIS);
|
||||||
mw.aload(OBJECT);
|
mw.aload(JSON_READER);
|
||||||
mw.lload(FEATURES);
|
mw.aload(mwc.var("map"));
|
||||||
mw.invokevirtual(TYPE_OBJECT_READER_ADAPTER, "processExtra", METHOD_DESC_PROCESS_EXTRA);
|
mw.lload(FEATURES);
|
||||||
|
mw.invokevirtual(TYPE_OBJECT_READER_ADAPTER, "processExtra", METHOD_DESC_PROCESS_EXTRA_2);
|
||||||
|
} else {
|
||||||
|
mw.aload(THIS);
|
||||||
|
mw.aload(JSON_READER);
|
||||||
|
mw.aload(OBJECT);
|
||||||
|
mw.lload(FEATURES);
|
||||||
|
mw.invokevirtual(TYPE_OBJECT_READER_ADAPTER, "processExtra", METHOD_DESC_PROCESS_EXTRA);
|
||||||
|
}
|
||||||
mw.goto_(for_inc_i_); // continue
|
mw.goto_(for_inc_i_); // continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1842,7 +2023,60 @@ public class ObjectReaderCreatorASM
|
|||||||
|
|
||||||
mw.visitLabel(end_);
|
mw.visitLabel(end_);
|
||||||
|
|
||||||
mw.aload(OBJECT);
|
if (context.objectReaderAdapter instanceof ObjectReaderNoneDefaultConstructor) {
|
||||||
|
ObjectReaderNoneDefaultConstructor objectReaderNoneDefaultConstructor = (ObjectReaderNoneDefaultConstructor) context.objectReaderAdapter;
|
||||||
|
boolean constructDirect = true;
|
||||||
|
if (classLoader.isExternalClass(context.objectClass)
|
||||||
|
|| (objectReaderNoneDefaultConstructor.constructor != null && !Modifier.isPublic(objectReaderNoneDefaultConstructor.constructor.getModifiers()))
|
||||||
|
|| (context.objectClass != null && !Modifier.isPublic(context.objectClass.getModifiers()))
|
||||||
|
) {
|
||||||
|
constructDirect = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (constructDirect) {
|
||||||
|
mw.new_(TYPE_OBJECT);
|
||||||
|
mw.dup();
|
||||||
|
StringBuilder buf = new StringBuilder().append("(");
|
||||||
|
for (FieldReader fieldReader : fieldReaderArray) {
|
||||||
|
mw.loadLocal(fieldReader.fieldClass, mwc.var(fieldReader));
|
||||||
|
buf.append(ASMUtils.desc(fieldReader.fieldClass));
|
||||||
|
}
|
||||||
|
buf.append(")V");
|
||||||
|
mw.invokespecial(TYPE_OBJECT, "<init>", buf.toString());
|
||||||
|
} else {
|
||||||
|
mw.aload(THIS);
|
||||||
|
mw.iconst_n(fieldReaderArray.length);
|
||||||
|
mw.anewArray("java/lang/Object");
|
||||||
|
for (int i = 0; i < fieldReaderArray.length; i++) {
|
||||||
|
FieldReader fieldReader = fieldReaderArray[i];
|
||||||
|
mw.dup();
|
||||||
|
mw.iconst_n(i);
|
||||||
|
mw.loadLocal(fieldReader.fieldClass, mwc.var(fieldReader));
|
||||||
|
if (fieldReader.fieldClass == int.class) {
|
||||||
|
mw.invokestatic("java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;");
|
||||||
|
} else if (fieldReader.fieldClass == long.class) {
|
||||||
|
mw.invokestatic("java/lang/Long", "valueOf", "(J)Ljava/lang/Long;");
|
||||||
|
} else if (fieldReader.fieldClass == float.class) {
|
||||||
|
mw.invokestatic("java/lang/Float", "valueOf", "(F)Ljava/lang/Float;");
|
||||||
|
} else if (fieldReader.fieldClass == double.class) {
|
||||||
|
mw.invokestatic("java/lang/Double", "valueOf", "(D)Ljava/lang/Double;");
|
||||||
|
} else if (fieldReader.fieldClass == boolean.class) {
|
||||||
|
mw.invokestatic("java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;");
|
||||||
|
} else if (fieldReader.fieldClass == short.class) {
|
||||||
|
mw.invokestatic("java/lang/Short", "valueOf", "(S)Ljava/lang/Short;");
|
||||||
|
} else if (fieldReader.fieldClass == byte.class) {
|
||||||
|
mw.invokestatic("java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;");
|
||||||
|
} else if (fieldReader.fieldClass == char.class) {
|
||||||
|
mw.invokestatic("java/lang/Character", "valueOf", "(C)Ljava/lang/Character;");
|
||||||
|
}
|
||||||
|
mw.aastore();
|
||||||
|
}
|
||||||
|
mw.invokevirtual(TYPE_OBJECT_READER_NONE_DEFAULT_CONSTRUCTOR, "createInstance", "([Ljava/lang/Object;)Ljava/lang/Object;");
|
||||||
|
}
|
||||||
|
mw.areturn();
|
||||||
|
} else {
|
||||||
|
mw.aload(OBJECT);
|
||||||
|
}
|
||||||
mw.areturn();
|
mw.areturn();
|
||||||
|
|
||||||
mw.visitMaxs(5, 10);
|
mw.visitMaxs(5, 10);
|
||||||
@ -2661,10 +2895,10 @@ public class ObjectReaderCreatorASM
|
|||||||
String classNameType,
|
String classNameType,
|
||||||
String TYPE_OBJECT,
|
String TYPE_OBJECT,
|
||||||
int FEATURES,
|
int FEATURES,
|
||||||
boolean fieldBased,
|
boolean fieldBased
|
||||||
Constructor defaultConstructor,
|
|
||||||
Supplier creator
|
|
||||||
) {
|
) {
|
||||||
|
Constructor defaultConstructor = context.defaultConstructor;
|
||||||
|
Supplier creator = context.objectReaderAdapter.creator;
|
||||||
Class objectClass = context.objectClass;
|
Class objectClass = context.objectClass;
|
||||||
final int JSON_READER = 1;
|
final int JSON_READER = 1;
|
||||||
|
|
||||||
@ -2687,7 +2921,7 @@ public class ObjectReaderCreatorASM
|
|||||||
mw.checkcast(TYPE_OBJECT);
|
mw.checkcast(TYPE_OBJECT);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
newObject(mw, TYPE_OBJECT, defaultConstructor);
|
newObject(mw, TYPE_OBJECT, context.defaultConstructor);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (context.hasStringField) {
|
if (context.hasStringField) {
|
||||||
@ -2755,7 +2989,9 @@ public class ObjectReaderCreatorASM
|
|||||||
String TYPE_FIELD_CLASS = ASMUtils.type(fieldClass);
|
String TYPE_FIELD_CLASS = ASMUtils.type(fieldClass);
|
||||||
String DESC_FIELD_CLASS = ASMUtils.desc(fieldClass);
|
String DESC_FIELD_CLASS = ASMUtils.desc(fieldClass);
|
||||||
|
|
||||||
mw.aload(OBJECT);
|
if (!(context.objectReaderAdapter instanceof ObjectReaderNoneDefaultConstructor)) {
|
||||||
|
mw.aload(OBJECT);
|
||||||
|
}
|
||||||
int fieldModifier = 0;
|
int fieldModifier = 0;
|
||||||
if ((fieldBased || method == null) && field != null) {
|
if ((fieldBased || method == null) && field != null) {
|
||||||
fieldModifier = field.getModifiers();
|
fieldModifier = field.getModifiers();
|
||||||
@ -2919,7 +3155,9 @@ public class ObjectReaderCreatorASM
|
|||||||
|
|
||||||
mw.aload(JSON_READER);
|
mw.aload(JSON_READER);
|
||||||
mw.invokevirtual(TYPE_JSON_READER, "skipValue", "()V");
|
mw.invokevirtual(TYPE_JSON_READER, "skipValue", "()V");
|
||||||
mw.pop();
|
if (!(context.objectReaderAdapter instanceof ObjectReaderNoneDefaultConstructor)) {
|
||||||
|
mw.pop();
|
||||||
|
}
|
||||||
mw.goto_(endSet_);
|
mw.goto_(endSet_);
|
||||||
|
|
||||||
mw.visitLabel(endIgnoreCheck_);
|
mw.visitLabel(endIgnoreCheck_);
|
||||||
@ -2962,7 +3200,8 @@ public class ObjectReaderCreatorASM
|
|||||||
fieldFeatures,
|
fieldFeatures,
|
||||||
itemType,
|
itemType,
|
||||||
TYPE_FIELD_CLASS,
|
TYPE_FIELD_CLASS,
|
||||||
context
|
context,
|
||||||
|
fieldBased
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
final String FIELD_OBJECT_READER = fieldObjectReader(i);
|
final String FIELD_OBJECT_READER = fieldObjectReader(i);
|
||||||
@ -3131,6 +3370,11 @@ public class ObjectReaderCreatorASM
|
|||||||
mw.visitVarInsn(LOAD, FIELD_VALUE);
|
mw.visitVarInsn(LOAD, FIELD_VALUE);
|
||||||
mw.invokevirtual("sun/misc/Unsafe", methodName, methodDes);
|
mw.invokevirtual("sun/misc/Unsafe", methodName, methodDes);
|
||||||
}
|
}
|
||||||
|
} else if (context.objectReaderAdapter instanceof ObjectReaderNoneDefaultConstructor) {
|
||||||
|
if (!fieldClass.isPrimitive()) {
|
||||||
|
mw.checkcast(ASMUtils.type(fieldClass));
|
||||||
|
}
|
||||||
|
mw.storeLocal(fieldClass, mwc.var(fieldReader));
|
||||||
} else {
|
} else {
|
||||||
boolean invokeFieldReaderAccept = context.externalClass || method == null || !context.publicClass;
|
boolean invokeFieldReaderAccept = context.externalClass || method == null || !context.publicClass;
|
||||||
|
|
||||||
@ -3526,7 +3770,8 @@ public class ObjectReaderCreatorASM
|
|||||||
long fieldFeatures,
|
long fieldFeatures,
|
||||||
Type itemType,
|
Type itemType,
|
||||||
String TYPE_FIELD_CLASS,
|
String TYPE_FIELD_CLASS,
|
||||||
ObjectWriteContext context
|
ObjectWriteContext context,
|
||||||
|
boolean fieldBased
|
||||||
) {
|
) {
|
||||||
if (itemType == null) {
|
if (itemType == null) {
|
||||||
itemType = Object.class;
|
itemType = Object.class;
|
||||||
@ -3536,7 +3781,12 @@ public class ObjectReaderCreatorASM
|
|||||||
String ITEM_OBJECT_READER = fieldItemObjectReader(i);
|
String ITEM_OBJECT_READER = fieldItemObjectReader(i);
|
||||||
MethodWriter mw = mwc.mw;
|
MethodWriter mw = mwc.mw;
|
||||||
|
|
||||||
Integer LIST = mwc.var(fieldClass);
|
int LIST;
|
||||||
|
if (context.objectReaderAdapter instanceof ObjectReaderNoneDefaultConstructor) {
|
||||||
|
LIST = mwc.var(fieldReader);
|
||||||
|
} else {
|
||||||
|
LIST = mwc.var(fieldClass);
|
||||||
|
}
|
||||||
Integer AUTO_TYPE_OBJECT_READER = mwc.var(ObjectReader.class);
|
Integer AUTO_TYPE_OBJECT_READER = mwc.var(ObjectReader.class);
|
||||||
|
|
||||||
String LIST_TYPE = fieldClass.isInterface() ? "java/util/ArrayList" : TYPE_FIELD_CLASS;
|
String LIST_TYPE = fieldClass.isInterface() ? "java/util/ArrayList" : TYPE_FIELD_CLASS;
|
||||||
@ -3833,13 +4083,18 @@ public class ObjectReaderCreatorASM
|
|||||||
final boolean hasStringField;
|
final boolean hasStringField;
|
||||||
final int fieldNameLengthMin;
|
final int fieldNameLengthMin;
|
||||||
final int fieldNameLengthMax;
|
final int fieldNameLengthMax;
|
||||||
|
final String classNameType;
|
||||||
|
final String classNameFull;
|
||||||
|
final Constructor defaultConstructor;
|
||||||
|
ObjectReaderAdapter objectReaderAdapter;
|
||||||
|
|
||||||
public ObjectWriteContext(
|
public ObjectWriteContext(
|
||||||
BeanInfo beanInfo,
|
BeanInfo beanInfo,
|
||||||
Class objectClass,
|
Class objectClass,
|
||||||
ClassWriter cw,
|
ClassWriter cw,
|
||||||
boolean externalClass,
|
boolean externalClass,
|
||||||
FieldReader[] fieldReaders
|
FieldReader[] fieldReaders,
|
||||||
|
Constructor defaultConstructor
|
||||||
) {
|
) {
|
||||||
this.beanInfo = beanInfo;
|
this.beanInfo = beanInfo;
|
||||||
this.objectClass = objectClass;
|
this.objectClass = objectClass;
|
||||||
@ -3847,6 +4102,7 @@ public class ObjectReaderCreatorASM
|
|||||||
this.publicClass = objectClass == null || Modifier.isPublic(objectClass.getModifiers());
|
this.publicClass = objectClass == null || Modifier.isPublic(objectClass.getModifiers());
|
||||||
this.externalClass = externalClass;
|
this.externalClass = externalClass;
|
||||||
this.fieldReaders = fieldReaders;
|
this.fieldReaders = fieldReaders;
|
||||||
|
this.defaultConstructor = defaultConstructor;
|
||||||
|
|
||||||
int fieldNameLengthMin = 0, fieldNameLengthMax = 0;
|
int fieldNameLengthMin = 0, fieldNameLengthMax = 0;
|
||||||
boolean hasStringField = false;
|
boolean hasStringField = false;
|
||||||
@ -3876,6 +4132,31 @@ public class ObjectReaderCreatorASM
|
|||||||
this.hasStringField = hasStringField;
|
this.hasStringField = hasStringField;
|
||||||
this.fieldNameLengthMin = fieldNameLengthMin;
|
this.fieldNameLengthMin = fieldNameLengthMin;
|
||||||
this.fieldNameLengthMax = fieldNameLengthMax;
|
this.fieldNameLengthMax = fieldNameLengthMax;
|
||||||
|
|
||||||
|
String className = "ORG_" + seed.incrementAndGet() + "_" + fieldReaders.length + (objectClass == null ? "" : "_" + objectClass.getSimpleName());
|
||||||
|
|
||||||
|
Package pkg = ObjectReaderCreatorASM.class.getPackage();
|
||||||
|
if (pkg != null) {
|
||||||
|
String packageName = pkg.getName();
|
||||||
|
int packageNameLength = packageName.length();
|
||||||
|
int charsLength = packageNameLength + 1 + className.length();
|
||||||
|
char[] chars = new char[charsLength];
|
||||||
|
packageName.getChars(0, packageName.length(), chars, 0);
|
||||||
|
chars[packageNameLength] = '.';
|
||||||
|
className.getChars(0, className.length(), chars, packageNameLength + 1);
|
||||||
|
classNameFull = new String(chars);
|
||||||
|
|
||||||
|
chars[packageNameLength] = '/';
|
||||||
|
for (int i = 0; i < packageNameLength; ++i) {
|
||||||
|
if (chars[i] == '.') {
|
||||||
|
chars[i] = '/';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
classNameType = new String(chars);
|
||||||
|
} else {
|
||||||
|
classNameType = className;
|
||||||
|
classNameFull = className;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean disableSupportArrayMapping() {
|
public boolean disableSupportArrayMapping() {
|
||||||
@ -4296,6 +4577,24 @@ public class ObjectReaderCreatorASM
|
|||||||
return var;
|
return var;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int var(FieldReader fieldReader) {
|
||||||
|
return var("_param_" + fieldReader.fieldName, fieldReader.fieldClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
int var(String name, Class type) {
|
||||||
|
Integer var = variants.get(name);
|
||||||
|
if (var == null) {
|
||||||
|
var = maxVariant;
|
||||||
|
variants.put(name, var);
|
||||||
|
if (type == long.class || type == double.class) {
|
||||||
|
maxVariant += 2;
|
||||||
|
} else {
|
||||||
|
maxVariant += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return var;
|
||||||
|
}
|
||||||
|
|
||||||
int var2(Object key) {
|
int var2(Object key) {
|
||||||
Integer var = variants.get(key);
|
Integer var = variants.get(key);
|
||||||
if (var == null) {
|
if (var == null) {
|
||||||
|
@ -5,6 +5,7 @@ import com.alibaba.fastjson2.util.Fnv;
|
|||||||
import com.alibaba.fastjson2.util.TypeUtils;
|
import com.alibaba.fastjson2.util.TypeUtils;
|
||||||
|
|
||||||
import java.lang.reflect.Constructor;
|
import java.lang.reflect.Constructor;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
@ -16,8 +17,9 @@ public class ObjectReaderNoneDefaultConstructor<T>
|
|||||||
extends ObjectReaderAdapter<T> {
|
extends ObjectReaderAdapter<T> {
|
||||||
final String[] paramNames;
|
final String[] paramNames;
|
||||||
final FieldReader[] setterFieldReaders;
|
final FieldReader[] setterFieldReaders;
|
||||||
private final Function<Map<Long, Object>, T> creator;
|
final Function<Map<Long, Object>, T> creatorFunction;
|
||||||
final Map<Long, FieldReader> paramFieldReaderMap;
|
final Map<Long, FieldReader> paramFieldReaderMap;
|
||||||
|
final Constructor noneDefaultConstructor;
|
||||||
|
|
||||||
public ObjectReaderNoneDefaultConstructor(
|
public ObjectReaderNoneDefaultConstructor(
|
||||||
Class objectClass,
|
Class objectClass,
|
||||||
@ -47,12 +49,17 @@ public class ObjectReaderNoneDefaultConstructor<T>
|
|||||||
);
|
);
|
||||||
|
|
||||||
this.paramNames = paramNames;
|
this.paramNames = paramNames;
|
||||||
this.creator = creator;
|
this.creatorFunction = creator;
|
||||||
this.setterFieldReaders = setterFieldReaders;
|
this.setterFieldReaders = setterFieldReaders;
|
||||||
this.paramFieldReaderMap = new HashMap<>();
|
this.paramFieldReaderMap = new HashMap<>();
|
||||||
for (FieldReader paramFieldReader : paramFieldReaders) {
|
for (FieldReader paramFieldReader : paramFieldReaders) {
|
||||||
paramFieldReaderMap.put(paramFieldReader.fieldNameHash, paramFieldReader);
|
paramFieldReaderMap.put(paramFieldReader.fieldNameHash, paramFieldReader);
|
||||||
}
|
}
|
||||||
|
if (creatorFunction instanceof ConstructorFunction) {
|
||||||
|
noneDefaultConstructor = ((ConstructorFunction) creator).constructor;
|
||||||
|
} else {
|
||||||
|
noneDefaultConstructor = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static FieldReader[] concat(FieldReader[] a, FieldReader[] b) {
|
static FieldReader[] concat(FieldReader[] a, FieldReader[] b) {
|
||||||
@ -65,9 +72,14 @@ public class ObjectReaderNoneDefaultConstructor<T>
|
|||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
|
public Collection<FieldReader> getParameterFieldReaders() {
|
||||||
|
return paramFieldReaderMap.values();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public T createInstanceNoneDefaultConstructor(Map<Long, Object> values) {
|
public T createInstanceNoneDefaultConstructor(Map<Long, Object> values) {
|
||||||
return creator.apply(values);
|
return creatorFunction.apply(values);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -342,7 +354,7 @@ public class ObjectReaderNoneDefaultConstructor<T>
|
|||||||
}
|
}
|
||||||
|
|
||||||
Map<Long, Object> argsMap = valueMap == null ? Collections.emptyMap() : valueMap;
|
Map<Long, Object> argsMap = valueMap == null ? Collections.emptyMap() : valueMap;
|
||||||
T object = creator.apply(argsMap);
|
T object = creatorFunction.apply(argsMap);
|
||||||
|
|
||||||
if (setterFieldReaders != null && valueMap != null) {
|
if (setterFieldReaders != null && valueMap != null) {
|
||||||
for (int i = 0; i < setterFieldReaders.length; i++) {
|
for (int i = 0; i < setterFieldReaders.length; i++) {
|
||||||
@ -521,4 +533,13 @@ public class ObjectReaderNoneDefaultConstructor<T>
|
|||||||
|
|
||||||
return object;
|
return object;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public T createInstance(Object[] args) {
|
||||||
|
try {
|
||||||
|
return (T) noneDefaultConstructor.newInstance(args);
|
||||||
|
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException |
|
||||||
|
InvocationTargetException e) {
|
||||||
|
throw new JSONException("invoke constructor error, " + constructor, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1356,18 +1356,50 @@ public class IOUtils {
|
|||||||
return UNSAFE.getInt(buf, ARRAY_BYTE_BASE_OFFSET + pos) == ALSE;
|
return UNSAFE.getInt(buf, ARRAY_BYTE_BASE_OFFSET + pos) == ALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean notALSE(byte[] buf, int pos) {
|
||||||
|
return UNSAFE.getInt(buf, ARRAY_BYTE_BASE_OFFSET + pos) != ALSE;
|
||||||
|
}
|
||||||
|
|
||||||
public static boolean isALSE(char[] buf, int pos) {
|
public static boolean isALSE(char[] buf, int pos) {
|
||||||
return getLongUnaligned(buf, pos) == ALSE_64;
|
return getLongUnaligned(buf, pos) == ALSE_64;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean notALSE(char[] buf, int pos) {
|
||||||
|
return getLongUnaligned(buf, pos) != ALSE_64;
|
||||||
|
}
|
||||||
|
|
||||||
public static boolean isNULL(byte[] buf, int pos) {
|
public static boolean isNULL(byte[] buf, int pos) {
|
||||||
return UNSAFE.getInt(buf, ARRAY_BYTE_BASE_OFFSET + pos) == NULL_32;
|
return UNSAFE.getInt(buf, ARRAY_BYTE_BASE_OFFSET + pos) == NULL_32;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean notNULL(byte[] buf, int pos) {
|
||||||
|
return UNSAFE.getInt(buf, ARRAY_BYTE_BASE_OFFSET + pos) != NULL_32;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isTRUE(byte[] buf, int pos) {
|
||||||
|
return UNSAFE.getInt(buf, ARRAY_BYTE_BASE_OFFSET + pos) == TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean notTRUE(byte[] buf, int pos) {
|
||||||
|
return UNSAFE.getInt(buf, ARRAY_BYTE_BASE_OFFSET + pos) != TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isTRUE(char[] buf, int pos) {
|
||||||
|
return UNSAFE.getLong(buf, ARRAY_BYTE_BASE_OFFSET + ((long) pos << 1)) == TRUE_64;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean notTRUE(char[] buf, int pos) {
|
||||||
|
return UNSAFE.getLong(buf, ARRAY_BYTE_BASE_OFFSET + ((long) pos << 1)) != TRUE_64;
|
||||||
|
}
|
||||||
|
|
||||||
public static boolean isNULL(char[] buf, int pos) {
|
public static boolean isNULL(char[] buf, int pos) {
|
||||||
return getLongUnaligned(buf, pos) == NULL_64;
|
return getLongUnaligned(buf, pos) == NULL_64;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean notNULL(char[] buf, int pos) {
|
||||||
|
return getLongUnaligned(buf, pos) != NULL_64;
|
||||||
|
}
|
||||||
|
|
||||||
public static void putNULL(byte[] buf, int pos) {
|
public static void putNULL(byte[] buf, int pos) {
|
||||||
UNSAFE.putInt(buf, ARRAY_CHAR_BASE_OFFSET + pos, NULL_32);
|
UNSAFE.putInt(buf, ARRAY_CHAR_BASE_OFFSET + pos, NULL_32);
|
||||||
}
|
}
|
||||||
|
9
pom.xml
9
pom.xml
@ -1019,6 +1019,15 @@
|
|||||||
<module>test-jdk17</module>
|
<module>test-jdk17</module>
|
||||||
</modules>
|
</modules>
|
||||||
</profile>
|
</profile>
|
||||||
|
<profile>
|
||||||
|
<id>enable-for-jdk21+</id>
|
||||||
|
<activation>
|
||||||
|
<jdk>[21,)</jdk>
|
||||||
|
</activation>
|
||||||
|
<modules>
|
||||||
|
<module>benchmark_21</module>
|
||||||
|
</modules>
|
||||||
|
</profile>
|
||||||
<profile>
|
<profile>
|
||||||
<id>enable-codegen</id>
|
<id>enable-codegen</id>
|
||||||
<activation>
|
<activation>
|
||||||
|
@ -28,5 +28,9 @@
|
|||||||
<artifactId>fastjson2</artifactId>
|
<artifactId>fastjson2</artifactId>
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>commons-io</groupId>
|
||||||
|
<artifactId>commons-io</artifactId>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</project>
|
</project>
|
||||||
|
@ -2,6 +2,10 @@ package com.alibaba.fastjson2;
|
|||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
public class RecordTest {
|
public class RecordTest {
|
||||||
@ -14,7 +18,49 @@ public class RecordTest {
|
|||||||
|
|
||||||
JSONObject object = JSON.parseObject(str);
|
JSONObject object = JSON.parseObject(str);
|
||||||
assertEquals(item.value, object.get("value"));
|
assertEquals(item.value, object.get("value"));
|
||||||
|
|
||||||
|
Item item2 = JSON.parseObject(str, Item.class);
|
||||||
|
assertEquals(item.value, item2.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
record Item(int value) { }
|
public record Item(int value) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test1() {
|
||||||
|
Item1 item = new Item1(Arrays.asList("abc"));
|
||||||
|
String str = JSON.toJSONString(item);
|
||||||
|
Item1 item2 = JSON.parseObject(str, Item1.class);
|
||||||
|
assertEquals(item.value, item2.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public record Item1(List<String> value) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test2() {
|
||||||
|
Item2 item = new Item2(Arrays.asList(new Item(123)));
|
||||||
|
String str = JSON.toJSONString(item);
|
||||||
|
Item2 item2 = JSON.parseObject(str, Item2.class);
|
||||||
|
assertEquals(item.value.size(), item2.value.size());
|
||||||
|
assertEquals(item.value.get(0).value, item2.value.get(0).value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public record Item2(List<Item> value) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test3() {
|
||||||
|
Item3 item = new Item3(new User(true, "abc"));
|
||||||
|
String str = JSON.toJSONString(item);
|
||||||
|
Item3 item2 = JSON.parseObject(str, Item3.class);
|
||||||
|
assertEquals(item.user.default_profile, item2.user.default_profile);
|
||||||
|
assertEquals(item.user.screen_name, item2.user.screen_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public record User(boolean default_profile, String screen_name) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public record Item3(User user) implements Serializable {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user