Compare commits

...

10 Commits

Author SHA1 Message Date
wenshao
f5be616daa simplify 2025-02-19 06:56:16 +08:00
wenshao
dc096e496c simplify 2025-02-19 06:31:31 +08:00
wenshao
6ca3abd326 refactor 2025-02-18 20:37:48 +08:00
wenshao
b9a6dbd116 checkstyle 2025-02-18 19:37:16 +08:00
wenshao
938fa270d0 refactor 2025-02-18 19:20:45 +08:00
wenshao
28c2e92394 optimize writeJSONB 2025-02-18 12:13:40 +08:00
wenshao
0c3e07ab31 refactor 2025-02-17 00:56:59 +08:00
高铁
ed393bbb5e fix javadoc 2025-02-16 23:41:37 +08:00
wenshao
e2745af3b7 bug fix 2025-02-16 23:28:24 +08:00
wenshao
17cca863a1 optimize write json 2025-02-16 22:44:33 +08:00
38 changed files with 4440 additions and 2912 deletions

View File

@ -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();

View File

@ -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 {

View File

@ -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

View File

@ -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
}

View File

@ -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;
}
}
}

View File

@ -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);
}
}
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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('.', '/') + ';';

View File

@ -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:

View File

@ -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.

View File

@ -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; // -

View File

@ -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);

View File

@ -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 &gt; 0
*/
public static Scientific doubleToScientific(double doubleValue) {
if (doubleValue == Double.MIN_VALUE) {

View 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;
}
}
}
}

View File

@ -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;
}

View File

@ -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) {

View File

@ -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);
}
}

View File

@ -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) {

View File

@ -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();

View File

@ -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<>();

View File

@ -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));

View File

@ -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));
}
}

View File

@ -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();

View File

@ -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));
}
}

View File

@ -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;
}
}

View File

@ -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

View File

@ -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);

View File

@ -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)
));
}
}

View File

@ -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());

View File

@ -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]);

View File

@ -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) {

View File

@ -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));

View File

@ -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);
}