mirror of
https://github.com/alibaba/fastjson.git
synced 2026-10-24 02:18:47 +08:00
@@ -1,25 +1,32 @@
|
||||
# fastjson
|
||||
|
||||
[](https://maven-badges.herokuapp.com/maven-central/com.alibaba/fastjson/)
|
||||
[](https://github.com/alibaba/fastjson/releases)
|
||||
[](https://www.apache.org/licenses/LICENSE-2.0.html)
|
||||
|
||||
Fast JSON Processor
|
||||
|
||||

|
||||

|
||||
|
||||
## Documentation
|
||||
https://github.com/alibaba/fastjson/wiki/%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98
|
||||
|
||||
- [Documentation Home](https://github.com/alibaba/fastjson/wiki)
|
||||
- [Frequently Asked Questions](https://github.com/alibaba/fastjson/wiki/%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98)
|
||||
|
||||
## Benchmark
|
||||
|
||||
https://github.com/eishay/jvm-serializers/wiki
|
||||
|
||||
|
||||
## Download
|
||||
http://repo1.maven.org/maven2/com/alibaba/fastjson/
|
||||
|
||||
http://repo1.maven.org/maven2/com/alibaba/fastjson/
|
||||
|
||||
## Maven
|
||||
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>fastjson</artifactId>
|
||||
<version>x.x.x</version>
|
||||
</dependency>
|
||||
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>fastjson</artifactId>
|
||||
<version>x.x.x</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>fastjson</artifactId>
|
||||
<version>1.2.5</version>
|
||||
<version>1.2.6</version>
|
||||
|
||||
<packaging>jar</packaging>
|
||||
<name>fastjson</name>
|
||||
|
||||
@@ -737,5 +737,5 @@ public abstract class JSON implements JSONStreamAware, JSONAware {
|
||||
}
|
||||
}
|
||||
|
||||
public final static String VERSION = "1.2.5";
|
||||
public final static String VERSION = "1.2.6";
|
||||
}
|
||||
|
||||
@@ -18,7 +18,9 @@ public @interface JSONType {
|
||||
boolean asm() default true;
|
||||
|
||||
String[] orders() default {};
|
||||
|
||||
|
||||
String[] includes() default {};
|
||||
|
||||
String[] ignores() default {};
|
||||
|
||||
SerializerFeature[] serialzeFeatures() default {};
|
||||
|
||||
@@ -160,7 +160,8 @@ public class MapSerializer implements ObjectSerializer {
|
||||
}
|
||||
|
||||
if (out.isEnabled(SerializerFeature.BrowserCompatible)
|
||||
|| out.isEnabled(SerializerFeature.WriteNonStringKeyAsString)) {
|
||||
|| out.isEnabled(SerializerFeature.WriteNonStringKeyAsString)
|
||||
|| out.isEnabled(SerializerFeature.BrowserSecure)) {
|
||||
String strEntryKey = JSON.toJSONString(entryKey);
|
||||
serializer.write(strEntryKey);
|
||||
} else {
|
||||
|
||||
@@ -642,7 +642,18 @@ public final class SerializeWriter extends Writer {
|
||||
for (int i = 0; i < text.length(); ++i) {
|
||||
char ch = text.charAt(i);
|
||||
|
||||
if (isEnabled(SerializerFeature.BrowserCompatible)) {
|
||||
if (isEnabled(SerializerFeature.BrowserSecure)) {
|
||||
if (!(ch >= '0' && ch <= '9') && !(ch >= 'a' && ch <= 'z') && !(ch >= 'A' && ch <= 'Z')
|
||||
&& !(ch == ',') && !(ch == '.') && !(ch == '_')) {
|
||||
write('\\');
|
||||
write('u');
|
||||
write(IOUtils.DIGITS[(ch >>> 12) & 15]);
|
||||
write(IOUtils.DIGITS[(ch >>> 8) & 15]);
|
||||
write(IOUtils.DIGITS[(ch >>> 4) & 15]);
|
||||
write(IOUtils.DIGITS[ch & 15]);
|
||||
continue;
|
||||
}
|
||||
} else if (isEnabled(SerializerFeature.BrowserCompatible)) {
|
||||
if (ch == '\b' //
|
||||
|| ch == '\f' //
|
||||
|| ch == '\n' //
|
||||
@@ -680,7 +691,15 @@ public final class SerializeWriter extends Writer {
|
||||
&& IOUtils.specicalFlags_doubleQuotes[ch] != 0 //
|
||||
|| (ch == '/' && isEnabled(SerializerFeature.WriteSlashAsSpecial))) {
|
||||
write('\\');
|
||||
write(replaceChars[(int) ch]);
|
||||
if (IOUtils.specicalFlags_doubleQuotes[ch] == 4) {
|
||||
write('u');
|
||||
write(IOUtils.DIGITS[ch >>> 12 & 15]);
|
||||
write(IOUtils.DIGITS[ch >>> 8 & 15]);
|
||||
write(IOUtils.DIGITS[ch >>> 4 & 15]);
|
||||
write(IOUtils.DIGITS[ch & 15]);
|
||||
} else {
|
||||
write(IOUtils.replaceChars[ch]);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -705,6 +724,51 @@ public final class SerializeWriter extends Writer {
|
||||
|
||||
count = newcount;
|
||||
|
||||
if (isEnabled(SerializerFeature.BrowserSecure)) {
|
||||
int lastSpecialIndex = -1;
|
||||
|
||||
for (int i = start; i < end; ++i) {
|
||||
char ch = buf[i];
|
||||
|
||||
if (!(ch >= '0' && ch <= '9') && !(ch >= 'a' && ch <= 'z') && !(ch >= 'A' && ch <= 'Z')
|
||||
&& !(ch == ',') && !(ch == '.') && !(ch == '_')) {
|
||||
lastSpecialIndex = i;
|
||||
newcount += 5;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (newcount > buf.length) {
|
||||
expandCapacity(newcount);
|
||||
}
|
||||
count = newcount;
|
||||
|
||||
for (int i = lastSpecialIndex; i >= start; --i) {
|
||||
char ch = buf[i];
|
||||
|
||||
if (!(ch >= '0' && ch <= '9') && !(ch >= 'a' && ch <= 'z') && !(ch >= 'A' && ch <= 'Z') && !(ch == ',')
|
||||
&& !(ch == '.') && !(ch == '_')) {
|
||||
System.arraycopy(buf, i + 1, buf, i + 6, end - i - 1);
|
||||
buf[i] = '\\';
|
||||
buf[i + 1] = 'u';
|
||||
buf[i + 2] = IOUtils.DIGITS[(ch >>> 12) & 15];
|
||||
buf[i + 3] = IOUtils.DIGITS[(ch >>> 8) & 15];
|
||||
buf[i + 4] = IOUtils.DIGITS[(ch >>> 4) & 15];
|
||||
buf[i + 5] = IOUtils.DIGITS[ch & 15];
|
||||
end += 5;
|
||||
}
|
||||
}
|
||||
|
||||
if (seperator != 0) {
|
||||
buf[count - 2] = '\"';
|
||||
buf[count - 1] = seperator;
|
||||
} else {
|
||||
buf[count - 1] = '\"';
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (isEnabled(SerializerFeature.BrowserCompatible)) {
|
||||
int lastSpecialIndex = -1;
|
||||
|
||||
@@ -1192,7 +1256,11 @@ public final class SerializeWriter extends Writer {
|
||||
writeString(value);
|
||||
}
|
||||
} else {
|
||||
if (isEnabled(SerializerFeature.BrowserCompatible)) {
|
||||
if (isEnabled(SerializerFeature.BrowserSecure)) {
|
||||
write(seperator);
|
||||
writeStringWithDoubleQuote(name, ':');
|
||||
writeStringWithDoubleQuote(value, (char) 0);
|
||||
} else if (isEnabled(SerializerFeature.BrowserCompatible)) {
|
||||
write(seperator);
|
||||
writeStringWithDoubleQuote(name, ':');
|
||||
writeStringWithDoubleQuote(value, (char) 0);
|
||||
|
||||
@@ -121,7 +121,12 @@ public enum SerializerFeature {
|
||||
/**
|
||||
* @since 1.1.42
|
||||
*/
|
||||
NotWriteDefaultValue
|
||||
NotWriteDefaultValue,
|
||||
|
||||
/**
|
||||
* @since 1.2.6
|
||||
*/
|
||||
BrowserSecure,
|
||||
;
|
||||
|
||||
private SerializerFeature(){
|
||||
|
||||
@@ -1267,10 +1267,24 @@ public class TypeUtils {
|
||||
private static boolean isJSONTypeIgnore(Class<?> clazz, String propertyName) {
|
||||
JSONType jsonType = clazz.getAnnotation(JSONType.class);
|
||||
|
||||
if (jsonType != null && jsonType.ignores() != null) {
|
||||
for (String item : jsonType.ignores()) {
|
||||
if (propertyName.equalsIgnoreCase(item)) {
|
||||
return true;
|
||||
if (jsonType != null) {
|
||||
// 1、新增 includes 支持,如果 JSONType 同时设置了includes 和 ignores 属性,则以includes为准。
|
||||
// 2、个人认为对于大小写敏感的Java和JS而言,使用 equals() 比 equalsIgnoreCase() 更好,改动的唯一风险就是向后兼容性的问题
|
||||
// 不过,相信开发者应该都是严格按照大小写敏感的方式进行属性设置的
|
||||
String[] fields = jsonType.includes();
|
||||
if (fields.length > 0) {
|
||||
for (int i = 0; i < fields.length; i++) {
|
||||
if (propertyName.equals(fields[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
fields = jsonType.ignores();
|
||||
for (int i = 0; i < fields.length; i++) {
|
||||
if (propertyName.equals(fields[i])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
package com.alibaba.fastjson.serializer;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.util.IOUtils;
|
||||
|
||||
public class SerializeWriterTest {
|
||||
|
||||
private final Logger logger = Logger.getLogger(SerializeWriterTest.class.getSimpleName());
|
||||
|
||||
private final ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
|
||||
private final SerializeWriter writer = new SerializeWriter(new OutputStreamWriter(baos));
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWriteLiteBasicStr() throws UnsupportedEncodingException {
|
||||
String targetStr = new String(IOUtils.DIGITS);
|
||||
this.doTestWrite(targetStr);
|
||||
}
|
||||
|
||||
private String doTestWrite(String input) throws UnsupportedEncodingException {
|
||||
writer.writeString(input, (char) 0);
|
||||
writer.flush();
|
||||
String result = this.baos.toString("UTF-8");
|
||||
|
||||
Assert.assertEquals(input, JSON.parse(result));
|
||||
|
||||
logger.info(result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWriteLiteSpecilaStr() throws UnsupportedEncodingException {
|
||||
this.doTestWrite(this.makeSpecialChars());
|
||||
}
|
||||
|
||||
private String makeSpecialChars() {
|
||||
StringBuilder strBuilder = new StringBuilder(128);
|
||||
for (char c = 128; c <= 160; c++) {
|
||||
strBuilder.append(c);
|
||||
}
|
||||
return strBuilder.toString();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWriteLargeBasicStr() throws UnsupportedEncodingException {
|
||||
String tmp = new String(IOUtils.DIGITS);
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (int i = 0; i < 200; i++) {
|
||||
builder.append(tmp);
|
||||
}
|
||||
this.doTestWrite(builder.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWriteLargeSpecialStr() throws UnsupportedEncodingException {
|
||||
|
||||
String tmp = this.makeSpecialChars();
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (int i = 0; i < 200; i++) {
|
||||
builder.append(tmp);
|
||||
}
|
||||
this.doTestWrite(builder.toString());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
package com.alibaba.json.bvt.serializer;
|
||||
|
||||
import java.io.StringWriter;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Assert;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.serializer.SerializerFeature;
|
||||
|
||||
public class SerializeWriterTest_BrowserSecure extends TestCase {
|
||||
|
||||
public void test_0() throws Exception {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
for (int i = 0; i < 1024; ++i) {
|
||||
buf.append('a');
|
||||
}
|
||||
buf.append("中国");
|
||||
buf.append("\0");
|
||||
JSON.toJSONString(buf.toString(), SerializerFeature.BrowserSecure);
|
||||
}
|
||||
|
||||
public void test_1() throws Exception {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
for (int i = 0; i < 1024; ++i) {
|
||||
buf.append('a');
|
||||
}
|
||||
buf.append("中国");
|
||||
buf.append("\0");
|
||||
|
||||
StringWriter out = new StringWriter();
|
||||
JSON.writeJSONStringTo(buf.toString(), out, SerializerFeature.BrowserSecure);
|
||||
}
|
||||
|
||||
public void test_zh() throws Exception {
|
||||
Assert.assertEquals("\"\\u4E2D\\u56FD\"", JSON.toJSONString("中国", SerializerFeature.BrowserSecure));
|
||||
}
|
||||
|
||||
public void test_all() throws Exception {
|
||||
String value = ".,_~!@<>'\"\\/hello world 0123;汉字;\u2028\u2028\r\n<script></scirpt>";
|
||||
String expect = "\".,_\\u007E\\u0021\\u0040\\u003C\\u003E\\u0027\\u0022\\u005C\\u002Fhello\\u0020world\\u00200123\\u003B\\u6C49\\u5B57\\uFF1B\\u2028\\u2028\\u000D\\u000A\\u003Cscript\\u003E\\u003C\\u002Fscirpt\\u003E\"";
|
||||
Assert.assertEquals(expect, JSON.toJSONString(value, SerializerFeature.BrowserSecure));
|
||||
}
|
||||
|
||||
public void test_all_map() throws Exception {
|
||||
String value = ".,_~!@<>'\"\\/hello world 0123;汉字;\u2028\u2028\r\n<script></scirpt>";
|
||||
|
||||
Map<String, String> map = new HashMap<String, String>();
|
||||
map.put("value", value);
|
||||
|
||||
String expect = "{\"value\":\".,_\\u007E\\u0021\\u0040\\u003C\\u003E\\u0027\\u0022\\u005C\\u002Fhello\\u0020world\\u00200123\\u003B\\u6C49\\u5B57\\uFF1B\\u2028\\u2028\\u000D\\u000A\\u003Cscript\\u003E\\u003C\\u002Fscirpt\\u003E\"}";
|
||||
String json = JSON.toJSONString(map, SerializerFeature.BrowserSecure);
|
||||
Assert.assertEquals(expect, json);
|
||||
|
||||
Assert.assertEquals(value, JSON.parseObject(json).get("value"));
|
||||
}
|
||||
|
||||
public void test_all_entity() throws Exception {
|
||||
String value = ".,_~!@<>'\"\\/hello world 0123;汉字;\u2028\u2028\r\n<script></scirpt>";
|
||||
|
||||
VO vo = new VO();
|
||||
vo.setValue(value);
|
||||
|
||||
String expect = "{\"value\":\".,_\\u007E\\u0021\\u0040\\u003C\\u003E\\u0027\\u0022\\u005C\\u002Fhello\\u0020world\\u00200123\\u003B\\u6C49\\u5B57\\uFF1B\\u2028\\u2028\\u000D\\u000A\\u003Cscript\\u003E\\u003C\\u002Fscirpt\\u003E\"}";
|
||||
String json = JSON.toJSONString(vo, SerializerFeature.BrowserSecure);
|
||||
Assert.assertEquals(expect, json);
|
||||
|
||||
Assert.assertEquals(value, JSON.parseObject(json, VO.class).getValue());
|
||||
}
|
||||
|
||||
public static class VO {
|
||||
|
||||
String value;
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -14,4 +14,12 @@ public class SerializerFeatureTest extends TestCase {
|
||||
feature = SerializerFeature.config(feature, SerializerFeature.BrowserCompatible, false);
|
||||
Assert.assertEquals(false, SerializerFeature.isEnabled(feature, SerializerFeature.BrowserCompatible));
|
||||
}
|
||||
|
||||
public void test_1 () throws Exception {
|
||||
int feature = 0;
|
||||
feature = SerializerFeature.config(feature, SerializerFeature.BrowserSecure, true);
|
||||
Assert.assertEquals(true, SerializerFeature.isEnabled(feature, SerializerFeature.BrowserSecure));
|
||||
feature = SerializerFeature.config(feature, SerializerFeature.BrowserSecure, false);
|
||||
Assert.assertEquals(false, SerializerFeature.isEnabled(feature, SerializerFeature.BrowserSecure));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user