This commit is contained in:
redkale
2024-09-16 17:21:13 +08:00
parent fcff5ccf7e
commit 6dca528381
6 changed files with 256 additions and 81 deletions

View File

@@ -38,6 +38,14 @@ public class JsonBytesWriter extends JsonWriter implements ByteTuple {
}
}
private static final byte[][] TENTHOUSAND_BYTES2 = new byte[TENTHOUSAND_MAX][];
static {
for (int i = 0; i < TENTHOUSAND_BYTES2.length; i++) {
TENTHOUSAND_BYTES2[i] = String.valueOf(-i).getBytes();
}
}
private int count;
private byte[] content;
@@ -186,8 +194,10 @@ public class JsonBytesWriter extends JsonWriter implements ByteTuple {
public void writeFieldShortValue(final byte[] fieldBytes, final short value) {
byte[] bs1 = fieldBytes;
byte[] bs2 = (value >= 0 && value < TENTHOUSAND_MAX)
? TENTHOUSAND_BYTES[(int) value]
: Utility.latin1ByteArray(String.valueOf(value));
? TENTHOUSAND_BYTES[value]
: ((value < 0 && value > -TENTHOUSAND_MAX)
? TENTHOUSAND_BYTES2[-value]
: Utility.latin1ByteArray(String.valueOf(value)));
int len1 = bs1.length;
int len2 = bs2.length;
byte[] src = expand(len1 + len2);
@@ -202,7 +212,9 @@ public class JsonBytesWriter extends JsonWriter implements ByteTuple {
byte[] bs1 = fieldBytes;
byte[] bs2 = (value >= 0 && value < TENTHOUSAND_MAX)
? TENTHOUSAND_BYTES[value]
: Utility.latin1ByteArray(String.valueOf(value));
: ((value < 0 && value > -TENTHOUSAND_MAX)
? TENTHOUSAND_BYTES2[-value]
: Utility.latin1ByteArray(String.valueOf(value)));
int len1 = bs1.length;
int len2 = bs2.length;
byte[] src = expand(len1 + len2);
@@ -217,7 +229,9 @@ public class JsonBytesWriter extends JsonWriter implements ByteTuple {
byte[] bs1 = fieldBytes;
byte[] bs2 = (value >= 0 && value < TENTHOUSAND_MAX)
? TENTHOUSAND_BYTES[(int) value]
: Utility.latin1ByteArray(String.valueOf(value));
: ((value < 0 && value > -TENTHOUSAND_MAX)
? TENTHOUSAND_BYTES2[(int) -value]
: Utility.latin1ByteArray(String.valueOf(value)));
int len1 = bs1.length;
int len2 = bs2.length;
byte[] src = expand(len1 + len2);
@@ -246,8 +260,10 @@ public class JsonBytesWriter extends JsonWriter implements ByteTuple {
public void writeLastFieldShortValue(final byte[] fieldBytes, final short value) {
byte[] bs1 = fieldBytes;
byte[] bs2 = (value >= 0 && value < TENTHOUSAND_MAX)
? TENTHOUSAND_BYTES[(int) value]
: Utility.latin1ByteArray(String.valueOf(value));
? TENTHOUSAND_BYTES[value]
: ((value < 0 && value > -TENTHOUSAND_MAX)
? TENTHOUSAND_BYTES2[-value]
: Utility.latin1ByteArray(String.valueOf(value)));
int len1 = bs1.length;
int len2 = bs2.length;
byte[] src = expand(len1 + len2 + 1);
@@ -263,7 +279,9 @@ public class JsonBytesWriter extends JsonWriter implements ByteTuple {
byte[] bs1 = fieldBytes;
byte[] bs2 = (value >= 0 && value < TENTHOUSAND_MAX)
? TENTHOUSAND_BYTES[value]
: Utility.latin1ByteArray(String.valueOf(value));
: ((value < 0 && value > -TENTHOUSAND_MAX)
? TENTHOUSAND_BYTES2[-value]
: Utility.latin1ByteArray(String.valueOf(value)));
int len1 = bs1.length;
int len2 = bs2.length;
byte[] src = expand(len1 + len2 + 1);
@@ -279,7 +297,9 @@ public class JsonBytesWriter extends JsonWriter implements ByteTuple {
byte[] bs1 = fieldBytes;
byte[] bs2 = (value >= 0 && value < TENTHOUSAND_MAX)
? TENTHOUSAND_BYTES[(int) value]
: Utility.latin1ByteArray(String.valueOf(value));
: ((value < 0 && value > -TENTHOUSAND_MAX)
? TENTHOUSAND_BYTES2[(int) -value]
: Utility.latin1ByteArray(String.valueOf(value)));
int len1 = bs1.length;
int len2 = bs2.length;
byte[] src = expand(len1 + len2 + 1);
@@ -356,11 +376,15 @@ public class JsonBytesWriter extends JsonWriter implements ByteTuple {
byte[] bs1 = firstFieldBytes;
byte[] bs2 = (value1 >= 0 && value1 < TENTHOUSAND_MAX)
? TENTHOUSAND_BYTES[value1]
: Utility.latin1ByteArray(String.valueOf(value1));
: ((value1 < 0 && value1 > -TENTHOUSAND_MAX)
? TENTHOUSAND_BYTES2[-value1]
: Utility.latin1ByteArray(String.valueOf(value1)));
byte[] bs3 = lastFieldBytes;
byte[] bs4 = (value2 >= 0 && value2 < TENTHOUSAND_MAX)
? TENTHOUSAND_BYTES[value2]
: Utility.latin1ByteArray(String.valueOf(value2));
: ((value2 < 0 && value2 > -TENTHOUSAND_MAX)
? TENTHOUSAND_BYTES2[-value2]
: Utility.latin1ByteArray(String.valueOf(value2)));
int len1 = bs1.length;
int len2 = bs2.length;
int len3 = bs3.length;
@@ -405,42 +429,6 @@ public class JsonBytesWriter extends JsonWriter implements ByteTuple {
return this.count;
}
private void writeEscapeLatinString(final boolean quote, byte[] value) {
byte[] bytes = expand(value.length * 2 + 2);
int curr = count;
if (quote) {
bytes[curr++] = BYTE_DQUOTE;
}
for (byte b : value) {
if (b == '"') {
bytes[curr++] = '\\';
bytes[curr++] = '"';
} else if (b == '\\') {
bytes[curr++] = '\\';
bytes[curr++] = '\\';
} else if (b < 32) {
if (b == '\n') {
bytes[curr++] = '\\';
bytes[curr++] = 'n';
} else if (b == '\r') {
bytes[curr++] = '\\';
bytes[curr++] = 'r';
} else if (b == '\t') {
bytes[curr++] = '\\';
bytes[curr++] = 't';
} else {
bytes[curr++] = b;
}
} else {
bytes[curr++] = b;
}
}
if (quote) {
bytes[curr++] = BYTE_DQUOTE;
}
count = curr;
}
@Override
public void writeString(String value) {
writeString(true, value);
@@ -456,12 +444,17 @@ public class JsonBytesWriter extends JsonWriter implements ByteTuple {
writeEscapeLatinString(quote, Utility.latin1ByteArray(value));
return;
}
byte[] bytes = expand(value.length() * 4 + 2);
byte[] utf16s = Utility.byteUTF16Array(value);
if (utf16s != null) { // JDK9+
writeUTF16String(quote, utf16s);
return;
}
int len = value.length();
byte[] bytes = expand(len * 4 + 2);
int curr = count;
if (quote) {
bytes[curr++] = BYTE_DQUOTE;
}
int len = value.length();
for (int i = 0; i < len; i++) {
char ch = value.charAt(i);
switch (ch) {
@@ -493,12 +486,12 @@ public class JsonBytesWriter extends JsonWriter implements ByteTuple {
bytes[curr++] = (byte) (0x80 | (ch & 0x3f));
} else if (Character.isSurrogate(ch)) { // 连取两个
int uc = Character.toCodePoint(ch, value.charAt(++i));
bytes[curr++] = (byte) (0xf0 | ((uc >> 18)));
bytes[curr++] = (byte) (0xf0 | (uc >> 18));
bytes[curr++] = (byte) (0x80 | ((uc >> 12) & 0x3f));
bytes[curr++] = (byte) (0x80 | ((uc >> 6) & 0x3f));
bytes[curr++] = (byte) (0x80 | (uc & 0x3f));
} else {
bytes[curr++] = (byte) (0xe0 | ((ch >> 12)));
bytes[curr++] = (byte) (0xe0 | (ch >> 12));
bytes[curr++] = (byte) (0x80 | ((ch >> 6) & 0x3f));
bytes[curr++] = (byte) (0x80 | (ch & 0x3f));
}
@@ -511,6 +504,127 @@ public class JsonBytesWriter extends JsonWriter implements ByteTuple {
count = curr;
}
// see java.lang.StringCoding.encodeUTF8_UTF16 方法
private void writeUTF16String(final boolean quote, byte[] value) {
int len = value.length;
byte[] bytes = expand(len * 4 + 2);
int curr = count;
if (quote) {
bytes[curr++] = BYTE_DQUOTE;
}
byte[] src = value;
int i = 0;
while (i < len) {
byte b = src[i];
byte b2 = src[i + 1];
i += 2;
if (b2 == 0 && b >= 0) {
if (b == '"') {
bytes[curr++] = '\\';
bytes[curr++] = '"';
} else if (b == '\\') {
bytes[curr++] = '\\';
bytes[curr++] = '\\';
} else if (b < 32) {
if (b == '\n') {
bytes[curr++] = '\\';
bytes[curr++] = 'n';
} else if (b == '\r') {
bytes[curr++] = '\\';
bytes[curr++] = 'r';
} else if (b == '\f') {
bytes[curr++] = '\\';
bytes[curr++] = 'f';
} else if (b == '\b') {
bytes[curr++] = '\\';
bytes[curr++] = 'b';
} else if (b == '\t') {
bytes[curr++] = '\\';
bytes[curr++] = 't';
} else {
bytes[curr++] = b;
}
} else {
bytes[curr++] = b;
}
} else {
char c = (char) ((b & 0xff) | ((b2 & 0xff) << 8));
if (c < 0x800) {
bytes[curr++] = (byte) (0xc0 | (c >> 6));
bytes[curr++] = (byte) (0x80 | (c & 0x3f));
} else if (Character.isSurrogate(c)) {
int uc = -1;
if (Character.isHighSurrogate(c) && i < len) {
char c2 = (char) ((src[i] & 0xff) | ((src[i + 1] & 0xff) << 8));
if (Character.isLowSurrogate(c2)) {
uc = Character.toCodePoint(c, c2);
}
}
if (uc < 0) {
bytes[curr++] = '?';
} else {
bytes[curr++] = (byte) (0xf0 | (uc >> 18));
bytes[curr++] = (byte) (0x80 | ((uc >> 12) & 0x3f));
bytes[curr++] = (byte) (0x80 | ((uc >> 6) & 0x3f));
bytes[curr++] = (byte) (0x80 | (uc & 0x3f));
i += 2; // 2 chars
}
} else {
// 3 bytes, 16 bits
bytes[curr++] = (byte) (0xe0 | (c >> 12));
bytes[curr++] = (byte) (0x80 | ((c >> 6) & 0x3f));
bytes[curr++] = (byte) (0x80 | (c & 0x3f));
}
}
}
if (quote) {
bytes[curr++] = BYTE_DQUOTE;
}
count = curr;
}
private void writeEscapeLatinString(final boolean quote, byte[] value) {
byte[] bytes = expand(value.length * 2 + 2);
int curr = count;
if (quote) {
bytes[curr++] = BYTE_DQUOTE;
}
for (byte b : value) {
if (b == '"') {
bytes[curr++] = '\\';
bytes[curr++] = '"';
} else if (b == '\\') {
bytes[curr++] = '\\';
bytes[curr++] = '\\';
} else if (b < 32) {
if (b == '\n') {
bytes[curr++] = '\\';
bytes[curr++] = 'n';
} else if (b == '\r') {
bytes[curr++] = '\\';
bytes[curr++] = 'r';
} else if (b == '\f') {
bytes[curr++] = '\\';
bytes[curr++] = 'f';
} else if (b == '\b') {
bytes[curr++] = '\\';
bytes[curr++] = 'b';
} else if (b == '\t') {
bytes[curr++] = '\\';
bytes[curr++] = 't';
} else {
bytes[curr++] = b;
}
} else {
bytes[curr++] = b;
}
}
if (quote) {
bytes[curr++] = BYTE_DQUOTE;
}
count = curr;
}
@Override
public void writeWrapper(StringWrapper wrapper) {
if (wrapper == null || wrapper.getValue() == null) {
@@ -522,6 +636,11 @@ public class JsonBytesWriter extends JsonWriter implements ByteTuple {
writeTo(Utility.latin1ByteArray(value));
return;
}
byte[] utf16s = Utility.byteUTF16Array(value);
if (utf16s != null) { // JDK9+
writeUTF16String(false, utf16s);
return;
}
byte[] bytes = expand(value.length() * 4 + 2);
int curr = count;
int len = value.length();
@@ -534,12 +653,12 @@ public class JsonBytesWriter extends JsonWriter implements ByteTuple {
bytes[curr++] = (byte) (0x80 | (ch & 0x3f));
} else if (Character.isSurrogate(ch)) { // 连取两个
int uc = Character.toCodePoint(ch, value.charAt(++i));
bytes[curr++] = (byte) (0xf0 | ((uc >> 18)));
bytes[curr++] = (byte) (0xf0 | (uc >> 18));
bytes[curr++] = (byte) (0x80 | ((uc >> 12) & 0x3f));
bytes[curr++] = (byte) (0x80 | ((uc >> 6) & 0x3f));
bytes[curr++] = (byte) (0x80 | (uc & 0x3f));
} else {
bytes[curr++] = (byte) (0xe0 | ((ch >> 12)));
bytes[curr++] = (byte) (0xe0 | (ch >> 12));
bytes[curr++] = (byte) (0x80 | ((ch >> 6) & 0x3f));
bytes[curr++] = (byte) (0x80 | (ch & 0x3f));
}
@@ -570,6 +689,13 @@ public class JsonBytesWriter extends JsonWriter implements ByteTuple {
count += bs.length;
return;
}
if (value < 0 && value > -TENTHOUSAND_MAX) {
byte[] bs = TENTHOUSAND_BYTES2[-value];
expand(bs.length);
System.arraycopy(bs, 0, content, count, bs.length);
count += bs.length;
return;
}
final char sign = value >= 0 ? 0 : '-';
if (value < 0) {
value = -value;
@@ -625,6 +751,13 @@ public class JsonBytesWriter extends JsonWriter implements ByteTuple {
count += bs.length;
return;
}
if (value < 0 && value > -TENTHOUSAND_MAX) {
byte[] bs = TENTHOUSAND_BYTES2[(int) -value];
expand(bs.length);
System.arraycopy(bs, 0, content, count, bs.length);
count += bs.length;
return;
}
final char sign = value >= 0 ? 0 : '-';
if (value < 0) {
value = -value;

View File

@@ -7,6 +7,11 @@ package org.redkale.convert.json;
import java.lang.reflect.*;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;
import org.redkale.asm.*;
import static org.redkale.asm.ClassWriter.COMPUTE_FRAMES;
@@ -53,6 +58,48 @@ public abstract class JsonDynEncoder<T> implements Encodeable<JsonWriter, T> {
if (clazz.isEnum()) {
return true;
}
if (type == Boolean.class) {
return true;
}
if (type == Byte.class) {
return true;
}
if (type == Short.class) {
return true;
}
if (type == Character.class) {
return true;
}
if (type == Integer.class) {
return true;
}
if (type == Float.class) {
return true;
}
if (type == Long.class) {
return true;
}
if (type == Double.class) {
return true;
}
if (type == BigInteger.class) {
return true;
}
if (type == BigDecimal.class) {
return true;
}
if (type == LocalDate.class) {
return true;
}
if (type == LocalTime.class) {
return true;
}
if (type == LocalDateTime.class) {
return true;
}
if (type == java.util.Date.class) {
return true;
}
if (type == boolean[].class) {
return true;
}
@@ -121,6 +168,12 @@ public abstract class JsonDynEncoder<T> implements Encodeable<JsonWriter, T> {
|| t == Long.class
|| t == Double.class
|| t == String.class
|| t == BigInteger.class
|| t == BigDecimal.class
|| t == LocalDate.class
|| t == LocalTime.class
|| t == LocalDateTime.class
|| t == java.util.Date.class
|| ((t instanceof Class) && ((Class) t).isEnum())) {
return true;
}

View File

@@ -127,7 +127,7 @@ public abstract class JsonWriter extends Writer {
writeTo(BYTE_COMMA);
}
if (member != null) {
writeTo(member.getJsonFieldNameChars());
writeTo(member.getJsonFieldNameBytes());
} else {
writeLatin1To(true, fieldName);
writeTo(BYTE_COLON);

View File

@@ -114,10 +114,6 @@ public final class Utility {
private static final Function<Object, Object> sbByteFunction;
private static final Function<Object, Object> strCharFunction;
private static final Function<Object, Object> sbCharFunction;
private static final Predicate<Object> strLatin1Function;
private static final ToLongFunction<Object> bufferAddrFunction;
@@ -146,8 +142,6 @@ public final class Utility {
.setRemoveOnCancelPolicy(true);
Unsafe unsafe0 = null;
Function<Object, Object> strCharFunction0 = null;
Function<Object, Object> sbCharFunction0 = null;
Function<Object, Object> strByteFunction0 = null;
Function<Object, Object> sbByteFunction0 = null;
Predicate<Object> strLatin1Function0 = null;
@@ -352,8 +346,6 @@ public final class Utility {
}
}
unsafeInstance = unsafe0;
strCharFunction = strCharFunction0;
sbCharFunction = sbCharFunction0;
strByteFunction = strByteFunction0;
sbByteFunction = sbByteFunction0;
strLatin1Function = strLatin1Function0;
@@ -4849,11 +4841,8 @@ public final class Utility {
if (value == null) {
return new byte[0];
}
if (strCharFunction == null) {
return encodeUTF8(value.toCharArray());
}
return encodeUTF8((char[]) strCharFunction.apply(value));
}
public static byte[] encodeUTF8(final char[] array) {
return encodeUTF8(array, 0, array.length);
@@ -4921,25 +4910,26 @@ public final class Utility {
return true;
}
public static byte[] byteUTF16Array(String value) {
if (value == null || strByteFunction == null) {
return null;
}
return (byte[]) strByteFunction.apply(value);
}
public static char[] charArray(String value) {
if (value == null) {
return null;
}
if (strCharFunction == null) {
return value.toCharArray();
}
return (char[]) strCharFunction.apply(value);
}
public static char[] charArray(StringBuilder value) {
if (value == null) {
return null;
}
if (sbCharFunction == null) {
return value.toString().toCharArray();
}
return (char[]) sbCharFunction.apply(value);
}
// 只能是单字节字符串
public static byte[] latin1ByteArray(String latin1Value) {
@@ -4975,11 +4965,8 @@ public final class Utility {
if (value == null) {
return -1;
}
if (strCharFunction == null) {
return encodeUTF8Length(value.toCharArray());
}
return encodeUTF8Length((char[]) strCharFunction.apply(value));
}
public static int encodeUTF8Length(final char[] text) {
return encodeUTF8Length(text, 0, text.length);

View File

@@ -73,15 +73,15 @@ public final class Message {
longs.add(2222L);
longs.add(3333L);
msg.longs = longs;
msg.ints = new int[] {2, 3, 4};
msg.ints = new int[] {-2, 3, 4};
JsonConvert convert = JsonFactory.root().getConvert();
Encodeable encoder = JsonFactory.root().loadEncoder(Message.class);
System.out.println(encoder);
ByteArray array = new ByteArray();
array.put("数据: ".getBytes(StandardCharsets.UTF_8));
JsonConvert.root().convertToBytes(array, msg);
convert.convertToBytes(array, msg);
System.out.println(array);
Message[] mss = new Message[] {msg};
System.out.println(JsonConvert.root().convertTo(mss));
System.out.println(convert.convertTo(mss));
}
}

View File

@@ -33,7 +33,9 @@ public class StringWrapperTest {
System.out.println(new String(convert.convertToBytes(wrapper)));
}
{
String val = "{id:'带中文'}";
String emoji =
new String(new byte[] {(byte) 0xF0, (byte) 0x9F, (byte) 0x98, (byte) 0x81}, StandardCharsets.UTF_8);
String val = "{id:'带中文" + emoji + "'}";
StringWrapper wrapper = new StringWrapper(val);
if (!main) Assertions.assertEquals(val, convert.convertTo(wrapper));
if (!main)