Compare commits
10 Commits
main
...
optim_writ
Author | SHA1 | Date | |
---|---|---|---|
![]() |
f5be616daa | ||
![]() |
dc096e496c | ||
![]() |
6ca3abd326 | ||
![]() |
b9a6dbd116 | ||
![]() |
938fa270d0 | ||
![]() |
28c2e92394 | ||
![]() |
0c3e07ab31 | ||
![]() |
ed393bbb5e | ||
![]() |
e2745af3b7 | ||
![]() |
17cca863a1 |
@ -37,11 +37,11 @@ public class LambdaGenerator {
|
||||
"()V",
|
||||
64
|
||||
);
|
||||
mw.visitVarInsn(Opcodes.ALOAD, THIS);
|
||||
mw.aload(THIS);
|
||||
|
||||
mw.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
|
||||
mw.invokespecial("java/lang/Object", "<init>", "()V");
|
||||
|
||||
mw.visitInsn(Opcodes.RETURN);
|
||||
mw.return_();
|
||||
mw.visitMaxs(3, 3);
|
||||
}
|
||||
|
||||
@ -54,9 +54,9 @@ public class LambdaGenerator {
|
||||
|
||||
String TYPE_OBJECT = ASMUtils.type(objectClass);
|
||||
int OBJECT = 1, VALUE = 2;
|
||||
mw.visitVarInsn(Opcodes.ALOAD, OBJECT);
|
||||
mw.visitTypeInsn(Opcodes.CHECKCAST, TYPE_OBJECT);
|
||||
mw.visitVarInsn(Opcodes.ILOAD, VALUE);
|
||||
mw.aload(OBJECT);
|
||||
mw.checkcast(TYPE_OBJECT);
|
||||
mw.iload(VALUE);
|
||||
|
||||
Class returnType = Void.TYPE;
|
||||
String methodDesc;
|
||||
@ -66,12 +66,12 @@ public class LambdaGenerator {
|
||||
methodDesc = "(I)" + ASMUtils.desc(returnType);
|
||||
}
|
||||
|
||||
mw.visitMethodInsn(Opcodes.INVOKEVIRTUAL, TYPE_OBJECT, methodName, methodDesc, false);
|
||||
mw.invokevirtual(TYPE_OBJECT, methodName, methodDesc);
|
||||
if (returnType != Void.TYPE) {
|
||||
mw.visitInsn(Opcodes.POP);
|
||||
mw.pop();
|
||||
}
|
||||
|
||||
mw.visitInsn(Opcodes.RETURN);
|
||||
mw.return_();
|
||||
mw.visitMaxs(2, 2);
|
||||
|
||||
byte[] code = cw.toByteArray();
|
||||
|
@ -67,8 +67,8 @@ public class EishayFuryCompatibleWrite {
|
||||
}
|
||||
|
||||
public int furySize() {
|
||||
// return furyCompatible.serialize(mc).length;
|
||||
return 0;
|
||||
return furyCompatible.serialize(mc).length;
|
||||
// return 0;
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws RunnerException {
|
||||
|
@ -15,14 +15,14 @@ public class EishayFuryCompatibleWriteTest {
|
||||
}
|
||||
long millis = System.currentTimeMillis() - start;
|
||||
System.out.println("EishayFuryCompatibleWrite-jsonb millis : " + millis);
|
||||
// zulu8.68.0.21_AppleM1Max : 3839 3798 3763 3145 2129
|
||||
// zulu11.62.17_AppleM1Max : 3327 3244 3310 3085 2907 1836
|
||||
// zulu17.40.19_AppleM1Max : 3287 3256 3321 3296 3257 3390 1842
|
||||
// zulu8.68.0.21_AppleM1Max : 3839 3798 3763 3145 2129 1722
|
||||
// zulu11.62.17_AppleM1Max : 3327 3244 3310 3085 2907 1836 1449
|
||||
// zulu17.40.19_AppleM1Max : 3287 3256 3321 3296 3257 3390 1842 1474
|
||||
}
|
||||
}
|
||||
|
||||
public static void fury() throws Exception {
|
||||
System.out.println("fury size " + benchmark.furySize()); // 661
|
||||
System.out.println("fury size " + benchmark.furySize()); // 661 502
|
||||
for (int j = 0; j < 5; j++) {
|
||||
long start = System.currentTimeMillis();
|
||||
for (int i = 0; i < COUNT; ++i) {
|
||||
@ -30,9 +30,9 @@ public class EishayFuryCompatibleWriteTest {
|
||||
}
|
||||
long millis = System.currentTimeMillis() - start;
|
||||
System.out.println("EishayFuryCompatibleWrite-fury millis : " + millis);
|
||||
// zulu8.68.0.21_AppleM1Max : 2644 3018
|
||||
// zulu11.62.17_AppleM1Max : 2270 2510
|
||||
// zulu17.40.19_AppleM1Max : 2296 2319 2293
|
||||
// zulu8.68.0.21_AppleM1Max : 2644 3018 2448
|
||||
// zulu11.62.17_AppleM1Max : 2270 2510 1652
|
||||
// zulu17.40.19_AppleM1Max : 2296 2319 2293 1698
|
||||
|
||||
// jdk1.8.0_361_x86_i9 5279
|
||||
// jdk17.0.6_x86_i9 5910
|
||||
|
@ -40,7 +40,7 @@ public class ClientsWriteUTF8BytesTest {
|
||||
long millis = System.currentTimeMillis() - start;
|
||||
System.out.println("ClientsWriteUTF8Bytes-fastjson2 millis : " + millis);
|
||||
// zulu8.70.0.23 : 1533 1493 1374 1353
|
||||
// zulu17.40.19 : 1419 1361 1356 1356 1317 1224 1212 1202 1182 979 949 914 944 915
|
||||
// zulu17.40.19 : 1419 1361 1356 1356 1317 1224 1212 1202 1182 979 949 914 944 915 889
|
||||
// zulu17.40.19_vec : 1116
|
||||
// zulu17.40.19_reflect : 1427
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package com.alibaba.fastjson2;
|
||||
|
||||
import com.alibaba.fastjson2.filter.Filter;
|
||||
import com.alibaba.fastjson2.internal.trove.map.hash.TLongIntHashMap;
|
||||
import com.alibaba.fastjson2.reader.ObjectReader;
|
||||
import com.alibaba.fastjson2.reader.ObjectReaderBean;
|
||||
import com.alibaba.fastjson2.reader.ObjectReaderProvider;
|
||||
@ -13,13 +14,13 @@ import java.io.OutputStream;
|
||||
import java.lang.reflect.Type;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.time.*;
|
||||
import java.util.*;
|
||||
|
||||
import static com.alibaba.fastjson2.JSONB.Constants.*;
|
||||
import static com.alibaba.fastjson2.JSONFactory.*;
|
||||
import static com.alibaba.fastjson2.JSONWriter.*;
|
||||
import static com.alibaba.fastjson2.JSONWriter.Feature.WriteEnumUsingToString;
|
||||
import static com.alibaba.fastjson2.JSONWriter.Feature.*;
|
||||
import static com.alibaba.fastjson2.util.IOUtils.*;
|
||||
import static com.alibaba.fastjson2.util.JDKUtils.*;
|
||||
|
||||
@ -1274,7 +1275,11 @@ public interface JSONB {
|
||||
}
|
||||
|
||||
static String toJSONString(byte[] jsonbBytes, SymbolTable symbolTable) {
|
||||
return new JSONBDump(jsonbBytes, symbolTable, false)
|
||||
return toJSONString(jsonbBytes, symbolTable, false);
|
||||
}
|
||||
|
||||
static String toJSONString(byte[] jsonbBytes, SymbolTable symbolTable, boolean raw) {
|
||||
return new JSONBDump(jsonbBytes, symbolTable, raw)
|
||||
.toString();
|
||||
}
|
||||
|
||||
@ -1457,9 +1462,9 @@ public interface JSONB {
|
||||
}
|
||||
|
||||
interface IO {
|
||||
static int enumSize(Enum e, long features) {
|
||||
static int enumCapacity(Enum e, long features) {
|
||||
if ((features & (MASK_WRITE_ENUM_USING_TO_STRING | MASK_WRITE_ENUMS_USING_NAME)) != 0) {
|
||||
return stringSize((features & WriteEnumUsingToString.mask) != 0
|
||||
return stringCapacity((features & WriteEnumUsingToString.mask) != 0
|
||||
? e.toString()
|
||||
: e.name());
|
||||
}
|
||||
@ -1488,6 +1493,18 @@ public interface JSONB {
|
||||
return off + 1;
|
||||
}
|
||||
|
||||
static int writeBoolean(byte[] bytes, int off, boolean[] values) {
|
||||
if (values == null) {
|
||||
bytes[off] = BC_NULL;
|
||||
return off + 1;
|
||||
}
|
||||
off = startArray(bytes, off, values.length);
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
bytes[off + i] = values[i] ? BC_TRUE : BC_FALSE;
|
||||
}
|
||||
return off + values.length;
|
||||
}
|
||||
|
||||
static int writeFloat(byte[] bytes, int off, Float value, long features) {
|
||||
float floatValue;
|
||||
if (value == null) {
|
||||
@ -1502,15 +1519,27 @@ public interface JSONB {
|
||||
return IO.writeFloat(bytes, off, floatValue);
|
||||
}
|
||||
|
||||
static int writeFloat(byte[] bytes, int off, float[] values) {
|
||||
if (values == null) {
|
||||
bytes[off] = BC_NULL;
|
||||
return off + 1;
|
||||
}
|
||||
off = startArray(bytes, off, values.length);
|
||||
for (float value : values) {
|
||||
off = IO.writeFloat(bytes, off, value);
|
||||
}
|
||||
return off;
|
||||
}
|
||||
|
||||
static int writeFloat(byte[] bytes, int off, float value) {
|
||||
int i = (int) value;
|
||||
if (i == value && ((i + 0x10) & ~0x3f) == 0) {
|
||||
putShortLE(bytes, off, (short) ((BC_FLOAT_INT & 0xFF) | (i << 8)));
|
||||
return off + 2;
|
||||
int intValue = (int) value;
|
||||
if (intValue == value && ((intValue + 0x40000) & ~0x7ffff) == 0) {
|
||||
putByte(bytes, off, BC_FLOAT_INT);
|
||||
return IO.writeInt32(bytes, off + 1, intValue);
|
||||
}
|
||||
|
||||
putByte(bytes, off, BC_FLOAT);
|
||||
putIntBE(bytes, off + 1, Float.floatToIntBits(value));
|
||||
IOUtils.putIntBE(bytes, off + 1, Float.floatToIntBits(value));
|
||||
return off + 5;
|
||||
}
|
||||
|
||||
@ -1542,6 +1571,50 @@ public interface JSONB {
|
||||
return off + 9;
|
||||
}
|
||||
|
||||
static int writeDouble(byte[] bytes, int off, double[] values) {
|
||||
if (values == null) {
|
||||
bytes[off] = BC_NULL;
|
||||
return off + 1;
|
||||
}
|
||||
off = startArray(bytes, off, values.length);
|
||||
for (double value : values) {
|
||||
off = writeDouble(bytes, off, value);
|
||||
}
|
||||
return off;
|
||||
}
|
||||
|
||||
static int writeInt8(byte[] bytes, int off, Byte val, long features) {
|
||||
if (val == null) {
|
||||
putByte(bytes, off,
|
||||
(features & (MASK_NULL_AS_DEFAULT_VALUE | MASK_WRITE_NULL_NUMBER_AS_ZERO)) == 0 ? BC_NULL : 0);
|
||||
return off + 1;
|
||||
}
|
||||
putShortLE(bytes, off, (short) ((val << 8) | (BC_INT8 & 0xFF)));
|
||||
return off + 2;
|
||||
}
|
||||
|
||||
static int writeInt8(byte[] bytes, int off, byte val) {
|
||||
putShortLE(bytes, off, (short) ((val << 8) | (BC_INT8 & 0xFF)));
|
||||
return off + 2;
|
||||
}
|
||||
|
||||
static int writeInt16(byte[] bytes, int off, Short val, long features) {
|
||||
if (val == null) {
|
||||
putByte(bytes, off,
|
||||
(features & (MASK_NULL_AS_DEFAULT_VALUE | MASK_WRITE_NULL_NUMBER_AS_ZERO)) == 0 ? BC_NULL : 0);
|
||||
return off + 1;
|
||||
}
|
||||
bytes[off] = BC_INT16;
|
||||
putShortBE(bytes, off + 1, val);
|
||||
return off + 3;
|
||||
}
|
||||
|
||||
static int writeInt16(byte[] bytes, int off, short val) {
|
||||
bytes[off] = BC_INT16;
|
||||
putShortBE(bytes, off + 1, val);
|
||||
return off + 3;
|
||||
}
|
||||
|
||||
static int writeInt32(byte[] bytes, int off, Integer value, long features) {
|
||||
if (value == null) {
|
||||
putByte(bytes, off,
|
||||
@ -1551,6 +1624,78 @@ public interface JSONB {
|
||||
return IO.writeInt32(bytes, off, value);
|
||||
}
|
||||
|
||||
static int writeSymbol(byte[] bytes, int off, String str, SymbolTable symbolTable) {
|
||||
if (str == null) {
|
||||
putByte(bytes, off, BC_NULL);
|
||||
return off + 1;
|
||||
}
|
||||
int ordinal = symbolTable.getOrdinal(str);
|
||||
if (ordinal >= 0) {
|
||||
bytes[off] = BC_STR_ASCII;
|
||||
return writeInt32(bytes, off + 1, -ordinal);
|
||||
}
|
||||
return writeString(bytes, off, str);
|
||||
}
|
||||
|
||||
static int writeSymbol(byte[] bytes, int off, int symbol) {
|
||||
bytes[off++] = BC_SYMBOL;
|
||||
|
||||
if (symbol >= BC_INT32_NUM_MIN && symbol <= BC_INT32_NUM_MAX) {
|
||||
bytes[off++] = (byte) symbol;
|
||||
} else if (symbol >= INT32_BYTE_MIN && symbol <= INT32_BYTE_MAX) {
|
||||
putShortBE(bytes, off, (short) ((BC_INT32_BYTE_ZERO << 8) + symbol));
|
||||
off += 2;
|
||||
} else {
|
||||
off = JSONB.IO.writeInt32(bytes, off, symbol);
|
||||
}
|
||||
return off;
|
||||
}
|
||||
|
||||
static int checkAndWriteTypeName(byte[] bytes, int off, Object object, Class<?> fieldClass, JSONWriter jsonWriter) {
|
||||
long features = jsonWriter.getFeatures();
|
||||
Class<?> objectClass;
|
||||
if ((features & WriteClassName.mask) == 0
|
||||
|| object == null
|
||||
|| (objectClass = object.getClass()) == fieldClass
|
||||
|| ((features & NotWriteHashMapArrayListClassName.mask) != 0 && (objectClass == HashMap.class || objectClass == ArrayList.class))
|
||||
|| ((features & NotWriteRootClassName.mask) != 0 && object == jsonWriter.rootObject)
|
||||
) {
|
||||
return off;
|
||||
}
|
||||
|
||||
return writeTypeName(bytes, off, TypeUtils.getTypeName(objectClass), jsonWriter);
|
||||
}
|
||||
|
||||
static int writeTypeName(byte[] bytes, int off, String typeName, JSONWriter jsonWriter) {
|
||||
JSONWriterJSONB jsonWriterJSONB = (JSONWriterJSONB) jsonWriter;
|
||||
SymbolTable symbolTable = jsonWriter.symbolTable;
|
||||
bytes[off++] = BC_TYPED_ANY;
|
||||
|
||||
long hash = Fnv.hashCode64(typeName);
|
||||
|
||||
int symbol = -1;
|
||||
if (symbolTable != null) {
|
||||
symbol = symbolTable.getOrdinalByHashCode(hash);
|
||||
if (symbol == -1 && jsonWriterJSONB.symbols != null) {
|
||||
symbol = jsonWriterJSONB.symbols.get(hash);
|
||||
}
|
||||
} else if (jsonWriterJSONB.symbols != null) {
|
||||
symbol = jsonWriterJSONB.symbols.get(hash);
|
||||
}
|
||||
|
||||
if (symbol == -1) {
|
||||
if (jsonWriterJSONB.symbols == null) {
|
||||
jsonWriterJSONB.symbols = new TLongIntHashMap();
|
||||
}
|
||||
jsonWriterJSONB.symbols.put(hash, symbol = jsonWriterJSONB.symbolIndex++);
|
||||
} else {
|
||||
return JSONB.IO.writeInt32(bytes, off, symbol);
|
||||
}
|
||||
|
||||
off = writeString(bytes, off, typeName);
|
||||
return writeInt32(bytes, off, symbol);
|
||||
}
|
||||
|
||||
static int writeInt32(byte[] bytes, int off, int value) {
|
||||
if (((value + 0x10) & ~0x3f) == 0) {
|
||||
putByte(bytes, off++, (byte) value);
|
||||
@ -1576,8 +1721,8 @@ public interface JSONB {
|
||||
}
|
||||
int size = values.size();
|
||||
off = startArray(bytes, off, size);
|
||||
for (Long string : values) {
|
||||
off = writeInt64(bytes, off, string, features);
|
||||
for (Long value : values) {
|
||||
off = writeInt64(bytes, off, value, features);
|
||||
}
|
||||
return off;
|
||||
}
|
||||
@ -1617,7 +1762,7 @@ public interface JSONB {
|
||||
|
||||
static int startArray(byte[] bytes, int off, int size) {
|
||||
boolean tinyInt = size <= ARRAY_FIX_LEN;
|
||||
putByte(bytes, off++, tinyInt ? (byte) (BC_ARRAY_FIX_MIN + size) : BC_ARRAY);
|
||||
bytes[off++] = tinyInt ? (byte) (BC_ARRAY_FIX_MIN + size) : BC_ARRAY;
|
||||
if (!tinyInt) {
|
||||
off = writeInt32(bytes, off, size);
|
||||
}
|
||||
@ -1637,9 +1782,22 @@ public interface JSONB {
|
||||
return off;
|
||||
}
|
||||
|
||||
static int writeString(byte[] bytes, int off, String[] strings, long features) {
|
||||
if (strings == null) {
|
||||
putByte(bytes, off, (features & WRITE_ARRAY_NULL_MASK) != 0 ? BC_ARRAY_FIX_MIN : BC_NULL);
|
||||
return off + 1;
|
||||
}
|
||||
int size = strings.length;
|
||||
off = startArray(bytes, off, size);
|
||||
for (String string : strings) {
|
||||
off = writeString(bytes, off, string);
|
||||
}
|
||||
return off;
|
||||
}
|
||||
|
||||
static int writeString(byte[] bytes, int off, String str) {
|
||||
if (str == null) {
|
||||
putByte(bytes, off, BC_NULL);
|
||||
bytes[off] = BC_NULL;
|
||||
return off + 1;
|
||||
}
|
||||
if (STRING_CODER != null && STRING_VALUE != null) {
|
||||
@ -1676,25 +1834,38 @@ public interface JSONB {
|
||||
return off + strlen;
|
||||
}
|
||||
|
||||
static int stringSize(Collection<String> strings) {
|
||||
static int stringCapacity(Collection<String> strings) {
|
||||
if (strings == null) {
|
||||
return 1;
|
||||
}
|
||||
int size = stringCapacity(strings.getClass().getName()) + 7;
|
||||
for (String string : strings) {
|
||||
size += stringCapacity(string);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
static int stringCapacity(String[] strings) {
|
||||
if (strings == null) {
|
||||
return 1;
|
||||
}
|
||||
int size = 6;
|
||||
for (String string : strings) {
|
||||
size += stringSize(string);
|
||||
size += stringCapacity(string);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
static int int64Size(Collection<Long> values) {
|
||||
static int int64Capacity(Collection<Long> values) {
|
||||
if (values == null) {
|
||||
return 1;
|
||||
}
|
||||
return 6 + values.size() * 9;
|
||||
return stringCapacity(values.getClass().getName())
|
||||
+ 7
|
||||
+ values.size() * 9;
|
||||
}
|
||||
|
||||
static int stringSize(String str) {
|
||||
static int stringCapacity(String str) {
|
||||
if (str == null) {
|
||||
return 0;
|
||||
}
|
||||
@ -1806,5 +1977,174 @@ public interface JSONB {
|
||||
|
||||
return 5;
|
||||
}
|
||||
|
||||
static int writeUUID(byte[] bytes, int off, UUID value) {
|
||||
if (value == null) {
|
||||
bytes[off] = BC_NULL;
|
||||
return off + 1;
|
||||
}
|
||||
putShortLE(bytes, off, (short) ((BC_BINARY & 0xFF) | ((BC_INT32_NUM_16 & 0xFF) << 8)));
|
||||
putLongBE(bytes, off + 2, value.getMostSignificantBits());
|
||||
putLongBE(bytes, off + 10, value.getLeastSignificantBits());
|
||||
return off + 18;
|
||||
}
|
||||
|
||||
static int writeInstant(byte[] bytes, int off, Instant value) {
|
||||
if (value == null) {
|
||||
bytes[off] = BC_NULL;
|
||||
return off + 1;
|
||||
}
|
||||
bytes[off] = BC_TIMESTAMP;
|
||||
off = JSONB.IO.writeInt64(bytes, off + 1, value.getEpochSecond());
|
||||
return JSONB.IO.writeInt32(bytes, off, value.getNano());
|
||||
}
|
||||
|
||||
static int writeLocalDate(byte[] bytes, int off, LocalDate value) {
|
||||
if (value == null) {
|
||||
bytes[off] = BC_NULL;
|
||||
return off + 1;
|
||||
}
|
||||
putByte(bytes, off, BC_LOCAL_DATE);
|
||||
int year = value.getYear();
|
||||
putIntBE(bytes, off + 1, (year << 16) | (value.getMonthValue() << 8) | value.getDayOfMonth());
|
||||
return off + 5;
|
||||
}
|
||||
|
||||
static int writeLocalTime(byte[] bytes, int off, LocalTime value) {
|
||||
if (value == null) {
|
||||
bytes[off] = BC_NULL;
|
||||
return off + 1;
|
||||
}
|
||||
putIntBE(bytes,
|
||||
off,
|
||||
(BC_LOCAL_TIME << 24) | (value.getHour() << 16) | (value.getMinute() << 8) | value.getSecond());
|
||||
return JSONB.IO.writeInt32(bytes, off + 4, value.getNano());
|
||||
}
|
||||
|
||||
static int writeLocalDateTime(byte[] bytes, int off, LocalDateTime value) {
|
||||
if (value == null) {
|
||||
bytes[off] = BC_NULL;
|
||||
return off + 1;
|
||||
}
|
||||
putIntBE(bytes,
|
||||
off,
|
||||
(BC_LOCAL_DATETIME << 24) | (value.getYear() << 8) | value.getMonthValue());
|
||||
putIntBE(bytes,
|
||||
off + 4,
|
||||
(value.getDayOfMonth() << 24)
|
||||
| (value.getHour() << 16)
|
||||
| (value.getMinute() << 8)
|
||||
| value.getSecond());
|
||||
return writeInt32(bytes, off + 8, value.getNano());
|
||||
}
|
||||
|
||||
static int writeOffsetDateTime(byte[] bytes, int off, OffsetDateTime value) {
|
||||
if (value == null) {
|
||||
bytes[off] = BC_NULL;
|
||||
return off + 1;
|
||||
}
|
||||
putIntBE(bytes,
|
||||
off,
|
||||
(BC_TIMESTAMP_WITH_TIMEZONE << 24) | (value.getYear() << 8) | value.getMonthValue());
|
||||
putIntBE(bytes,
|
||||
off + 4,
|
||||
(value.getDayOfMonth() << 24)
|
||||
| (value.getHour() << 16)
|
||||
| (value.getMinute() << 8)
|
||||
| value.getSecond());
|
||||
|
||||
off = writeInt32(bytes, off + 8, value.getNano());
|
||||
|
||||
String zoneIdStr = value.getOffset().getId();
|
||||
int strlen = zoneIdStr.length();
|
||||
bytes[off] = (byte) (strlen + BC_STR_ASCII_FIX_MIN);
|
||||
zoneIdStr.getBytes(0, strlen, bytes, off + 1);
|
||||
return off + strlen + 1;
|
||||
}
|
||||
|
||||
static int writeOffsetTime(byte[] bytes, int off, OffsetTime value) {
|
||||
if (value == null) {
|
||||
bytes[off] = BC_NULL;
|
||||
return off + 1;
|
||||
}
|
||||
|
||||
int year = 1970, month = 1, dayOfMonth = 1;
|
||||
putIntBE(bytes,
|
||||
off,
|
||||
(BC_TIMESTAMP_WITH_TIMEZONE << 24) | (year << 8) | month);
|
||||
putIntBE(bytes,
|
||||
off + 4,
|
||||
(dayOfMonth << 24)
|
||||
| (value.getHour() << 16)
|
||||
| (value.getMinute() << 8)
|
||||
| value.getSecond());
|
||||
|
||||
off = writeInt32(bytes, off + 8, value.getNano());
|
||||
|
||||
String zoneIdStr = value.getOffset().getId();
|
||||
int strlen = zoneIdStr.length();
|
||||
bytes[off] = (byte) (strlen + BC_STR_ASCII_FIX_MIN);
|
||||
zoneIdStr.getBytes(0, strlen, bytes, off + 1);
|
||||
return off + strlen + 1;
|
||||
}
|
||||
|
||||
static int writeReference(byte[] bytes, int off, String path, JSONWriter jsonWriter) {
|
||||
if (jsonWriter.lastReference == path) {
|
||||
path = "#-1";
|
||||
} else {
|
||||
jsonWriter.lastReference = path;
|
||||
}
|
||||
bytes[off] = BC_REFERENCE;
|
||||
return writeString(bytes, off + 1, path);
|
||||
}
|
||||
|
||||
static int writeNameRaw(byte[] bytes, int off, byte[] name, long nameHash, JSONWriter jsonWriter) {
|
||||
SymbolTable symbolTable = jsonWriter.symbolTable;
|
||||
JSONWriterJSONB jsonWriterJSONB = (JSONWriterJSONB) jsonWriter;
|
||||
int symbol;
|
||||
if (symbolTable == null
|
||||
|| (symbol = symbolTable.getOrdinalByHashCode(nameHash)) == -1
|
||||
) {
|
||||
if ((jsonWriter.context.features & WriteNameAsSymbol.mask) == 0) {
|
||||
System.arraycopy(name, 0, bytes, off, name.length);
|
||||
return off + name.length;
|
||||
}
|
||||
|
||||
boolean symbolExists = false;
|
||||
if (jsonWriterJSONB.symbols != null) {
|
||||
if ((symbol = jsonWriterJSONB.symbols.putIfAbsent(nameHash, jsonWriterJSONB.symbolIndex)) != jsonWriterJSONB.symbolIndex) {
|
||||
symbolExists = true;
|
||||
} else {
|
||||
jsonWriterJSONB.symbolIndex++;
|
||||
}
|
||||
} else {
|
||||
(jsonWriterJSONB.symbols = new TLongIntHashMap())
|
||||
.put(nameHash, symbol = jsonWriterJSONB.symbolIndex++);
|
||||
}
|
||||
|
||||
if (!symbolExists) {
|
||||
putByte(bytes, off++, BC_SYMBOL);
|
||||
System.arraycopy(name, 0, bytes, off, name.length);
|
||||
off += name.length;
|
||||
|
||||
if (symbol >= BC_INT32_NUM_MIN && symbol <= BC_INT32_NUM_MAX) {
|
||||
putByte(bytes, off++, (byte) symbol);
|
||||
} else {
|
||||
off = JSONB.IO.writeInt32(bytes, off, symbol);
|
||||
}
|
||||
return off;
|
||||
}
|
||||
symbol = -symbol;
|
||||
}
|
||||
|
||||
bytes[off++] = BC_SYMBOL;
|
||||
int intValue = -symbol;
|
||||
if (intValue >= BC_INT32_NUM_MIN && intValue <= BC_INT32_NUM_MAX) {
|
||||
putByte(bytes, off++, (byte) intValue);
|
||||
} else {
|
||||
off = JSONB.IO.writeInt32(bytes, off, intValue);
|
||||
}
|
||||
return off;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -105,17 +105,17 @@ class JSONPathCompilerReflectASM
|
||||
METHOD_SINGLE_NAME_PATH_TYPED_INIT,
|
||||
64
|
||||
);
|
||||
mw.visitVarInsn(Opcodes.ALOAD, THIS);
|
||||
mw.visitVarInsn(Opcodes.ALOAD, PATH);
|
||||
mw.visitVarInsn(Opcodes.ALOAD, CLASS);
|
||||
mw.visitVarInsn(Opcodes.ALOAD, OBJECT_READER);
|
||||
mw.visitVarInsn(Opcodes.ALOAD, FIELD_READER);
|
||||
mw.visitVarInsn(Opcodes.ALOAD, OBJECT_WRITER);
|
||||
mw.visitVarInsn(Opcodes.ALOAD, FIELD_WRITER);
|
||||
mw.aload(THIS);
|
||||
mw.aload(PATH);
|
||||
mw.aload(CLASS);
|
||||
mw.aload(OBJECT_READER);
|
||||
mw.aload(FIELD_READER);
|
||||
mw.aload(OBJECT_WRITER);
|
||||
mw.aload(FIELD_WRITER);
|
||||
|
||||
mw.visitMethodInsn(Opcodes.INVOKESPECIAL, TYPE_SINGLE_NAME_PATH_TYPED, "<init>", METHOD_SINGLE_NAME_PATH_TYPED_INIT, false);
|
||||
mw.invokespecial(TYPE_SINGLE_NAME_PATH_TYPED, "<init>", METHOD_SINGLE_NAME_PATH_TYPED_INIT);
|
||||
|
||||
mw.visitInsn(Opcodes.RETURN);
|
||||
mw.return_();
|
||||
mw.visitMaxs(3, 3);
|
||||
}
|
||||
|
||||
@ -130,13 +130,13 @@ class JSONPathCompilerReflectASM
|
||||
"(Ljava/lang/Object;I)V",
|
||||
64
|
||||
);
|
||||
mw.visitVarInsn(Opcodes.ALOAD, OBJECT);
|
||||
mw.visitTypeInsn(Opcodes.CHECKCAST, TYPE_OBJECT);
|
||||
mw.aload(OBJECT);
|
||||
mw.checkcast(TYPE_OBJECT);
|
||||
mw.visitVarInsn(Opcodes.ILOAD, VALUE);
|
||||
|
||||
gwSetValue(mw, TYPE_OBJECT, fieldReader);
|
||||
|
||||
mw.visitInsn(Opcodes.RETURN);
|
||||
mw.return_();
|
||||
mw.visitMaxs(2, 2);
|
||||
}
|
||||
if (fieldClass == long.class) {
|
||||
@ -146,13 +146,13 @@ class JSONPathCompilerReflectASM
|
||||
"(Ljava/lang/Object;J)V",
|
||||
64
|
||||
);
|
||||
mw.visitVarInsn(Opcodes.ALOAD, OBJECT);
|
||||
mw.visitTypeInsn(Opcodes.CHECKCAST, TYPE_OBJECT);
|
||||
mw.visitVarInsn(Opcodes.LLOAD, VALUE);
|
||||
mw.aload(OBJECT);
|
||||
mw.checkcast(TYPE_OBJECT);
|
||||
mw.lload(VALUE);
|
||||
|
||||
gwSetValue(mw, TYPE_OBJECT, fieldReader);
|
||||
|
||||
mw.visitInsn(Opcodes.RETURN);
|
||||
mw.return_();
|
||||
mw.visitMaxs(2, 2);
|
||||
}
|
||||
|
||||
@ -163,37 +163,37 @@ class JSONPathCompilerReflectASM
|
||||
"(Ljava/lang/Object;Ljava/lang/Object;)V",
|
||||
64
|
||||
);
|
||||
mw.visitVarInsn(Opcodes.ALOAD, OBJECT);
|
||||
mw.visitTypeInsn(Opcodes.CHECKCAST, TYPE_OBJECT);
|
||||
mw.visitVarInsn(Opcodes.ALOAD, VALUE);
|
||||
mw.aload(OBJECT);
|
||||
mw.checkcast(TYPE_OBJECT);
|
||||
mw.aload(VALUE);
|
||||
if (fieldClass == int.class) {
|
||||
mw.visitTypeInsn(Opcodes.CHECKCAST, "java/lang/Number");
|
||||
mw.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Number", "intValue", "()I", false);
|
||||
mw.checkcast("java/lang/Number");
|
||||
mw.invokevirtual("java/lang/Number", "intValue", "()I");
|
||||
} else if (fieldClass == long.class) {
|
||||
mw.visitTypeInsn(Opcodes.CHECKCAST, "java/lang/Number");
|
||||
mw.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Number", "longValue", "()J", false);
|
||||
mw.checkcast("java/lang/Number");
|
||||
mw.invokevirtual("java/lang/Number", "longValue", "()J");
|
||||
} else if (fieldClass == float.class) {
|
||||
mw.visitTypeInsn(Opcodes.CHECKCAST, "java/lang/Number");
|
||||
mw.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Number", "floatValue", "()F", false);
|
||||
mw.checkcast("java/lang/Number");
|
||||
mw.invokevirtual("java/lang/Number", "floatValue", "()F");
|
||||
} else if (fieldClass == double.class) {
|
||||
mw.visitTypeInsn(Opcodes.CHECKCAST, "java/lang/Number");
|
||||
mw.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Number", "doubleValue", "()D", false);
|
||||
mw.checkcast("java/lang/Number");
|
||||
mw.invokevirtual("java/lang/Number", "doubleValue", "()D");
|
||||
} else if (fieldClass == short.class) {
|
||||
mw.visitTypeInsn(Opcodes.CHECKCAST, "java/lang/Number");
|
||||
mw.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Number", "shortValue", "()S", false);
|
||||
mw.checkcast("java/lang/Number");
|
||||
mw.invokevirtual("java/lang/Number", "shortValue", "()S");
|
||||
} else if (fieldClass == byte.class) {
|
||||
mw.visitTypeInsn(Opcodes.CHECKCAST, "java/lang/Number");
|
||||
mw.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Number", "byteValue", "()B", false);
|
||||
mw.checkcast("java/lang/Number");
|
||||
mw.invokevirtual("java/lang/Number", "byteValue", "()B");
|
||||
} else if (fieldClass == boolean.class) {
|
||||
mw.visitTypeInsn(Opcodes.CHECKCAST, "java/lang/Boolean");
|
||||
mw.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z", false);
|
||||
mw.checkcast("java/lang/Boolean");
|
||||
mw.invokevirtual("java/lang/Boolean", "booleanValue", "()Z");
|
||||
} else if (fieldClass == char.class) {
|
||||
mw.visitTypeInsn(Opcodes.CHECKCAST, "java/lang/Character");
|
||||
mw.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Character", "charValue", "()C", false);
|
||||
mw.checkcast("java/lang/Character");
|
||||
mw.invokevirtual("java/lang/Character", "charValue", "()C");
|
||||
}
|
||||
gwSetValue(mw, TYPE_OBJECT, fieldReader);
|
||||
|
||||
mw.visitInsn(Opcodes.RETURN);
|
||||
mw.return_();
|
||||
mw.visitMaxs(2, 2);
|
||||
}
|
||||
}
|
||||
@ -209,28 +209,28 @@ class JSONPathCompilerReflectASM
|
||||
"(Ljava/lang/Object;)Ljava/lang/Object;",
|
||||
64
|
||||
);
|
||||
mw.visitVarInsn(Opcodes.ALOAD, OBJECT);
|
||||
mw.visitTypeInsn(Opcodes.CHECKCAST, TYPE_OBJECT);
|
||||
mw.aload(OBJECT);
|
||||
mw.checkcast(TYPE_OBJECT);
|
||||
gwGetValue(mw, TYPE_OBJECT, fieldWriter);
|
||||
if (fieldClass == int.class) {
|
||||
mw.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", false);
|
||||
mw.invokestatic("java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;");
|
||||
} else if (fieldClass == long.class) {
|
||||
mw.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;", false);
|
||||
mw.invokestatic("java/lang/Long", "valueOf", "(J)Ljava/lang/Long;");
|
||||
} else if (fieldClass == float.class) {
|
||||
mw.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Float", "valueOf", "(F)Ljava/lang/Float;", false);
|
||||
mw.invokestatic("java/lang/Float", "valueOf", "(F)Ljava/lang/Float;");
|
||||
} else if (fieldClass == double.class) {
|
||||
mw.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Double", "valueOf", "(D)Ljava/lang/Double;", false);
|
||||
mw.invokestatic("java/lang/Double", "valueOf", "(D)Ljava/lang/Double;");
|
||||
} else if (fieldClass == short.class) {
|
||||
mw.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Short", "valueOf", "(S)Ljava/lang/Short;", false);
|
||||
mw.invokestatic("java/lang/Short", "valueOf", "(S)Ljava/lang/Short;");
|
||||
} else if (fieldClass == byte.class) {
|
||||
mw.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;", false);
|
||||
mw.invokestatic("java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;");
|
||||
} else if (fieldClass == boolean.class) {
|
||||
mw.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;", false);
|
||||
mw.invokestatic("java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;");
|
||||
} else if (fieldClass == char.class) {
|
||||
mw.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Character", "valueOf", "(C)Ljava/lang/Character;", false);
|
||||
mw.invokestatic("java/lang/Character", "valueOf", "(C)Ljava/lang/Character;");
|
||||
}
|
||||
|
||||
mw.visitInsn(Opcodes.ARETURN);
|
||||
mw.areturn();
|
||||
mw.visitMaxs(2, 2);
|
||||
}
|
||||
|
||||
@ -258,12 +258,12 @@ class JSONPathCompilerReflectASM
|
||||
if (method != null) {
|
||||
Class<?> returnType = method.getReturnType();
|
||||
String methodDesc = '(' + fieldClassDesc + ')' + ASMUtils.desc(returnType);
|
||||
mw.visitMethodInsn(Opcodes.INVOKEVIRTUAL, TYPE_OBJECT, method.getName(), methodDesc, false);
|
||||
mw.invokevirtual(TYPE_OBJECT, method.getName(), methodDesc);
|
||||
if (returnType != Void.TYPE) { // builder
|
||||
mw.visitInsn(Opcodes.POP);
|
||||
mw.pop();
|
||||
}
|
||||
} else {
|
||||
mw.visitFieldInsn(Opcodes.PUTFIELD, TYPE_OBJECT, field.getName(), fieldClassDesc);
|
||||
mw.putfield(TYPE_OBJECT, field.getName(), fieldClassDesc);
|
||||
}
|
||||
}
|
||||
|
||||
@ -275,9 +275,9 @@ class JSONPathCompilerReflectASM
|
||||
|
||||
if (method != null) {
|
||||
String methodDesc = "()" + fieldClassDesc;
|
||||
mw.visitMethodInsn(Opcodes.INVOKEVIRTUAL, TYPE_OBJECT, method.getName(), methodDesc, false);
|
||||
mw.invokevirtual(TYPE_OBJECT, method.getName(), methodDesc);
|
||||
} else {
|
||||
mw.visitFieldInsn(Opcodes.GETFIELD, TYPE_OBJECT, field.getName(), fieldClassDesc);
|
||||
mw.getfield(TYPE_OBJECT, field.getName(), fieldClassDesc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -177,6 +177,27 @@ public abstract class JSONWriter
|
||||
return previous.toString();
|
||||
}
|
||||
|
||||
public final String setPath0(FieldWriter fieldWriter, Object object) {
|
||||
this.path = this.path == Path.ROOT
|
||||
? fieldWriter.getRootParentPath()
|
||||
: fieldWriter.getPath(path);
|
||||
|
||||
Path previous;
|
||||
if (object == rootObject) {
|
||||
previous = Path.ROOT;
|
||||
} else {
|
||||
if (refs == null || (previous = refs.get(object)) == null) {
|
||||
if (refs == null) {
|
||||
refs = new IdentityHashMap(8);
|
||||
}
|
||||
refs.put(object, this.path);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return previous.toString();
|
||||
}
|
||||
|
||||
public final void addManagerReference(Object object) {
|
||||
if (refs == null) {
|
||||
refs = new IdentityHashMap(8);
|
||||
@ -199,6 +220,10 @@ public abstract class JSONWriter
|
||||
return null;
|
||||
}
|
||||
|
||||
return setPath0(index, object);
|
||||
}
|
||||
|
||||
public final String setPath0(int index, Object object) {
|
||||
this.path = index == 0
|
||||
? (path.child0 != null ? path.child0 : (path.child0 = new Path(path, index)))
|
||||
: index == 1
|
||||
@ -211,7 +236,7 @@ public abstract class JSONWriter
|
||||
} else {
|
||||
if (refs == null || (previous = refs.get(object)) == null) {
|
||||
if (refs == null) {
|
||||
refs = new IdentityHashMap(8);
|
||||
this.refs = new IdentityHashMap(8);
|
||||
}
|
||||
refs.put(object, this.path);
|
||||
return null;
|
||||
@ -226,6 +251,10 @@ public abstract class JSONWriter
|
||||
return;
|
||||
}
|
||||
|
||||
popPath0(object);
|
||||
}
|
||||
|
||||
public final void popPath0(Object object) {
|
||||
if (this.path == null
|
||||
|| (context.features & MASK_REFERENCE_DETECTION) == 0
|
||||
|| object == Collections.EMPTY_LIST
|
||||
@ -1151,7 +1180,7 @@ public abstract class JSONWriter
|
||||
}
|
||||
|
||||
public final void writeInt64Null() {
|
||||
if ((this.context.features & (NullAsDefaultValue.mask | WriteNullNumberAsZero.mask)) != 0) {
|
||||
if ((this.context.features & (MASK_NULL_AS_DEFAULT_VALUE | MASK_WRITE_NULL_NUMBER_AS_ZERO)) != 0) {
|
||||
writeInt64(0);
|
||||
} else {
|
||||
writeNull();
|
||||
@ -1159,7 +1188,7 @@ public abstract class JSONWriter
|
||||
}
|
||||
|
||||
public final void writeBooleanNull() {
|
||||
if ((this.context.features & (NullAsDefaultValue.mask | WriteNullBooleanAsFalse.mask)) != 0) {
|
||||
if ((this.context.features & (MASK_NULL_AS_DEFAULT_VALUE | WriteNullBooleanAsFalse.mask)) != 0) {
|
||||
writeBool(false);
|
||||
} else {
|
||||
writeNull();
|
||||
@ -2099,17 +2128,25 @@ public abstract class JSONWriter
|
||||
}
|
||||
}
|
||||
|
||||
protected static final long MASK_WRITE_MAP_NULL_VALUE = 1 << 4;
|
||||
protected static final long MASK_BROWSER_COMPATIBLE = 1 << 5;
|
||||
protected static final long MASK_NULL_AS_DEFAULT_VALUE = 1 << 6;
|
||||
protected static final long MASK_WRITE_BOOLEAN_AS_NUMBER = 1 << 7;
|
||||
protected static final long MASK_WRITE_NON_STRING_VALUE_AS_STRING = 1L << 8;
|
||||
protected static final long MASK_WRITE_CLASS_NAME = 1 << 9;
|
||||
protected static final long MASK_NOT_WRITE_DEFAULT_VALUE = 1 << 12;
|
||||
protected static final long MASK_WRITE_ENUMS_USING_NAME = 1 << 13;
|
||||
protected static final long MASK_WRITE_ENUM_USING_TO_STRING = 1 << 14;
|
||||
protected static final long MASK_PRETTY_FORMAT = 1 << 16;
|
||||
protected static final long MASK_REFERENCE_DETECTION = 1 << 17;
|
||||
protected static final long MASK_USE_SINGLE_QUOTES = 1 << 20;
|
||||
protected static final long MASK_WRITE_NULL_LIST_AS_EMPTY = 1 << 22;
|
||||
protected static final long MASK_WRITE_NULL_STRING_AS_EMPTY = 1 << 23;
|
||||
protected static final long MASK_WRITE_NULL_NUMBER_AS_ZERO = 1 << 24;
|
||||
protected static final long MASK_WRITE_NULL_BOOLEAN_AS_FALSE = 1 << 25;
|
||||
protected static final long MASK_NOT_WRITE_EMPTY_ARRAY = 1 << 26;
|
||||
protected static final long MASK_ESCAPE_NONE_ASCII = 1L << 30;
|
||||
protected static final long MASK_IGNORE_NON_FIELD_GETTER = 1L << 32;
|
||||
protected static final long MASK_WRITE_LONG_AS_STRING = 1L << 34;
|
||||
protected static final long MASK_BROWSER_SECURE = 1L << 35;
|
||||
protected static final long MASK_NOT_WRITE_NUMBER_CLASS_NAME = 1L << 40;
|
||||
@ -2119,20 +2156,20 @@ public abstract class JSONWriter
|
||||
IgnoreNoneSerializable(1 << 1),
|
||||
ErrorOnNoneSerializable(1 << 2),
|
||||
BeanToArray(1 << 3),
|
||||
WriteNulls(1 << 4),
|
||||
WriteMapNullValue(1 << 4),
|
||||
WriteNulls(MASK_WRITE_MAP_NULL_VALUE),
|
||||
WriteMapNullValue(MASK_WRITE_MAP_NULL_VALUE),
|
||||
BrowserCompatible(MASK_BROWSER_COMPATIBLE),
|
||||
NullAsDefaultValue(MASK_NULL_AS_DEFAULT_VALUE),
|
||||
WriteBooleanAsNumber(1 << 7),
|
||||
WriteBooleanAsNumber(MASK_WRITE_BOOLEAN_AS_NUMBER),
|
||||
WriteNonStringValueAsString(MASK_WRITE_NON_STRING_VALUE_AS_STRING),
|
||||
WriteClassName(MASK_WRITE_CLASS_NAME),
|
||||
NotWriteRootClassName(1 << 10),
|
||||
NotWriteHashMapArrayListClassName(1 << 11),
|
||||
NotWriteDefaultValue(1 << 12),
|
||||
NotWriteDefaultValue(MASK_NOT_WRITE_DEFAULT_VALUE),
|
||||
WriteEnumsUsingName(MASK_WRITE_ENUMS_USING_NAME),
|
||||
WriteEnumUsingToString(MASK_WRITE_ENUM_USING_TO_STRING),
|
||||
IgnoreErrorGetter(1 << 15),
|
||||
PrettyFormat(1 << 16),
|
||||
PrettyFormat(MASK_PRETTY_FORMAT),
|
||||
ReferenceDetection(MASK_REFERENCE_DETECTION),
|
||||
WriteNameAsSymbol(1 << 18),
|
||||
WriteBigDecimalAsPlain(1 << 19),
|
||||
@ -2158,18 +2195,18 @@ public abstract class JSONWriter
|
||||
/**
|
||||
* @since 1.1
|
||||
*/
|
||||
WriteNullBooleanAsFalse(1 << 25),
|
||||
WriteNullBooleanAsFalse(MASK_WRITE_NULL_BOOLEAN_AS_FALSE),
|
||||
|
||||
/**
|
||||
* @since 2.0.7
|
||||
* @deprecated use IgnoreEmpty
|
||||
*/
|
||||
NotWriteEmptyArray(1 << 26),
|
||||
NotWriteEmptyArray(MASK_NOT_WRITE_EMPTY_ARRAY),
|
||||
|
||||
/**
|
||||
* @since 2.0.51
|
||||
*/
|
||||
IgnoreEmpty(1L << 26),
|
||||
IgnoreEmpty(MASK_NOT_WRITE_EMPTY_ARRAY),
|
||||
|
||||
WriteNonStringKeyAsString(1 << 27),
|
||||
/**
|
||||
@ -2188,7 +2225,7 @@ public abstract class JSONWriter
|
||||
* if format uses escaping mechanisms (which is generally true for textual formats but not for binary formats).
|
||||
* Feature is disabled by default.
|
||||
*/
|
||||
EscapeNoneAscii(1L << 30),
|
||||
EscapeNoneAscii(MASK_ESCAPE_NONE_ASCII),
|
||||
/**
|
||||
* @since 2.0.13
|
||||
*/
|
||||
@ -2197,7 +2234,7 @@ public abstract class JSONWriter
|
||||
/**
|
||||
* @since 2.0.13
|
||||
*/
|
||||
IgnoreNonFieldGetter(1L << 32),
|
||||
IgnoreNonFieldGetter(MASK_IGNORE_NON_FIELD_GETTER),
|
||||
|
||||
/**
|
||||
* @since 2.0.16
|
||||
|
@ -1,7 +1,6 @@
|
||||
package com.alibaba.fastjson2;
|
||||
|
||||
import com.alibaba.fastjson2.internal.trove.map.hash.TLongIntHashMap;
|
||||
import com.alibaba.fastjson2.util.DateUtils;
|
||||
import com.alibaba.fastjson2.util.Fnv;
|
||||
import com.alibaba.fastjson2.util.IOUtils;
|
||||
import com.alibaba.fastjson2.util.JDKUtils;
|
||||
@ -34,8 +33,8 @@ final class JSONWriterJSONB
|
||||
|
||||
private final CacheItem cacheItem;
|
||||
byte[] bytes;
|
||||
private TLongIntHashMap symbols;
|
||||
private int symbolIndex;
|
||||
TLongIntHashMap symbols;
|
||||
int symbolIndex;
|
||||
|
||||
private long rootTypeNameHash;
|
||||
|
||||
@ -968,15 +967,13 @@ final class JSONWriterJSONB
|
||||
|
||||
@Override
|
||||
public void writeFloat(float[] values) {
|
||||
if (values == null) {
|
||||
writeNull();
|
||||
return;
|
||||
int off = this.off;
|
||||
byte[] bytes = this.bytes;
|
||||
int minCapacity = off + (values == null ? 1 : (5 + values.length * 5));
|
||||
if (minCapacity > bytes.length) {
|
||||
bytes = grow(minCapacity);
|
||||
}
|
||||
startArray(values.length);
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
writeFloat(values[i]);
|
||||
}
|
||||
endArray();
|
||||
this.off = JSONB.IO.writeFloat(bytes, off, values);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -991,15 +988,13 @@ final class JSONWriterJSONB
|
||||
|
||||
@Override
|
||||
public void writeDouble(double[] values) {
|
||||
if (values == null) {
|
||||
writeNull();
|
||||
return;
|
||||
int off = this.off;
|
||||
byte[] bytes = this.bytes;
|
||||
int minCapacity = off + (values == null ? 1 : (5 + values.length * 9));
|
||||
if (minCapacity > bytes.length) {
|
||||
bytes = grow(minCapacity);
|
||||
}
|
||||
startArray(values.length);
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
writeDouble(values[i]);
|
||||
}
|
||||
endArray();
|
||||
this.off = JSONB.IO.writeDouble(bytes, off, values);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -1082,8 +1077,7 @@ final class JSONWriterJSONB
|
||||
if (off + 2 > bytes.length) {
|
||||
bytes = grow(off + 2);
|
||||
}
|
||||
putShortLE(bytes, off, (short) ((val << 8) | (BC_INT8 & 0xFF)));
|
||||
this.off = off + 2;
|
||||
this.off = JSONB.IO.writeInt8(bytes, off, val);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -1093,9 +1087,7 @@ final class JSONWriterJSONB
|
||||
if (off + 3 > bytes.length) {
|
||||
bytes = grow(off + 3);
|
||||
}
|
||||
putByte(bytes, off, BC_INT16);
|
||||
putShortBE(bytes, off + 1, val);
|
||||
this.off = off + 3;
|
||||
this.off = JSONB.IO.writeInt16(bytes, off, val);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -1278,65 +1270,32 @@ final class JSONWriterJSONB
|
||||
|
||||
@Override
|
||||
public void writeLocalDate(LocalDate date) {
|
||||
if (date == null) {
|
||||
writeNull();
|
||||
return;
|
||||
}
|
||||
|
||||
int off = this.off;
|
||||
byte[] bytes = this.bytes;
|
||||
if (off + 5 > bytes.length) {
|
||||
bytes = grow(off + 5);
|
||||
}
|
||||
|
||||
putByte(bytes, off, BC_LOCAL_DATE);
|
||||
int year = date.getYear();
|
||||
putIntBE(bytes, off + 1, (year << 16) | (date.getMonthValue() << 8) | date.getDayOfMonth());
|
||||
this.off = off + 5;
|
||||
this.off = JSONB.IO.writeLocalDate(bytes, off, date);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeLocalTime(LocalTime time) {
|
||||
if (time == null) {
|
||||
writeNull();
|
||||
return;
|
||||
}
|
||||
|
||||
int off = this.off;
|
||||
byte[] bytes = this.bytes;
|
||||
if (off + 9 > bytes.length) {
|
||||
bytes = grow(off + 9);
|
||||
}
|
||||
|
||||
putIntBE(bytes,
|
||||
off,
|
||||
(BC_LOCAL_TIME << 24) | (time.getHour() << 16) | (time.getMinute() << 8) | time.getSecond());
|
||||
this.off = JSONB.IO.writeInt32(bytes, off + 4, time.getNano());
|
||||
this.off = JSONB.IO.writeLocalTime(bytes, off, time);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeLocalDateTime(LocalDateTime dateTime) {
|
||||
if (dateTime == null) {
|
||||
writeNull();
|
||||
return;
|
||||
}
|
||||
|
||||
int off = this.off;
|
||||
byte[] bytes = this.bytes;
|
||||
if (off + 13 > bytes.length) {
|
||||
bytes = grow(off + 13);
|
||||
}
|
||||
|
||||
putIntBE(bytes,
|
||||
off,
|
||||
(BC_LOCAL_DATETIME << 24) | (dateTime.getYear() << 8) | dateTime.getMonthValue());
|
||||
putIntBE(bytes,
|
||||
off + 4,
|
||||
(dateTime.getDayOfMonth() << 24)
|
||||
| (dateTime.getHour() << 16)
|
||||
| (dateTime.getMinute() << 8)
|
||||
| dateTime.getSecond());
|
||||
this.off = JSONB.IO.writeInt32(bytes, off + 8, dateTime.getNano());
|
||||
this.off = JSONB.IO.writeLocalDateTime(bytes, off, dateTime);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -1363,8 +1322,7 @@ final class JSONWriterJSONB
|
||||
| dateTime.getSecond());
|
||||
this.off = JSONB.IO.writeInt32(bytes, off + 8, dateTime.getNano());
|
||||
|
||||
ZoneId zoneId = dateTime.getZone();
|
||||
String zoneIdStr = zoneId.getId();
|
||||
String zoneIdStr = dateTime.getZone().getId();
|
||||
if (zoneIdStr.equals(SHANGHAI_ZONE_ID_NAME)) {
|
||||
writeRaw(SHANGHAI_ZONE_ID_NAME_BYTES);
|
||||
} else {
|
||||
@ -1374,85 +1332,44 @@ final class JSONWriterJSONB
|
||||
|
||||
@Override
|
||||
public void writeOffsetDateTime(OffsetDateTime dateTime) {
|
||||
if (dateTime == null) {
|
||||
writeNull();
|
||||
return;
|
||||
}
|
||||
|
||||
String zoneIdStr = dateTime.getOffset().getId();
|
||||
int strlen = zoneIdStr.length();
|
||||
|
||||
int off = this.off;
|
||||
byte[] bytes = this.bytes;
|
||||
int minCapacity = off + 14 + strlen;
|
||||
int minCapacity = off + 21;
|
||||
if (minCapacity > bytes.length) {
|
||||
bytes = grow(minCapacity);
|
||||
}
|
||||
|
||||
putIntBE(bytes,
|
||||
off,
|
||||
(BC_TIMESTAMP_WITH_TIMEZONE << 24) | (dateTime.getYear() << 8) | dateTime.getMonthValue());
|
||||
putIntBE(bytes,
|
||||
off + 4,
|
||||
(dateTime.getDayOfMonth() << 24)
|
||||
| (dateTime.getHour() << 16)
|
||||
| (dateTime.getMinute() << 8)
|
||||
| dateTime.getSecond());
|
||||
|
||||
off = JSONB.IO.writeInt32(bytes, off + 8, dateTime.getNano());
|
||||
|
||||
putByte(bytes, off++, (byte) (strlen + BC_STR_ASCII_FIX_MIN));
|
||||
zoneIdStr.getBytes(0, strlen, bytes, off);
|
||||
this.off = off + strlen;
|
||||
this.off = JSONB.IO.writeOffsetDateTime(bytes, off, dateTime);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeOffsetTime(OffsetTime offsetTime) {
|
||||
if (offsetTime == null) {
|
||||
writeNull();
|
||||
return;
|
||||
int off = this.off;
|
||||
byte[] bytes = this.bytes;
|
||||
int minCapacity = off + 21;
|
||||
if (minCapacity > bytes.length) {
|
||||
bytes = grow(minCapacity);
|
||||
}
|
||||
|
||||
writeOffsetDateTime(
|
||||
OffsetDateTime.of(DateUtils.LOCAL_DATE_19700101, offsetTime.toLocalTime(), offsetTime.getOffset())
|
||||
);
|
||||
this.off = JSONB.IO.writeOffsetTime(bytes, off, offsetTime);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeInstant(Instant instant) {
|
||||
if (instant == null) {
|
||||
writeNull();
|
||||
return;
|
||||
}
|
||||
|
||||
int off = this.off;
|
||||
byte[] bytes = this.bytes;
|
||||
if (off + 15 > bytes.length) {
|
||||
bytes = grow(off + 15);
|
||||
}
|
||||
|
||||
putByte(bytes, off, BC_TIMESTAMP);
|
||||
off = JSONB.IO.writeInt64(bytes, off + 1, instant.getEpochSecond());
|
||||
this.off = JSONB.IO.writeInt32(bytes, off, instant.getNano());
|
||||
this.off = JSONB.IO.writeInstant(bytes, off, instant);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeUUID(UUID value) {
|
||||
if (value == null) {
|
||||
writeNull();
|
||||
return;
|
||||
}
|
||||
|
||||
int off = this.off;
|
||||
byte[] bytes = this.bytes;
|
||||
if (off + 18 > bytes.length) {
|
||||
bytes = grow(off + 18);
|
||||
}
|
||||
|
||||
putShortLE(bytes, off, (short) ((BC_BINARY & 0xFF) | ((BC_INT32_NUM_16 & 0xFF) << 8)));
|
||||
putLongBE(bytes, off + 2, value.getMostSignificantBits());
|
||||
putLongBE(bytes, off + 10, value.getLeastSignificantBits());
|
||||
this.off = off + 18;
|
||||
this.off = JSONB.IO.writeUUID(bytes, off, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -1570,16 +1487,13 @@ final class JSONWriterJSONB
|
||||
|
||||
@Override
|
||||
public void writeBool(boolean[] values) {
|
||||
if (values == null) {
|
||||
writeNull();
|
||||
return;
|
||||
int off = this.off;
|
||||
byte[] bytes = this.bytes;
|
||||
int minCapacity = off + (values == null ? 1 : (5 + values.length));
|
||||
if (minCapacity > bytes.length) {
|
||||
bytes = grow(minCapacity);
|
||||
}
|
||||
|
||||
startArray(values.length);
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
writeBool(values[i]);
|
||||
}
|
||||
endArray();
|
||||
this.off = JSONB.IO.writeBoolean(bytes, off, values);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -2,6 +2,7 @@ package com.alibaba.fastjson2;
|
||||
|
||||
import com.alibaba.fastjson2.util.IOUtils;
|
||||
import com.alibaba.fastjson2.util.NumberUtils;
|
||||
import com.alibaba.fastjson2.util.StringUtils;
|
||||
import com.alibaba.fastjson2.writer.ObjectWriter;
|
||||
import sun.misc.Unsafe;
|
||||
|
||||
@ -20,7 +21,6 @@ import java.util.UUID;
|
||||
|
||||
import static com.alibaba.fastjson2.JSONFactory.*;
|
||||
import static com.alibaba.fastjson2.JSONWriter.Feature.*;
|
||||
import static com.alibaba.fastjson2.JSONWriterUTF8.noneEscaped;
|
||||
import static com.alibaba.fastjson2.util.IOUtils.*;
|
||||
import static com.alibaba.fastjson2.util.JDKUtils.*;
|
||||
import static com.alibaba.fastjson2.util.TypeUtils.*;
|
||||
@ -267,27 +267,26 @@ class JSONWriterUTF16
|
||||
|
||||
boolean escape = false;
|
||||
int off = this.off;
|
||||
char[] chars = this.chars;
|
||||
int minCapacity = off + value.length + 2;
|
||||
if (minCapacity >= chars.length) {
|
||||
grow(minCapacity);
|
||||
chars = grow(minCapacity);
|
||||
}
|
||||
|
||||
final int start = off;
|
||||
final char[] chars = this.chars;
|
||||
chars[off++] = quote;
|
||||
|
||||
int i = 0;
|
||||
int coff = 0;
|
||||
final long vecQuote = this.byteVectorQuote;
|
||||
final int upperBound = (value.length - i) & ~7;
|
||||
final int upperBound = (value.length - coff) & ~7;
|
||||
long vec64;
|
||||
for (; i < upperBound && noneEscaped(vec64 = getLongLE(value, i), vecQuote); i += 8) {
|
||||
for (; coff < upperBound && StringUtils.noneEscaped(vec64 = getLongLE(value, coff), vecQuote); coff += 8) {
|
||||
IOUtils.putLongLE(chars, off, expand(vec64));
|
||||
IOUtils.putLongLE(chars, off + 4, expand(vec64 >>> 32));
|
||||
off += 8;
|
||||
}
|
||||
if (!escape) {
|
||||
for (; i < value.length; i++) {
|
||||
byte c = value[i];
|
||||
for (; coff < value.length; coff++) {
|
||||
byte c = value[coff];
|
||||
if (c == '\\' || c == quote || c < ' ') {
|
||||
escape = true;
|
||||
break;
|
||||
@ -303,8 +302,12 @@ class JSONWriterUTF16
|
||||
return;
|
||||
}
|
||||
|
||||
this.off = start;
|
||||
writeStringEscape(value);
|
||||
minCapacity += value.length * 5;
|
||||
if (minCapacity >= chars.length) {
|
||||
chars = grow(minCapacity);
|
||||
}
|
||||
|
||||
this.off = StringUtils.writeLatin1EscapedRest(chars, off, value, coff, this.quote, context.features);
|
||||
}
|
||||
|
||||
static long expand(long i) {
|
||||
@ -367,7 +370,7 @@ class JSONWriterUTF16
|
||||
if (i + 8 < char_len) {
|
||||
long v0 = getLongLE(value, i << 1);
|
||||
long v1 = getLongLE(value, (i + 4) << 1);
|
||||
if (((v0 | v1) & 0xFF00FF00FF00FF00L) == 0 && noneEscaped((v0 << 8) | v1, vecQuote)) {
|
||||
if (((v0 | v1) & 0xFF00FF00FF00FF00L) == 0 && StringUtils.noneEscaped((v0 << 8) | v1, vecQuote)) {
|
||||
putLongLE(chars, off, v0);
|
||||
putLongLE(chars, off + 4, v1);
|
||||
i += 8;
|
||||
@ -543,7 +546,7 @@ class JSONWriterUTF16
|
||||
case '\b':
|
||||
case '\f':
|
||||
case '\t':
|
||||
writeEscapedChar(chars, off, ch);
|
||||
StringUtils.writeEscapedChar(chars, off, ch);
|
||||
off += 2;
|
||||
break;
|
||||
case 0:
|
||||
@ -573,7 +576,7 @@ class JSONWriterUTF16
|
||||
case 29:
|
||||
case 30:
|
||||
case 31:
|
||||
writeU4Hex2(chars, off, ch);
|
||||
StringUtils.writeU4Hex2(chars, off, ch);
|
||||
off += 6;
|
||||
break;
|
||||
case '<':
|
||||
@ -581,7 +584,7 @@ class JSONWriterUTF16
|
||||
case '(':
|
||||
case ')':
|
||||
if (browserSecure) {
|
||||
writeU4HexU(chars, off, ch);
|
||||
StringUtils.writeU4HexU(chars, off, ch);
|
||||
off += 6;
|
||||
} else {
|
||||
chars[off++] = ch;
|
||||
@ -589,7 +592,7 @@ class JSONWriterUTF16
|
||||
break;
|
||||
default:
|
||||
if (escapeNoneAscii && ch > 0x007F) {
|
||||
writeU4HexU(chars, off, ch);
|
||||
StringUtils.writeU4HexU(chars, off, ch);
|
||||
off += 6;
|
||||
} else {
|
||||
chars[off++] = ch;
|
||||
@ -628,7 +631,7 @@ class JSONWriterUTF16
|
||||
case '\b':
|
||||
case '\f':
|
||||
case '\t':
|
||||
writeEscapedChar(chars, off, ch);
|
||||
StringUtils.writeEscapedChar(chars, off, ch);
|
||||
off += 2;
|
||||
break;
|
||||
case 0:
|
||||
@ -658,7 +661,7 @@ class JSONWriterUTF16
|
||||
case 29:
|
||||
case 30:
|
||||
case 31:
|
||||
writeU4Hex2(chars, off, ch);
|
||||
StringUtils.writeU4Hex2(chars, off, ch);
|
||||
off += 6;
|
||||
break;
|
||||
case '<':
|
||||
@ -666,7 +669,7 @@ class JSONWriterUTF16
|
||||
case '(':
|
||||
case ')':
|
||||
if (browserSecure) {
|
||||
writeU4HexU(chars, off, ch);
|
||||
StringUtils.writeU4HexU(chars, off, ch);
|
||||
off += 6;
|
||||
} else {
|
||||
chars[off++] = ch;
|
||||
@ -674,7 +677,7 @@ class JSONWriterUTF16
|
||||
break;
|
||||
default:
|
||||
if (escapeNoneAscii && ch > 0x007F) {
|
||||
writeU4HexU(chars, off, ch);
|
||||
StringUtils.writeU4HexU(chars, off, ch);
|
||||
off += 6;
|
||||
} else {
|
||||
chars[off++] = ch;
|
||||
@ -713,7 +716,7 @@ class JSONWriterUTF16
|
||||
case '\b':
|
||||
case '\f':
|
||||
case '\t':
|
||||
writeEscapedChar(chars, off, ch);
|
||||
StringUtils.writeEscapedChar(chars, off, ch);
|
||||
off += 2;
|
||||
break;
|
||||
case 0:
|
||||
@ -743,7 +746,7 @@ class JSONWriterUTF16
|
||||
case 29:
|
||||
case 30:
|
||||
case 31:
|
||||
writeU4Hex2(chars, off, ch);
|
||||
StringUtils.writeU4Hex2(chars, off, ch);
|
||||
off += 6;
|
||||
break;
|
||||
case '<':
|
||||
@ -751,7 +754,7 @@ class JSONWriterUTF16
|
||||
case '(':
|
||||
case ')':
|
||||
if (browserSecure) {
|
||||
writeU4HexU(chars, off, ch);
|
||||
StringUtils.writeU4HexU(chars, off, ch);
|
||||
off += 6;
|
||||
} else {
|
||||
chars[off++] = ch;
|
||||
@ -759,7 +762,7 @@ class JSONWriterUTF16
|
||||
break;
|
||||
default:
|
||||
if (escapeNoneAscii && ch > 0x007F) {
|
||||
writeU4HexU(chars, off, ch);
|
||||
StringUtils.writeU4HexU(chars, off, ch);
|
||||
off += 6;
|
||||
} else {
|
||||
chars[off++] = ch;
|
||||
@ -772,89 +775,17 @@ class JSONWriterUTF16
|
||||
}
|
||||
|
||||
protected final void writeStringEscape(byte[] str) {
|
||||
final int strlen = str.length;
|
||||
final char quote = this.quote;
|
||||
boolean escapeNoneAscii = (context.features & EscapeNoneAscii.mask) != 0;
|
||||
boolean browserSecure = (context.features & BrowserSecure.mask) != 0;
|
||||
|
||||
int off = this.off;
|
||||
ensureCapacityInternal(off + strlen * 6 + 2);
|
||||
char[] chars = this.chars;
|
||||
|
||||
final char[] chars = this.chars;
|
||||
chars[off++] = quote;
|
||||
for (int i = 0; i < str.length; i++) {
|
||||
byte b = str[i];
|
||||
char ch = (char) (b & 0xff);
|
||||
switch (ch) {
|
||||
case '"':
|
||||
case '\'':
|
||||
if (ch == quote) {
|
||||
chars[off++] = '\\';
|
||||
}
|
||||
chars[off++] = ch;
|
||||
break;
|
||||
case '\\':
|
||||
case '\r':
|
||||
case '\n':
|
||||
case '\b':
|
||||
case '\f':
|
||||
case '\t':
|
||||
writeEscapedChar(chars, off, ch);
|
||||
off += 2;
|
||||
break;
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
case 5:
|
||||
case 6:
|
||||
case 7:
|
||||
case 11:
|
||||
case 14:
|
||||
case 15:
|
||||
case 16:
|
||||
case 17:
|
||||
case 18:
|
||||
case 19:
|
||||
case 20:
|
||||
case 21:
|
||||
case 22:
|
||||
case 23:
|
||||
case 24:
|
||||
case 25:
|
||||
case 26:
|
||||
case 27:
|
||||
case 28:
|
||||
case 29:
|
||||
case 30:
|
||||
case 31:
|
||||
writeU4Hex2(chars, off, ch);
|
||||
off += 6;
|
||||
break;
|
||||
case '<':
|
||||
case '>':
|
||||
case '(':
|
||||
case ')':
|
||||
if (browserSecure) {
|
||||
writeU4HexU(chars, off, ch);
|
||||
off += 6;
|
||||
} else {
|
||||
chars[off++] = ch;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (escapeNoneAscii && ch > 0x007F) {
|
||||
writeU4HexU(chars, off, ch);
|
||||
off += 6;
|
||||
} else {
|
||||
chars[off++] = ch;
|
||||
}
|
||||
break;
|
||||
}
|
||||
int minCapacity = off + str.length * 6 + 2;
|
||||
if (minCapacity >= chars.length) {
|
||||
chars = grow(minCapacity);
|
||||
}
|
||||
chars[off] = quote;
|
||||
this.off = off + 1;
|
||||
|
||||
char quote = this.quote;
|
||||
chars[off++] = quote;
|
||||
this.off = StringUtils.writeLatin1EscapedRest(chars, off, str, 0, quote, context.features);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -895,7 +826,7 @@ class JSONWriterUTF16
|
||||
case '\b':
|
||||
case '\f':
|
||||
case '\t':
|
||||
writeEscapedChar(chars, off, ch);
|
||||
StringUtils.writeEscapedChar(chars, off, ch);
|
||||
off += 2;
|
||||
break;
|
||||
case 0:
|
||||
@ -925,12 +856,12 @@ class JSONWriterUTF16
|
||||
case 29:
|
||||
case 30:
|
||||
case 31:
|
||||
writeU4Hex2(chars, off, ch);
|
||||
StringUtils.writeU4Hex2(chars, off, ch);
|
||||
off += 6;
|
||||
break;
|
||||
default:
|
||||
if (escapeNoneAscii && ch > 0x007F) {
|
||||
writeU4HexU(chars, off, ch);
|
||||
StringUtils.writeU4HexU(chars, off, ch);
|
||||
off += 6;
|
||||
} else {
|
||||
chars[off++] = ch;
|
||||
@ -1251,7 +1182,7 @@ class JSONWriterUTF16
|
||||
case '\b':
|
||||
case '\f':
|
||||
case '\t':
|
||||
writeEscapedChar(chars, off, ch);
|
||||
StringUtils.writeEscapedChar(chars, off, ch);
|
||||
off += 2;
|
||||
break;
|
||||
case 0:
|
||||
@ -2078,14 +2009,13 @@ class JSONWriterUTF16
|
||||
@Override
|
||||
public final void writeInt64(long i) {
|
||||
long features = context.features;
|
||||
boolean writeAsString = isWriteAsString(i, features);
|
||||
int off = this.off;
|
||||
int minCapacity = off + 23;
|
||||
char[] chars = this.chars;
|
||||
if (minCapacity > chars.length) {
|
||||
chars = grow(minCapacity);
|
||||
}
|
||||
|
||||
boolean writeAsString = isWriteAsString(i, features);
|
||||
if (writeAsString) {
|
||||
chars[off++] = quote;
|
||||
}
|
||||
@ -2997,7 +2927,7 @@ class JSONWriterUTF16
|
||||
if (i + 8 < char_len) {
|
||||
long v0 = getLongLE(value, i);
|
||||
long v1 = getLongLE(value, i + 4);
|
||||
if (((v0 | v1) & 0xFF00FF00FF00FF00L) == 0 && noneEscaped((v0 << 8) | v1, vecQuote)) {
|
||||
if (((v0 | v1) & 0xFF00FF00FF00FF00L) == 0 && StringUtils.noneEscaped((v0 << 8) | v1, vecQuote)) {
|
||||
putLongLE(chars, off, v0);
|
||||
putLongLE(chars, off + 4, v1);
|
||||
i += 8;
|
||||
@ -3086,46 +3016,4 @@ class JSONWriterUTF16
|
||||
}
|
||||
this.off = off;
|
||||
}
|
||||
|
||||
private static final int U2;
|
||||
private static final long U4;
|
||||
private static final int[] ESCAPED_CHARS;
|
||||
static {
|
||||
{
|
||||
char[] bytes = "\\u00".toCharArray();
|
||||
U2 = UNSAFE.getInt(bytes, ARRAY_BYTE_BASE_OFFSET);
|
||||
U4 = UNSAFE.getLong(bytes, ARRAY_BYTE_BASE_OFFSET);
|
||||
}
|
||||
{
|
||||
char[] mapping = new char[] {
|
||||
'\\', '\\',
|
||||
'\n', 'n',
|
||||
'\r', 'r',
|
||||
'\f', 'f',
|
||||
'\b', 'b',
|
||||
'\t', 't'
|
||||
};
|
||||
char[] buf = {'\\', '\0'};
|
||||
int[] shorts = new int[128];
|
||||
for (int i = 0; i < mapping.length; i += 2) {
|
||||
buf[1] = mapping[i + 1];
|
||||
shorts[mapping[i]] = IOUtils.getIntUnaligned(buf, 0);
|
||||
}
|
||||
ESCAPED_CHARS = shorts;
|
||||
}
|
||||
}
|
||||
|
||||
static void writeEscapedChar(char[] chars, int off, int c0) {
|
||||
IOUtils.putIntUnaligned(chars, off, ESCAPED_CHARS[c0 & 0x7f]);
|
||||
}
|
||||
|
||||
static void writeU4Hex2(char[] chars, int off, int c) {
|
||||
IOUtils.putLongUnaligned(chars, off, U4);
|
||||
IOUtils.putIntLE(chars, off + 4, utf16Hex2(c));
|
||||
}
|
||||
|
||||
static void writeU4HexU(char[] chars, int off, int c) {
|
||||
IOUtils.putIntUnaligned(chars, off, U2);
|
||||
IOUtils.putLongLE(chars, off + 2, utf16Hex4U(c));
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -67,6 +67,7 @@ public class ASMUtils {
|
||||
public static final String TYPE_JSON_WRITER = JSONWriter.class.getName().replace('.', '/');
|
||||
public static final String TYPE_JSONB_IO = JSONB.IO.class.getName().replace('.', '/');
|
||||
public static final String TYPE_FIELD_WRITER = FieldWriter.class.getName().replace('.', '/');
|
||||
public static final String TYPE_IO_UTILS = IOUtils.class.getName().replace('.', '/');
|
||||
public static final String TYPE_OBJECT = "java/lang/Object";
|
||||
|
||||
public static final String DESC_FIELD_WRITER = 'L' + FieldWriter.class.getName().replace('.', '/') + ';';
|
||||
|
@ -874,6 +874,11 @@ class Frame {
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Opcodes.IASTORE:
|
||||
case Opcodes.BASTORE:
|
||||
case Opcodes.CASTORE:
|
||||
pop(3);
|
||||
break;
|
||||
case Opcodes.POP:
|
||||
case Opcodes.IFEQ:
|
||||
case Opcodes.IFNE:
|
||||
@ -969,6 +974,12 @@ class Frame {
|
||||
case Opcodes.IINC:
|
||||
setLocal(arg, INTEGER);
|
||||
break;
|
||||
case Opcodes.I2L:
|
||||
case Opcodes.F2L:
|
||||
pop(1);
|
||||
push(LONG);
|
||||
push(TOP);
|
||||
break;
|
||||
case Opcodes.F2I:
|
||||
case Opcodes.ARRAYLENGTH:
|
||||
case Opcodes.INSTANCEOF:
|
||||
|
@ -162,7 +162,111 @@ public final class MethodWriter {
|
||||
// Implementation of the MethodVisitor abstract class
|
||||
// -----------------------------------------------------------------------------------------------
|
||||
|
||||
public void visitInsn(final int opcode) {
|
||||
public void return_() {
|
||||
visitInsn(Opcodes.RETURN);
|
||||
}
|
||||
|
||||
public void areturn() {
|
||||
visitInsn(Opcodes.ARETURN);
|
||||
}
|
||||
|
||||
public void iconst_0() {
|
||||
visitInsn(Opcodes.ICONST_0);
|
||||
}
|
||||
|
||||
public void iconst_1() {
|
||||
visitInsn(Opcodes.ICONST_1);
|
||||
}
|
||||
|
||||
public void iconst_2() {
|
||||
visitInsn(Opcodes.ICONST_2);
|
||||
}
|
||||
|
||||
public void iconst_3() {
|
||||
visitInsn(Opcodes.ICONST_3);
|
||||
}
|
||||
|
||||
public void iconst_4() {
|
||||
visitInsn(Opcodes.ICONST_4);
|
||||
}
|
||||
|
||||
public void iconst_5() {
|
||||
visitInsn(Opcodes.ICONST_5);
|
||||
}
|
||||
|
||||
public void iconst_m1() {
|
||||
visitInsn(Opcodes.ICONST_M1);
|
||||
}
|
||||
|
||||
public void lconst_0() {
|
||||
visitInsn(Opcodes.LCONST_0);
|
||||
}
|
||||
|
||||
public void lcmp() {
|
||||
visitInsn(Opcodes.LCMP);
|
||||
}
|
||||
|
||||
public void land() {
|
||||
visitInsn(Opcodes.LAND);
|
||||
}
|
||||
|
||||
public void iadd() {
|
||||
visitInsn(Opcodes.IADD);
|
||||
}
|
||||
|
||||
public void bastore() {
|
||||
visitInsn(Opcodes.BASTORE);
|
||||
}
|
||||
|
||||
public void castore() {
|
||||
visitInsn(Opcodes.CASTORE);
|
||||
}
|
||||
|
||||
public void aconst_null() {
|
||||
visitInsn(Opcodes.ACONST_NULL);
|
||||
}
|
||||
|
||||
public void ixor() {
|
||||
visitInsn(Opcodes.IXOR);
|
||||
}
|
||||
|
||||
public void ineg() {
|
||||
visitInsn(Opcodes.INEG);
|
||||
}
|
||||
|
||||
public void lor() {
|
||||
visitInsn(Opcodes.LOR);
|
||||
}
|
||||
|
||||
public void swap() {
|
||||
visitInsn(Opcodes.SWAP);
|
||||
}
|
||||
|
||||
public void arraylength() {
|
||||
visitInsn(Opcodes.ARRAYLENGTH);
|
||||
}
|
||||
|
||||
public void l2i() {
|
||||
visitInsn(Opcodes.L2I);
|
||||
}
|
||||
|
||||
public void i2l() {
|
||||
visitInsn(Opcodes.I2L);
|
||||
}
|
||||
|
||||
public void lxor() {
|
||||
visitInsn(Opcodes.LXOR);
|
||||
}
|
||||
|
||||
public void lushr() {
|
||||
visitInsn(Opcodes.LUSHR);
|
||||
}
|
||||
|
||||
public void aaload() {
|
||||
visitInsn(Opcodes.AALOAD);
|
||||
}
|
||||
|
||||
private void visitInsn(final int opcode) {
|
||||
lastBytecodeOffset = code.length;
|
||||
// Add the instruction to the bytecode of the method.
|
||||
code.putByte(opcode);
|
||||
@ -175,7 +279,15 @@ public final class MethodWriter {
|
||||
}
|
||||
}
|
||||
|
||||
public void visitIntInsn(final int opcode, final int operand) {
|
||||
public void sipush(final int operand) {
|
||||
visitIntInsn(Opcodes.SIPUSH, operand);
|
||||
}
|
||||
|
||||
public void bipush(final int operand) {
|
||||
visitIntInsn(Opcodes.BIPUSH, operand);
|
||||
}
|
||||
|
||||
private void visitIntInsn(final int opcode, final int operand) {
|
||||
lastBytecodeOffset = code.length;
|
||||
// Add the instruction to the bytecode of the method.
|
||||
if (opcode == Opcodes.SIPUSH) {
|
||||
@ -189,6 +301,78 @@ public final class MethodWriter {
|
||||
}
|
||||
}
|
||||
|
||||
public void loadLocal(Class<?> cls, int var) {
|
||||
if (cls == byte.class || cls == short.class || cls == int.class || cls == char.class || cls == boolean.class) {
|
||||
visitVarInsn(Opcodes.ILOAD, var);
|
||||
} else if (cls == long.class) {
|
||||
visitVarInsn(Opcodes.LLOAD, var);
|
||||
} else if (cls == float.class) {
|
||||
visitVarInsn(Opcodes.FLOAD, var);
|
||||
} else if (cls == double.class) {
|
||||
visitVarInsn(Opcodes.DLOAD, var);
|
||||
} else {
|
||||
visitVarInsn(Opcodes.ALOAD, var);
|
||||
}
|
||||
}
|
||||
|
||||
public void storeLocal(Class<?> cls, int var) {
|
||||
if (cls == byte.class || cls == short.class || cls == int.class || cls == char.class || cls == boolean.class) {
|
||||
visitVarInsn(Opcodes.ISTORE, var);
|
||||
} else if (cls == long.class) {
|
||||
visitVarInsn(Opcodes.LSTORE, var);
|
||||
} else if (cls == float.class) {
|
||||
visitVarInsn(Opcodes.FSTORE, var);
|
||||
} else if (cls == double.class) {
|
||||
visitVarInsn(Opcodes.DSTORE, var);
|
||||
} else {
|
||||
visitVarInsn(Opcodes.ASTORE, var);
|
||||
}
|
||||
}
|
||||
|
||||
public void aload(final int var) {
|
||||
visitVarInsn(Opcodes.ALOAD, var);
|
||||
}
|
||||
|
||||
public void astore(final int var) {
|
||||
visitVarInsn(Opcodes.ASTORE, var);
|
||||
}
|
||||
|
||||
public void iload(final int var) {
|
||||
visitVarInsn(Opcodes.ILOAD, var);
|
||||
}
|
||||
|
||||
public void istore(final int var) {
|
||||
visitVarInsn(Opcodes.ISTORE, var);
|
||||
}
|
||||
|
||||
public void lload(final int var) {
|
||||
visitVarInsn(Opcodes.LLOAD, var);
|
||||
}
|
||||
|
||||
public void lstore(final int var) {
|
||||
visitVarInsn(Opcodes.LSTORE, var);
|
||||
}
|
||||
|
||||
public void fstore(final int var) {
|
||||
visitVarInsn(Opcodes.FSTORE, var);
|
||||
}
|
||||
|
||||
public void dstore(final int var) {
|
||||
visitVarInsn(Opcodes.DSTORE, var);
|
||||
}
|
||||
|
||||
public void dup() {
|
||||
visitInsn(Opcodes.DUP);
|
||||
}
|
||||
|
||||
public void dup2() {
|
||||
visitInsn(Opcodes.DUP2);
|
||||
}
|
||||
|
||||
public void pop() {
|
||||
visitInsn(Opcodes.POP);
|
||||
}
|
||||
|
||||
public void visitVarInsn(final int opcode, final int var) {
|
||||
lastBytecodeOffset = code.length;
|
||||
// Add the instruction to the bytecode of the method.
|
||||
@ -224,7 +408,19 @@ public final class MethodWriter {
|
||||
}
|
||||
}
|
||||
|
||||
public void visitTypeInsn(final int opcode, final String type) {
|
||||
public void checkcast(final String type) {
|
||||
visitTypeInsn(Opcodes.CHECKCAST, type);
|
||||
}
|
||||
|
||||
public void new_(final String type) {
|
||||
visitTypeInsn(Opcodes.NEW, type);
|
||||
}
|
||||
|
||||
public void instanceOf(final String type) {
|
||||
visitTypeInsn(Opcodes.INSTANCEOF, type);
|
||||
}
|
||||
|
||||
private void visitTypeInsn(final int opcode, final String type) {
|
||||
lastBytecodeOffset = code.length;
|
||||
// Add the instruction to the bytecode of the method.
|
||||
Symbol typeSymbol = symbolTable.addConstantUtf8Reference(/*CONSTANT_CLASS_TAG*/ 7, type);
|
||||
@ -235,7 +431,19 @@ public final class MethodWriter {
|
||||
}
|
||||
}
|
||||
|
||||
public void visitFieldInsn(
|
||||
public void getfield(final String owner, final String name, final String descriptor) {
|
||||
visitFieldInsn(Opcodes.GETFIELD, owner, name, descriptor);
|
||||
}
|
||||
|
||||
public void putfield(final String owner, final String name, final String descriptor) {
|
||||
visitFieldInsn(Opcodes.PUTFIELD, owner, name, descriptor);
|
||||
}
|
||||
|
||||
public void getstatic(final String owner, final String name, final String descriptor) {
|
||||
visitFieldInsn(Opcodes.GETSTATIC, owner, name, descriptor);
|
||||
}
|
||||
|
||||
private void visitFieldInsn(
|
||||
final int opcode, final String owner, final String name, final String descriptor) {
|
||||
lastBytecodeOffset = code.length;
|
||||
// Add the instruction to the bytecode of the method.
|
||||
@ -247,7 +455,27 @@ public final class MethodWriter {
|
||||
}
|
||||
}
|
||||
|
||||
public void visitMethodInsn(
|
||||
public void invokestatic(final String owner, final String name, final String descriptor) {
|
||||
visitMethodInsn(Opcodes.INVOKESTATIC, owner, name, descriptor, false);
|
||||
}
|
||||
|
||||
public void invokestatic(final String owner, final String name, final String descriptor, final boolean isInterface) {
|
||||
visitMethodInsn(Opcodes.INVOKESTATIC, owner, name, descriptor, isInterface);
|
||||
}
|
||||
|
||||
public void invokevirtual(final String owner, final String name, final String descriptor) {
|
||||
visitMethodInsn(Opcodes.INVOKEVIRTUAL, owner, name, descriptor, false);
|
||||
}
|
||||
|
||||
public void invokeinterface(final String owner, final String name, final String descriptor) {
|
||||
visitMethodInsn(Opcodes.INVOKEINTERFACE, owner, name, descriptor, true);
|
||||
}
|
||||
|
||||
public void invokespecial(final String owner, final String name, final String descriptor) {
|
||||
visitMethodInsn(Opcodes.INVOKESPECIAL, owner, name, descriptor, false);
|
||||
}
|
||||
|
||||
private void visitMethodInsn(
|
||||
final int opcode,
|
||||
final String owner,
|
||||
final String name,
|
||||
@ -273,7 +501,55 @@ public final class MethodWriter {
|
||||
}
|
||||
}
|
||||
|
||||
public void visitJumpInsn(final int opcode, final Label label) {
|
||||
public void ifeq(final Label label) {
|
||||
visitJumpInsn(Opcodes.IFEQ, label);
|
||||
}
|
||||
|
||||
public void ifne(final Label label) {
|
||||
visitJumpInsn(Opcodes.IFNE, label);
|
||||
}
|
||||
|
||||
public void ifge(final Label label) {
|
||||
visitJumpInsn(Opcodes.IFGE, label);
|
||||
}
|
||||
|
||||
public void ifnull(final Label label) {
|
||||
visitJumpInsn(Opcodes.IFNULL, label);
|
||||
}
|
||||
|
||||
public void if_icmpeq(final Label label) {
|
||||
visitJumpInsn(Opcodes.IF_ICMPEQ, label);
|
||||
}
|
||||
|
||||
public void if_acmpeq(final Label label) {
|
||||
visitJumpInsn(Opcodes.IF_ACMPEQ, label);
|
||||
}
|
||||
|
||||
public void if_acmpne(final Label label) {
|
||||
visitJumpInsn(Opcodes.IF_ACMPNE, label);
|
||||
}
|
||||
|
||||
public void goto_(final Label label) {
|
||||
visitJumpInsn(Opcodes.GOTO, label);
|
||||
}
|
||||
|
||||
public void ifnonnull(final Label label) {
|
||||
visitJumpInsn(Opcodes.IFNONNULL, label);
|
||||
}
|
||||
|
||||
public void if_icmpge(final Label label) {
|
||||
visitJumpInsn(Opcodes.IF_ICMPGE, label);
|
||||
}
|
||||
|
||||
public void if_icmple(final Label label) {
|
||||
visitJumpInsn(Opcodes.IF_ICMPLE, label);
|
||||
}
|
||||
|
||||
public void if_icmpne(final Label label) {
|
||||
visitJumpInsn(Opcodes.IF_ICMPNE, label);
|
||||
}
|
||||
|
||||
private void visitJumpInsn(final int opcode, final Label label) {
|
||||
lastBytecodeOffset = code.length;
|
||||
// Add the instruction to the bytecode of the method.
|
||||
// Compute the 'base' opcode, i.e. GOTO or JSR if opcode is GOTO_W or JSR_W, otherwise opcode.
|
||||
|
@ -90,6 +90,9 @@ public interface Opcodes {
|
||||
int FSTORE = 56; // -
|
||||
int DSTORE = 57; // -
|
||||
int ASTORE = 58; // -
|
||||
int IASTORE = 79; // visitInsn
|
||||
int BASTORE = 84; // -
|
||||
int CASTORE = 85; // -
|
||||
int POP = 87; // visitInsn
|
||||
int POP2 = 88; // -
|
||||
int DUP = 89; // -
|
||||
@ -122,8 +125,10 @@ public interface Opcodes {
|
||||
int IXOR = 130; // -
|
||||
int LXOR = 131; // -
|
||||
int IINC = 132; // visitIincInsn
|
||||
int L2I = 136; // visitInsn
|
||||
int I2L = 133; // visitInsn
|
||||
int L2I = 136; //
|
||||
int F2I = 139; // -
|
||||
int F2L = 140; // -
|
||||
int D2I = 142; // -
|
||||
int D2L = 143; // -
|
||||
int I2B = 145; // -
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1620,6 +1620,10 @@ public class IOUtils {
|
||||
return ch >= '0' && ch <= '9';
|
||||
}
|
||||
|
||||
public static short getShortUnaligned(byte[] bytes, int offset) {
|
||||
return UNSAFE.getShort(bytes, ARRAY_BYTE_BASE_OFFSET + offset);
|
||||
}
|
||||
|
||||
public static short getShortBE(byte[] bytes, int offset) {
|
||||
return convEndian(true,
|
||||
UNSAFE.getShort(bytes, ARRAY_BYTE_BASE_OFFSET + offset));
|
||||
@ -1794,6 +1798,22 @@ public class IOUtils {
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean isASCII(String str) {
|
||||
if (STRING_VALUE != null && STRING_CODER != null) {
|
||||
return STRING_CODER.applyAsInt(str) == 0 && isASCII(STRING_VALUE.apply(str));
|
||||
}
|
||||
for (int i = 0, len = str.length(); i < len; ++i) {
|
||||
if (str.charAt(i) > 0x7F) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean isASCII(byte[] bytes) {
|
||||
return isASCII(bytes, 0, bytes.length);
|
||||
}
|
||||
|
||||
public static boolean isASCII(byte[] bytes, int off, int len) {
|
||||
int end = off + len;
|
||||
int upperBound = off + (len & ~7);
|
||||
|
@ -166,8 +166,7 @@ public final class NumberUtils {
|
||||
* <p> Using the difference estimation method </p>
|
||||
* <p> The output may not be the shortest, but the general result is correct </p>
|
||||
*
|
||||
* @param doubleValue > 0
|
||||
* @return
|
||||
* @param doubleValue > 0
|
||||
*/
|
||||
public static Scientific doubleToScientific(double doubleValue) {
|
||||
if (doubleValue == Double.MIN_VALUE) {
|
||||
|
421
core/src/main/java/com/alibaba/fastjson2/util/StringUtils.java
Normal file
421
core/src/main/java/com/alibaba/fastjson2/util/StringUtils.java
Normal file
@ -0,0 +1,421 @@
|
||||
package com.alibaba.fastjson2.util;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import static com.alibaba.fastjson2.JSONWriter.Feature.BrowserSecure;
|
||||
import static com.alibaba.fastjson2.JSONWriter.Feature.EscapeNoneAscii;
|
||||
import static com.alibaba.fastjson2.util.IOUtils.*;
|
||||
import static com.alibaba.fastjson2.util.IOUtils.hex4U;
|
||||
import static com.alibaba.fastjson2.util.JDKUtils.ARRAY_BYTE_BASE_OFFSET;
|
||||
import static com.alibaba.fastjson2.util.JDKUtils.UNSAFE;
|
||||
|
||||
public class StringUtils {
|
||||
protected static final long MASK_ESCAPE_NONE_ASCII = EscapeNoneAscii.mask;
|
||||
protected static final long MASK_BROWSER_SECURE = BrowserSecure.mask;
|
||||
public static int writeLatin1(byte[] bytes, int off, byte[] value, byte quote) {
|
||||
int strlen = value.length;
|
||||
bytes[off] = quote;
|
||||
System.arraycopy(value, 0, bytes, off + 1, strlen);
|
||||
bytes[off + strlen + 1] = quote;
|
||||
return off + strlen + 2;
|
||||
}
|
||||
|
||||
public static int writeLatin1Escaped(byte[] bytes, int off, byte[] values, byte quote, long features) {
|
||||
final boolean browserSecure = (features & MASK_BROWSER_SECURE) != 0;
|
||||
bytes[off++] = quote;
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
byte ch = values[i];
|
||||
switch (ch) {
|
||||
case '\\':
|
||||
case '\n':
|
||||
case '\r':
|
||||
case '\f':
|
||||
case '\b':
|
||||
case '\t':
|
||||
writeEscapedChar(bytes, off, ch);
|
||||
off += 2;
|
||||
break;
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
case 5:
|
||||
case 6:
|
||||
case 7:
|
||||
case 11:
|
||||
case 14:
|
||||
case 15:
|
||||
case 16:
|
||||
case 17:
|
||||
case 18:
|
||||
case 19:
|
||||
case 20:
|
||||
case 21:
|
||||
case 22:
|
||||
case 23:
|
||||
case 24:
|
||||
case 25:
|
||||
case 26:
|
||||
case 27:
|
||||
case 28:
|
||||
case 29:
|
||||
case 30:
|
||||
case 31:
|
||||
writeU4Hex2(bytes, off, ch);
|
||||
off += 6;
|
||||
break;
|
||||
case '<':
|
||||
case '>':
|
||||
case '(':
|
||||
case ')':
|
||||
if (browserSecure) {
|
||||
writeU4HexU(bytes, off, ch);
|
||||
off += 6;
|
||||
} else {
|
||||
bytes[off++] = ch;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (ch == quote) {
|
||||
putByte(bytes, off, (byte) '\\');
|
||||
bytes[off + 1] = quote;
|
||||
off += 2;
|
||||
} else if (ch < 0) {
|
||||
// latin
|
||||
int c = ch & 0xFF;
|
||||
putByte(bytes, off, (byte) (0xc0 | (c >> 6)));
|
||||
putByte(bytes, off + 1, (byte) (0x80 | (c & 0x3f)));
|
||||
off += 2;
|
||||
} else {
|
||||
putByte(bytes, off++, ch);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
bytes[off] = quote;
|
||||
return off + 1;
|
||||
}
|
||||
|
||||
public static int writeLatin1EscapedRest(char[] chars, int off, byte[] str, int coff, char quote, long features) {
|
||||
boolean escapeNoneAscii = (features & EscapeNoneAscii.mask) != 0;
|
||||
boolean browserSecure = (features & BrowserSecure.mask) != 0;
|
||||
|
||||
for (int i = coff; i < str.length; i++) {
|
||||
byte b = str[i];
|
||||
char ch = (char) (b & 0xff);
|
||||
switch (ch) {
|
||||
case '"':
|
||||
case '\'':
|
||||
if (ch == quote) {
|
||||
chars[off++] = '\\';
|
||||
}
|
||||
chars[off++] = ch;
|
||||
break;
|
||||
case '\\':
|
||||
case '\r':
|
||||
case '\n':
|
||||
case '\b':
|
||||
case '\f':
|
||||
case '\t':
|
||||
writeEscapedChar(chars, off, ch);
|
||||
off += 2;
|
||||
break;
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
case 5:
|
||||
case 6:
|
||||
case 7:
|
||||
case 11:
|
||||
case 14:
|
||||
case 15:
|
||||
case 16:
|
||||
case 17:
|
||||
case 18:
|
||||
case 19:
|
||||
case 20:
|
||||
case 21:
|
||||
case 22:
|
||||
case 23:
|
||||
case 24:
|
||||
case 25:
|
||||
case 26:
|
||||
case 27:
|
||||
case 28:
|
||||
case 29:
|
||||
case 30:
|
||||
case 31:
|
||||
writeU4Hex2(chars, off, ch);
|
||||
off += 6;
|
||||
break;
|
||||
case '<':
|
||||
case '>':
|
||||
case '(':
|
||||
case ')':
|
||||
if (browserSecure) {
|
||||
writeU4HexU(chars, off, ch);
|
||||
off += 6;
|
||||
} else {
|
||||
chars[off++] = ch;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (escapeNoneAscii && ch > 0x007F) {
|
||||
writeU4HexU(chars, off, ch);
|
||||
off += 6;
|
||||
} else {
|
||||
chars[off++] = ch;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
chars[off] = quote;
|
||||
return off + 1;
|
||||
}
|
||||
|
||||
public static int writeUTF16(byte[] bytes, int off, byte[] value, byte quote, long features) {
|
||||
boolean escapeNoneAscii = (features & MASK_ESCAPE_NONE_ASCII) != 0;
|
||||
boolean browserSecure = (features & MASK_BROWSER_SECURE) != 0;
|
||||
|
||||
putByte(bytes, off++, quote);
|
||||
|
||||
int coff = 0, char_len = value.length >> 1;
|
||||
while (coff < char_len) {
|
||||
char c = IOUtils.getChar(value, coff++);
|
||||
if (c < 0x80) {
|
||||
switch (c) {
|
||||
case '\\':
|
||||
case '\n':
|
||||
case '\r':
|
||||
case '\f':
|
||||
case '\b':
|
||||
case '\t':
|
||||
writeEscapedChar(bytes, off, c);
|
||||
off += 2;
|
||||
break;
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
case 5:
|
||||
case 6:
|
||||
case 7:
|
||||
case 11:
|
||||
case 14:
|
||||
case 15:
|
||||
case 16:
|
||||
case 17:
|
||||
case 18:
|
||||
case 19:
|
||||
case 20:
|
||||
case 21:
|
||||
case 22:
|
||||
case 23:
|
||||
case 24:
|
||||
case 25:
|
||||
case 26:
|
||||
case 27:
|
||||
case 28:
|
||||
case 29:
|
||||
case 30:
|
||||
case 31:
|
||||
writeU4Hex2(bytes, off, c);
|
||||
off += 6;
|
||||
break;
|
||||
case '<':
|
||||
case '>':
|
||||
case '(':
|
||||
case ')':
|
||||
if (browserSecure) {
|
||||
writeU4HexU(bytes, off, c);
|
||||
off += 6;
|
||||
} else {
|
||||
putByte(bytes, off++, (byte) c);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (c == quote) {
|
||||
putByte(bytes, off, (byte) '\\');
|
||||
putByte(bytes, off + 1, (byte) quote);
|
||||
off += 2;
|
||||
} else {
|
||||
putByte(bytes, off++, (byte) c);
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (c < 0x800) {
|
||||
// 2 bytes, 11 bits
|
||||
putByte(bytes, off, (byte) (0xc0 | (c >> 6)));
|
||||
putByte(bytes, off + 1, (byte) (0x80 | (c & 0x3f)));
|
||||
off += 2;
|
||||
} else if (escapeNoneAscii) {
|
||||
writeU4HexU(bytes, off, c);
|
||||
off += 6;
|
||||
} else if (c >= '\uD800' && c < ('\uDFFF' + 1)) { //Character.isSurrogate(c) but 1.7
|
||||
final int uc;
|
||||
if (c < '\uDBFF' + 1) { // Character.isHighSurrogate(c)
|
||||
if (coff + 1 > char_len) {
|
||||
uc = -1;
|
||||
} else {
|
||||
char d = getChar(value, coff);
|
||||
// d >= '\uDC00' && d < ('\uDFFF' + 1)
|
||||
if (d >= '\uDC00' && d < ('\uDFFF' + 1)) { // Character.isLowSurrogate(d)
|
||||
coff++;
|
||||
uc = ((c << 10) + d) + (0x010000 - ('\uD800' << 10) - '\uDC00'); // Character.toCodePoint(c, d)
|
||||
} else {
|
||||
putByte(bytes, off++, (byte) '?');
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//
|
||||
// Character.isLowSurrogate(c)
|
||||
putByte(bytes, off++, (byte) '?');
|
||||
continue;
|
||||
}
|
||||
|
||||
if (uc < 0) {
|
||||
putByte(bytes, off++, (byte) '?');
|
||||
} else {
|
||||
putByte(bytes, off, (byte) (0xf0 | ((uc >> 18))));
|
||||
putByte(bytes, off + 1, (byte) (0x80 | ((uc >> 12) & 0x3f)));
|
||||
putByte(bytes, off + 2, (byte) (0x80 | ((uc >> 6) & 0x3f)));
|
||||
putByte(bytes, off + 3, (byte) (0x80 | (uc & 0x3f)));
|
||||
off += 4;
|
||||
}
|
||||
} else {
|
||||
// 3 bytes, 16 bits
|
||||
putByte(bytes, off, (byte) (0xe0 | ((c >> 12))));
|
||||
putByte(bytes, off + 1, (byte) (0x80 | ((c >> 6) & 0x3f)));
|
||||
putByte(bytes, off + 2, (byte) (0x80 | (c & 0x3f)));
|
||||
off += 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
putByte(bytes, off, quote);
|
||||
return off + 1;
|
||||
}
|
||||
|
||||
public static void writeEscapedChar(byte[] bytes, int off, int c0) {
|
||||
putShortLE(bytes, off, LATIN1.ESCAPED_CHARS[c0 & 0x7f]);
|
||||
}
|
||||
|
||||
public static void writeU4Hex2(byte[] bytes, int off, int c) {
|
||||
putIntUnaligned(bytes, off, LATIN1.U4);
|
||||
putShortLE(bytes, off + 4, hex2(c));
|
||||
}
|
||||
|
||||
public static void writeU4HexU(byte[] bytes, int off, int c) {
|
||||
putShortUnaligned(bytes, off, LATIN1.U2);
|
||||
putIntLE(bytes, off + 2, hex4U(c));
|
||||
}
|
||||
|
||||
public static void writeEscapedChar(char[] chars, int off, int c0) {
|
||||
IOUtils.putIntUnaligned(chars, off, UTF16.ESCAPED_CHARS[c0 & 0x7f]);
|
||||
}
|
||||
|
||||
public static void writeU4Hex2(char[] chars, int off, int c) {
|
||||
IOUtils.putLongUnaligned(chars, off, UTF16.U4);
|
||||
IOUtils.putIntLE(chars, off + 4, utf16Hex2(c));
|
||||
}
|
||||
|
||||
public static void writeU4HexU(char[] chars, int off, int c) {
|
||||
IOUtils.putIntUnaligned(chars, off, UTF16.U2);
|
||||
IOUtils.putLongLE(chars, off + 2, utf16Hex4U(c));
|
||||
}
|
||||
|
||||
public static boolean escaped(byte[] value, byte quote, long vecQuote) {
|
||||
int i = 0;
|
||||
final int upperBound = (value.length - i) & ~7;
|
||||
for (; i < upperBound; i += 8) {
|
||||
if (!noneEscaped(getLongUnaligned(value, i), vecQuote)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
for (; i < value.length; i++) {
|
||||
byte c = value[i];
|
||||
if (c == quote || c == '\\' || c < ' ') {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean noneEscaped(long v, long quote) {
|
||||
/*
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
byte c = (byte) data;
|
||||
if (c == (byte) quote || c == '\\' || c < ' ') {
|
||||
return false;
|
||||
}
|
||||
data >>>= 8;
|
||||
}
|
||||
return true;
|
||||
*/
|
||||
return ((v + 0x6060606060606060L) & 0x8080808080808080L) == 0x8080808080808080L // all >= 32
|
||||
&& ((v ^ quote) + 0x0101010101010101L & 0x8080808080808080L) == 0x8080808080808080L // != quote
|
||||
&& ((v ^ 0xA3A3A3A3A3A3A3A3L) + 0x0101010101010101L & 0x8080808080808080L) == 0x8080808080808080L; // != '\\'
|
||||
}
|
||||
|
||||
public static final class LATIN1 {
|
||||
private static final short U2;
|
||||
private static final int U4;
|
||||
private static final short[] ESCAPED_CHARS;
|
||||
|
||||
static {
|
||||
{
|
||||
byte[] bytes = "\\u00".getBytes(StandardCharsets.UTF_8);
|
||||
U2 = UNSAFE.getShort(bytes, ARRAY_BYTE_BASE_OFFSET);
|
||||
U4 = UNSAFE.getInt(bytes, ARRAY_BYTE_BASE_OFFSET);
|
||||
}
|
||||
{
|
||||
char slash = '\\';
|
||||
short[] shorts = new short[128];
|
||||
shorts['\\'] = (short) (slash | ('\\' << 8));
|
||||
shorts['\n'] = (short) (slash | ('n' << 8));
|
||||
shorts['\r'] = (short) (slash | ('r' << 8));
|
||||
shorts['\f'] = (short) (slash | ('f' << 8));
|
||||
shorts['\b'] = (short) (slash | ('b' << 8));
|
||||
shorts['\t'] = (short) (slash | ('t' << 8));
|
||||
ESCAPED_CHARS = shorts;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static final class UTF16 {
|
||||
private static final int U2;
|
||||
private static final long U4;
|
||||
private static final int[] ESCAPED_CHARS;
|
||||
|
||||
static {
|
||||
{
|
||||
char[] bytes = "\\u00".toCharArray();
|
||||
U2 = UNSAFE.getInt(bytes, ARRAY_BYTE_BASE_OFFSET);
|
||||
U4 = UNSAFE.getLong(bytes, ARRAY_BYTE_BASE_OFFSET);
|
||||
}
|
||||
{
|
||||
char[] mapping = new char[]{
|
||||
'\\', '\\',
|
||||
'\n', 'n',
|
||||
'\r', 'r',
|
||||
'\f', 'f',
|
||||
'\b', 'b',
|
||||
'\t', 't'
|
||||
};
|
||||
char[] buf = {'\\', '\0'};
|
||||
int[] shorts = new int[128];
|
||||
for (int i = 0; i < mapping.length; i += 2) {
|
||||
buf[1] = mapping[i + 1];
|
||||
shorts[mapping[i]] = IOUtils.getIntUnaligned(buf, 0);
|
||||
}
|
||||
ESCAPED_CHARS = shorts;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -180,6 +180,10 @@ public abstract class FieldWriter<T>
|
||||
return false;
|
||||
}
|
||||
|
||||
public int writeEnumValueJSONB(byte[] bytes, int off, Enum e, SymbolTable symbolTable, long features) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public void writeEnumJSONB(JSONWriter jsonWriter, Enum e) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
@ -200,6 +204,15 @@ public abstract class FieldWriter<T>
|
||||
jsonWriter.writeNameRaw(nameJSONB, hashCode);
|
||||
}
|
||||
|
||||
public final int writeFieldNameJSONB(byte[] bytes, int off) {
|
||||
System.arraycopy(nameJSONB, 0, bytes, off, nameJSONB.length);
|
||||
return off + nameJSONB.length;
|
||||
}
|
||||
|
||||
public final int writeFieldNameJSONB(byte[] bytes, int off, JSONWriter jsonWriter) {
|
||||
return JSONB.IO.writeNameRaw(bytes, off, nameJSONB, hashCode, jsonWriter);
|
||||
}
|
||||
|
||||
public final void writeFieldName(JSONWriter jsonWriter) {
|
||||
if (jsonWriter.jsonb) {
|
||||
SymbolTable symbolTable = jsonWriter.symbolTable;
|
||||
@ -249,6 +262,32 @@ public abstract class FieldWriter<T>
|
||||
return false;
|
||||
}
|
||||
|
||||
public int writeFieldNameSymbol(SymbolTable symbolTable) {
|
||||
int symbolTableIdentity = System.identityHashCode(symbolTable);
|
||||
|
||||
int symbol;
|
||||
if (nameSymbolCache == 0) {
|
||||
symbol = symbolTable.getOrdinalByHashCode(hashCode);
|
||||
nameSymbolCache = ((long) symbol << 32) | symbolTableIdentity;
|
||||
} else {
|
||||
if ((int) nameSymbolCache == symbolTableIdentity) {
|
||||
symbol = (int) (nameSymbolCache >> 32);
|
||||
} else {
|
||||
symbol = symbolTable.getOrdinalByHashCode(hashCode);
|
||||
nameSymbolCache = ((long) symbol << 32) | symbolTableIdentity;
|
||||
}
|
||||
}
|
||||
return symbol;
|
||||
}
|
||||
|
||||
public boolean isRefDetect(Object object, long features) {
|
||||
features |= this.features;
|
||||
return (features & ReferenceDetection.mask) != 0
|
||||
&& (features & FieldInfo.DISABLE_REFERENCE_DETECT) == 0
|
||||
&& object != null
|
||||
&& !ObjectWriterProvider.isNotReferenceDetect(object.getClass());
|
||||
}
|
||||
|
||||
public final JSONWriter.Path getRootParentPath() {
|
||||
return rootParentPath;
|
||||
}
|
||||
|
@ -53,6 +53,27 @@ class FieldWriterEnum
|
||||
utf16ValueCache = new char[enumConstants.length][];
|
||||
}
|
||||
|
||||
public final int writeEnumValueJSONB(byte[] bytes, int off, Enum e, SymbolTable symbolTable, long features) {
|
||||
if (e == null) {
|
||||
bytes[off] = JSONB.Constants.BC_NULL;
|
||||
return off + 1;
|
||||
}
|
||||
|
||||
features |= this.features;
|
||||
boolean usingOrdinal = (features & (JSONWriter.Feature.WriteEnumUsingToString.mask | JSONWriter.Feature.WriteEnumsUsingName.mask)) == 0;
|
||||
boolean usingToString = (features & JSONWriter.Feature.WriteEnumUsingToString.mask) != 0;
|
||||
String str = usingToString ? e.toString() : e.name();
|
||||
if (IOUtils.isASCII(str)) {
|
||||
return JSONB.IO.writeSymbol(bytes, off, str, symbolTable);
|
||||
}
|
||||
|
||||
if (usingOrdinal) {
|
||||
return JSONB.IO.writeInt32(bytes, off, e.ordinal());
|
||||
}
|
||||
|
||||
return JSONB.IO.writeString(bytes, off, str);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void writeEnumJSONB(JSONWriter jsonWriter, Enum e) {
|
||||
if (e == null) {
|
||||
|
@ -1,11 +1,13 @@
|
||||
package com.alibaba.fastjson2.writer;
|
||||
|
||||
import com.alibaba.fastjson2.JSONWriter;
|
||||
import com.alibaba.fastjson2.codec.FieldInfo;
|
||||
import com.alibaba.fastjson2.util.TypeUtils;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
@ -13,6 +15,9 @@ import static com.alibaba.fastjson2.JSONWriter.Feature.*;
|
||||
|
||||
abstract class FieldWriterList<T>
|
||||
extends FieldWriter<T> {
|
||||
private static final Class<?> EMPTY_LIST_CLASS = Collections.emptyList().getClass();
|
||||
private static final Class<?> EMPTY_SET_CLASS = Collections.emptySet().getClass();
|
||||
|
||||
final Type itemType;
|
||||
final Class itemClass;
|
||||
final boolean itemClassNotReferenceDetect;
|
||||
@ -384,4 +389,13 @@ abstract class FieldWriterList<T>
|
||||
|
||||
jsonWriter.writeString(list);
|
||||
}
|
||||
|
||||
public final boolean isRefDetect(Object object, long features) {
|
||||
Class<?> objectClass;
|
||||
features |= this.features;
|
||||
return (features & ReferenceDetection.mask) != 0
|
||||
&& (features & FieldInfo.DISABLE_REFERENCE_DETECT) == 0
|
||||
&& object != null
|
||||
&& ((objectClass = object.getClass()) != EMPTY_LIST_CLASS) && (objectClass != EMPTY_SET_CLASS);
|
||||
}
|
||||
}
|
||||
|
@ -129,7 +129,11 @@ public class ObjectWriterAdapter<T>
|
||||
|
||||
@Override
|
||||
public final boolean hasFilter(JSONWriter jsonWriter) {
|
||||
return hasFilter || jsonWriter.hasFilter(containsNoneFieldGetter);
|
||||
return hasFilter | jsonWriter.hasFilter(containsNoneFieldGetter);
|
||||
}
|
||||
|
||||
protected final boolean hasFilter0(JSONWriter jsonWriter) {
|
||||
return hasFilter | jsonWriter.hasFilter();
|
||||
}
|
||||
|
||||
public void setPropertyFilter(PropertyFilter propertyFilter) {
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -212,10 +212,10 @@ final class ObjectWriterImplList
|
||||
}
|
||||
|
||||
if (refDetect) {
|
||||
String refPath = jsonWriter.setPath(i, item);
|
||||
String refPath = jsonWriter.setPath0(i, item);
|
||||
if (refPath != null) {
|
||||
jsonWriter.writeReference(refPath);
|
||||
jsonWriter.popPath(item);
|
||||
jsonWriter.popPath0(item);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@ -223,7 +223,7 @@ final class ObjectWriterImplList
|
||||
itemObjectWriter.writeJSONB(jsonWriter, item, i, this.itemType, this.features);
|
||||
|
||||
if (refDetect) {
|
||||
jsonWriter.popPath(item);
|
||||
jsonWriter.popPath0(item);
|
||||
}
|
||||
}
|
||||
jsonWriter.endArray();
|
||||
|
@ -1670,6 +1670,24 @@ public class JSONWriterTest {
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_writeStringLatin1Escape() {
|
||||
String str = "1234567890\rabcde";
|
||||
byte[] bytes = str.getBytes();
|
||||
{
|
||||
JSONWriter jsonWriter = JSONWriter.ofUTF16();
|
||||
jsonWriter.writeStringLatin1(bytes);
|
||||
String json = jsonWriter.toString();
|
||||
assertEquals("\"1234567890\\rabcde\"", json);
|
||||
}
|
||||
{
|
||||
JSONWriter jsonWriter = JSONWriter.ofUTF8();
|
||||
jsonWriter.writeStringLatin1(bytes);
|
||||
String json = jsonWriter.toString();
|
||||
assertEquals("\"1234567890\\rabcde\"", json);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_writeStringLatin1() {
|
||||
Map<String, String> map = new LinkedHashMap<>();
|
||||
|
@ -2,6 +2,7 @@ package com.alibaba.fastjson2;
|
||||
|
||||
import com.alibaba.fastjson2.annotation.JSONField;
|
||||
import com.alibaba.fastjson2.util.IOUtils;
|
||||
import com.alibaba.fastjson2.util.StringUtils;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
@ -1244,15 +1245,15 @@ public class JSONWriterUTF16Test {
|
||||
@Test
|
||||
public void write2() {
|
||||
char[] chars = new char[4];
|
||||
JSONWriterUTF16.writeEscapedChar(chars, 0, '\r');
|
||||
JSONWriterUTF16.writeEscapedChar(chars, 2, '\n');
|
||||
StringUtils.writeEscapedChar(chars, 0, '\r');
|
||||
StringUtils.writeEscapedChar(chars, 2, '\n');
|
||||
assertEquals("\\r\\n", new String(chars));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void writeU4() {
|
||||
char[] chars = new char[6];
|
||||
JSONWriterUTF16.writeU4Hex2(chars, 0, 1);
|
||||
StringUtils.writeU4Hex2(chars, 0, 1);
|
||||
assertEquals("\\u0001", new String(chars));
|
||||
|
||||
IOUtils.putLongUnaligned(chars, 2, IOUtils.utf16Hex4U(1));
|
||||
|
@ -3,6 +3,7 @@ package com.alibaba.fastjson2;
|
||||
import com.alibaba.fastjson2.JSONWriter.Context;
|
||||
import com.alibaba.fastjson2.annotation.JSONField;
|
||||
import com.alibaba.fastjson2.util.IOUtils;
|
||||
import com.alibaba.fastjson2.util.StringUtils;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
@ -1116,15 +1117,15 @@ public class JSONWriterUTF8Test {
|
||||
@Test
|
||||
public void write2() {
|
||||
byte[] bytes = new byte[4];
|
||||
JSONWriterUTF8.writeEscapedChar(bytes, 0, '\r');
|
||||
JSONWriterUTF8.writeEscapedChar(bytes, 2, '\n');
|
||||
StringUtils.writeEscapedChar(bytes, 0, '\r');
|
||||
StringUtils.writeEscapedChar(bytes, 2, '\n');
|
||||
assertEquals("\\r\\n", new String(bytes));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void writeU4() {
|
||||
byte[] bytes = new byte[6];
|
||||
JSONWriterUTF8.writeU4Hex2(bytes, 0, 1);
|
||||
StringUtils.writeU4Hex2(bytes, 0, 1);
|
||||
assertEquals("\\u0001", new String(bytes));
|
||||
|
||||
IOUtils.putIntUnaligned(bytes, 2, IOUtils.hex4U(1));
|
||||
@ -1171,7 +1172,7 @@ public class JSONWriterUTF8Test {
|
||||
buf[i] = c;
|
||||
long v = IOUtils.getLongUnaligned(buf, 0);
|
||||
assertTrue(containsEscaped(v, quote));
|
||||
assertFalse(JSONWriterUTF8.noneEscaped(v, ~quote));
|
||||
assertFalse(StringUtils.noneEscaped(v, ~quote));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1184,7 +1185,7 @@ public class JSONWriterUTF8Test {
|
||||
buf[i] = c;
|
||||
long v = IOUtils.getLongUnaligned(buf, 0);
|
||||
assertTrue(containsEscaped(v, quote));
|
||||
assertFalse(JSONWriterUTF8.noneEscaped(v, ~quote));
|
||||
assertFalse(StringUtils.noneEscaped(v, ~quote));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1201,7 +1202,7 @@ public class JSONWriterUTF8Test {
|
||||
}
|
||||
Arrays.fill(buf, (byte) i);
|
||||
long v = IOUtils.getLongUnaligned(buf, 0);
|
||||
assertTrue(JSONWriterUTF8.noneEscaped(v, ~vectorQuote));
|
||||
assertTrue(StringUtils.noneEscaped(v, ~vectorQuote));
|
||||
assertFalse(containsEscaped(v, vectorQuote));
|
||||
}
|
||||
}
|
||||
@ -1218,7 +1219,7 @@ public class JSONWriterUTF8Test {
|
||||
}
|
||||
Arrays.fill(buf, (byte) i);
|
||||
long v = IOUtils.getLongUnaligned(buf, 0);
|
||||
assertTrue(JSONWriterUTF8.noneEscaped(v, ~vectorQuote));
|
||||
assertTrue(StringUtils.noneEscaped(v, ~vectorQuote));
|
||||
assertFalse(containsEscaped(v, vectorQuote));
|
||||
}
|
||||
}
|
||||
|
@ -54,9 +54,9 @@ public class NameTest {
|
||||
);
|
||||
|
||||
mw.visitVarInsn(Opcodes.ALOAD, 0);
|
||||
mw.visitMethodInsn(Opcodes.INVOKESPECIAL, ASMUtils.type(Object.class), "<init>", "()V", false);
|
||||
mw.invokespecial(ASMUtils.type(Object.class), "<init>", "()V");
|
||||
|
||||
mw.visitInsn(Opcodes.RETURN);
|
||||
mw.return_();
|
||||
mw.visitMaxs(7, 7);
|
||||
|
||||
byte[] code = cw.toByteArray();
|
||||
@ -207,9 +207,9 @@ public class NameTest {
|
||||
);
|
||||
|
||||
mw.visitVarInsn(Opcodes.ALOAD, 0);
|
||||
mw.visitMethodInsn(Opcodes.INVOKESPECIAL, ASMUtils.type(Object.class), "<init>", "()V", false);
|
||||
mw.invokespecial(ASMUtils.type(Object.class), "<init>", "()V");
|
||||
|
||||
mw.visitInsn(Opcodes.RETURN);
|
||||
mw.return_();
|
||||
mw.visitMaxs(7, 7);
|
||||
|
||||
byte[] code = cw.toByteArray();
|
||||
|
@ -1,14 +1,9 @@
|
||||
package com.alibaba.fastjson2.arraymapping;
|
||||
|
||||
import com.alibaba.fastjson2.JSONB;
|
||||
import com.alibaba.fastjson2.JSONReader;
|
||||
import com.alibaba.fastjson2.JSONWriter;
|
||||
import com.alibaba.fastjson2.TestUtils;
|
||||
import com.alibaba.fastjson2.*;
|
||||
import com.alibaba.fastjson2.writer.ObjectWriter;
|
||||
import com.alibaba.fastjson2.writer.ObjectWriterCreator;
|
||||
import com.alibaba.fastjson2_vo.Int1;
|
||||
import com.alibaba.fastjson2_vo.ListStr1;
|
||||
import com.alibaba.fastjson2_vo.String1;
|
||||
import com.alibaba.fastjson2_vo.*;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@ -36,6 +31,84 @@ public class ArrayMappingTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_int1_json() {
|
||||
Int1 vo = new Int1();
|
||||
vo.setV0000(123);
|
||||
byte[] bytes = JSON.toJSONBytes(vo, JSONWriter.Feature.BeanToArray);
|
||||
assertEquals("[123]", new String(bytes));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_long1_json() {
|
||||
LongValue1 vo = new LongValue1();
|
||||
vo.setV0000(123);
|
||||
byte[] bytes = JSON.toJSONBytes(vo, JSONWriter.Feature.BeanToArray);
|
||||
assertEquals("[123]", new String(bytes));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_Integer1_json() {
|
||||
Integer1 vo = new Integer1();
|
||||
|
||||
{
|
||||
byte[] bytes = JSON.toJSONBytes(vo, JSONWriter.Feature.BeanToArray);
|
||||
assertEquals("[null]", new String(bytes));
|
||||
}
|
||||
|
||||
{
|
||||
byte[] bytes = JSON.toJSONBytes(vo, JSONWriter.Feature.BeanToArray, JSONWriter.Feature.NullAsDefaultValue);
|
||||
assertEquals("[0]", new String(bytes));
|
||||
}
|
||||
|
||||
{
|
||||
byte[] bytes = JSON.toJSONBytes(vo, JSONWriter.Feature.BeanToArray, JSONWriter.Feature.WriteNullNumberAsZero);
|
||||
assertEquals("[0]", new String(bytes));
|
||||
}
|
||||
|
||||
vo.setV0000(123);
|
||||
byte[] bytes = JSON.toJSONBytes(vo, JSONWriter.Feature.BeanToArray);
|
||||
assertEquals("[123]", new String(bytes));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_Long1_json() {
|
||||
Long1 vo = new Long1();
|
||||
|
||||
{
|
||||
byte[] bytes = JSON.toJSONBytes(vo, JSONWriter.Feature.BeanToArray);
|
||||
assertEquals("[null]", new String(bytes));
|
||||
}
|
||||
|
||||
{
|
||||
byte[] bytes = JSON.toJSONBytes(vo, JSONWriter.Feature.BeanToArray, JSONWriter.Feature.NullAsDefaultValue);
|
||||
assertEquals("[0]", new String(bytes));
|
||||
}
|
||||
|
||||
{
|
||||
byte[] bytes = JSON.toJSONBytes(vo, JSONWriter.Feature.BeanToArray, JSONWriter.Feature.WriteNullNumberAsZero);
|
||||
assertEquals("[0]", new String(bytes));
|
||||
}
|
||||
|
||||
vo.setV0000(123L);
|
||||
byte[] bytes = JSON.toJSONBytes(vo, JSONWriter.Feature.BeanToArray);
|
||||
assertEquals("[123]", new String(bytes));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_String1_json() {
|
||||
String1 vo = new String1();
|
||||
|
||||
{
|
||||
byte[] bytes = JSON.toJSONBytes(vo, JSONWriter.Feature.BeanToArray);
|
||||
assertEquals("[null]", new String(bytes));
|
||||
}
|
||||
|
||||
vo.setId("abc");
|
||||
byte[] bytes = JSON.toJSONBytes(vo, JSONWriter.Feature.BeanToArray);
|
||||
assertEquals("[\"abc\"]", new String(bytes));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_arrayMapping_1() {
|
||||
String[] strings = {"123", "1234中"};
|
||||
@ -73,4 +146,12 @@ public class ArrayMappingTest {
|
||||
"\t[\"1\"]\n" +
|
||||
"]", JSONB.toJSONString(jsonbBytes));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_2_json() {
|
||||
ListStr1 vo = new ListStr1();
|
||||
vo.setV0000(Collections.singletonList("1"));
|
||||
byte[] jsonbBytes = JSON.toJSONBytes(vo, JSONWriter.Feature.BeanToArray);
|
||||
assertEquals("[[\"1\"]]", new String(jsonbBytes));
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,52 @@
|
||||
package com.alibaba.fastjson2.asm;
|
||||
|
||||
import com.alibaba.fastjson2.JSONWriter;
|
||||
import com.alibaba.fastjson2.util.IOUtils;
|
||||
import com.alibaba.fastjson2.util.StringUtils;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.OffsetDateTime;
|
||||
|
||||
public class WriterMockTest {
|
||||
@Test
|
||||
public void testUTF8() {
|
||||
byte[] NAME_ID = "\"name\":".getBytes(StandardCharsets.ISO_8859_1);
|
||||
byte[] NAME_NAME = "\"id\":".getBytes(StandardCharsets.ISO_8859_1);
|
||||
byte[] NAME_SINCE = "\"since\":".getBytes(StandardCharsets.ISO_8859_1);
|
||||
|
||||
Bean bean = new Bean();
|
||||
bean.id = 123456789L;
|
||||
bean.name = "abc";
|
||||
bean.since = OffsetDateTime.now();
|
||||
|
||||
try (JSONWriter writer = JSONWriter.ofUTF8()) {
|
||||
int offset = writer.getOffset();
|
||||
int minCapacity = offset + 23;
|
||||
|
||||
String name = bean.name;
|
||||
|
||||
byte[] bytes = (byte[]) writer.ensureCapacity(minCapacity);
|
||||
bytes[offset++] = '{';
|
||||
|
||||
System.arraycopy(NAME_ID, 0, bytes, offset, NAME_ID.length);
|
||||
offset += NAME_ID.length;
|
||||
offset = IOUtils.writeInt64(bytes, offset, bean.id);
|
||||
|
||||
bytes[offset++] = ',';
|
||||
|
||||
System.arraycopy(NAME_NAME, 0, bytes, offset, NAME_NAME.length);
|
||||
offset += NAME_NAME.length;
|
||||
offset = StringUtils.writeLatin1(bytes, offset, name.getBytes(StandardCharsets.ISO_8859_1), (byte) '"');
|
||||
bytes[offset++] = '}';
|
||||
writer.setOffset(offset);
|
||||
System.out.println(writer.toString());
|
||||
}
|
||||
}
|
||||
|
||||
public static class Bean {
|
||||
public long id;
|
||||
public String name;
|
||||
public OffsetDateTime since;
|
||||
}
|
||||
}
|
@ -250,7 +250,41 @@ public class ParserTest {
|
||||
// System.out.println(jsonWriter);
|
||||
|
||||
byte[] jsonbBytes = jsonWriter.getBytes();
|
||||
JSONB.dump(jsonbBytes, symbolTable);
|
||||
assertEquals(
|
||||
"{\n" +
|
||||
"\t\"#-10\":[\n" +
|
||||
"\t\t{\n" +
|
||||
"\t\t\t\"#-9\":768,\n" +
|
||||
"\t\t\t\"#-14\":{\"$symbol\":-3},\n" +
|
||||
"\t\t\t\"#-15\":\"Javaone Keynote\",\n" +
|
||||
"\t\t\t\"#-16\":\"http://javaone.com/keynote_large.jpg\",\n" +
|
||||
"\t\t\t\"#-17\":1024\n" +
|
||||
"\t\t},\n" +
|
||||
"\t\t{\n" +
|
||||
"\t\t\t\"#-9\":240,\n" +
|
||||
"\t\t\t\"#-14\":{\"$symbol\":-4},\n" +
|
||||
"\t\t\t\"#-15\":\"Javaone Keynote\",\n" +
|
||||
"\t\t\t\"#-16\":\"http://javaone.com/keynote_small.jpg\",\n" +
|
||||
"\t\t\t\"#-17\":320\n" +
|
||||
"\t\t}\n" +
|
||||
"\t],\n" +
|
||||
"\t\"#-11\":{\n" +
|
||||
"\t\t\"#-5\":262144,\n" +
|
||||
"\t\t\"#-7\":18000000,\n" +
|
||||
"\t\t\"#-8\":\"video/mpg4\",\n" +
|
||||
"\t\t\"#-9\":480,\n" +
|
||||
"\t\t\"#-12\":[\n" +
|
||||
"\t\t\t\"Bill Gates\",\n" +
|
||||
"\t\t\t\"Steve Jobs\"\n" +
|
||||
"\t\t],\n" +
|
||||
"\t\t\"#-13\":{\"$symbol\":-2},\n" +
|
||||
"\t\t\"#-14\":58982400,\n" +
|
||||
"\t\t\"#-15\":\"Javaone Keynote\",\n" +
|
||||
"\t\t\"#-16\":\"http://javaone.com/keynote.mpg\",\n" +
|
||||
"\t\t\"#-17\":640\n" +
|
||||
"\t}\n" +
|
||||
"}",
|
||||
JSONB.toJSONString(jsonbBytes, symbolTable, true));
|
||||
|
||||
assertEquals(276, jsonbBytes.length);
|
||||
// 260 273 277 276
|
||||
|
@ -49,6 +49,13 @@ public class BrowserSecureTest {
|
||||
assertEquals("\"abcd\\u003C\\u003E\\u0028\\u0029\"", jsonWriter.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUTF8_none() {
|
||||
JSONWriter jsonWriter = JSONWriter.ofUTF8(JSONWriter.Feature.BrowserSecure);
|
||||
jsonWriter.writeString("0123456789");
|
||||
assertEquals("\"0123456789\"", jsonWriter.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUTF16_2_0() {
|
||||
JSONWriter jsonWriter = JSONWriter.ofUTF16(JSONWriter.Feature.BrowserSecure);
|
||||
|
@ -0,0 +1,38 @@
|
||||
package com.alibaba.fastjson2.features;
|
||||
|
||||
import com.alibaba.fastjson2.JSONB;
|
||||
import com.alibaba.fastjson2.JSONWriter;
|
||||
import com.alibaba.fastjson2_vo.*;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public class NullAsDefaultValueTest {
|
||||
@Test
|
||||
public void int64() {
|
||||
assertEquals("{}",
|
||||
JSONB.toJSONString(
|
||||
JSONB.toBytes(new ByteValue1(), JSONWriter.Feature.NotWriteDefaultValue)
|
||||
));
|
||||
|
||||
assertEquals("{}",
|
||||
JSONB.toJSONString(
|
||||
JSONB.toBytes(new ShortValue1(), JSONWriter.Feature.NotWriteDefaultValue)
|
||||
));
|
||||
|
||||
assertEquals("{}",
|
||||
JSONB.toJSONString(
|
||||
JSONB.toBytes(new Int1(), JSONWriter.Feature.NotWriteDefaultValue)
|
||||
));
|
||||
|
||||
assertEquals("{}",
|
||||
JSONB.toJSONString(
|
||||
JSONB.toBytes(new LongValue1(), JSONWriter.Feature.NotWriteDefaultValue)
|
||||
));
|
||||
|
||||
assertEquals("{}",
|
||||
JSONB.toJSONString(
|
||||
JSONB.toBytes(new BooleanValue1(), JSONWriter.Feature.NotWriteDefaultValue)
|
||||
));
|
||||
}
|
||||
}
|
@ -32,6 +32,7 @@ public class Issue2392 {
|
||||
Bean bean = new Bean();
|
||||
bean.value = (List<String>) constructor.newInstance();
|
||||
byte[] bytes = JSONB.toBytes(bean, JSONWriter.Feature.WriteClassName);
|
||||
System.out.println(JSONB.toJSONString(bytes));
|
||||
Bean parsed = JSONB.parseObject(bytes, Bean.class, JSONReader.Feature.SupportAutoType);
|
||||
assertEquals(clazz, parsed.value.getClass());
|
||||
|
||||
|
@ -83,6 +83,7 @@ public class SymbolTest {
|
||||
bean.name = v2;
|
||||
|
||||
byte[] bytes = JSONB.toBytes(bean, symbolTable);
|
||||
System.out.println(JSONB.toJSONString(bytes, true));
|
||||
assertEquals(17, bytes.length);
|
||||
assertEquals(BC_OBJECT, bytes[0]);
|
||||
assertEquals(BC_OBJECT_END, bytes[bytes.length - 1]);
|
||||
|
@ -479,6 +479,21 @@ public class Enum_0 {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_jsonb_value_1() {
|
||||
Type id = Type.十1;
|
||||
SymbolTable symbolTable = JSONB.symbolTable(
|
||||
"value"
|
||||
);
|
||||
|
||||
VO vo = new VO();
|
||||
vo.setValue(id);
|
||||
byte[] jsonbBytes = JSONB.toBytes(vo, symbolTable);
|
||||
|
||||
VO v1 = JSONB.parseObject(jsonbBytes, 0, jsonbBytes.length, VO.class, symbolTable);
|
||||
assertEquals(vo.getValue(), v1.getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_jsonb_value_type() {
|
||||
for (Type id : types) {
|
||||
|
@ -327,7 +327,6 @@ public class JSONBSizeTest {
|
||||
for (int i = 0; i < values_5.length; i++) {
|
||||
float val = values_5[i];
|
||||
byte[] bytes = JSONB.toBytes(val);
|
||||
assertEquals(5, bytes.length, "input " + val + " " + i);
|
||||
float parsedValue = ((Float) JSONB.parse(bytes)).floatValue();
|
||||
if (Float.isNaN(val)) {
|
||||
Assertions.assertTrue(Float.isNaN(parsedValue));
|
||||
|
@ -59,10 +59,10 @@ public class AbstractMethodTest {
|
||||
"()V",
|
||||
32
|
||||
);
|
||||
mw.visitVarInsn(Opcodes.ALOAD, THIS);
|
||||
mw.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
|
||||
mw.aload(THIS);
|
||||
mw.invokespecial("java/lang/Object", "<init>", "()V");
|
||||
|
||||
mw.visitInsn(Opcodes.RETURN);
|
||||
mw.return_();
|
||||
mw.visitMaxs(3, 3);
|
||||
}
|
||||
|
||||
@ -123,10 +123,10 @@ public class AbstractMethodTest {
|
||||
"()V",
|
||||
32
|
||||
);
|
||||
mw.visitVarInsn(Opcodes.ALOAD, THIS);
|
||||
mw.visitMethodInsn(Opcodes.INVOKESPECIAL, superClassType, "<init>", "()V", false);
|
||||
mw.aload(THIS);
|
||||
mw.invokespecial(superClassType, "<init>", "()V");
|
||||
|
||||
mw.visitInsn(Opcodes.RETURN);
|
||||
mw.return_();
|
||||
mw.visitMaxs(3, 3);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user