相信每个开发人员都用过json吧。然而在json常用的工具中鼎鼎有名的无非是fastjson和gson了,但是不知道小伙伴没有没有去了解过他们其中的源码设计?我们接下来重点看一下fastjson的toJSONString方法。
我们拿Student(String studentId,String studentName,Byte studentAge,Boolean studentSex)来做例子
byte age = 20;
Student student = new Student("0001","张三",age,true);
String s = JSONObject.toJSONString(student);
logger.info("s==={}",s);
我们直接跟进去toJSONString方法:
/**
* This method serializes the specified object into its equivalent Json representation. Note that this method works fine if the any of the object fields are of generic type,
* just the object itself should not be of a generic type. If you want to write out the object to a
* {@link Writer}, use {@link #writeJSONString(Writer, Object, SerializerFeature[])} instead.
*
* @param object the object for which json representation is to be created setting for fastjson
* @return Json representation of {@code object}.
*/
public static String toJSONString(Object object) {
return toJSONString(object, emptyFilters);
}
public static String toJSONString(Object object, SerializeFilter[] filters, SerializerFeature... features) {
return toJSONString(object, SerializeConfig.globalInstance, filters, null, DEFAULT_GENERATE_FEATURE, features);
}
//这里是我们的重点方法
/**
* @since 1.2.9
* @return
*/
public static String toJSONString(Object object, //
SerializeConfig config, //
SerializeFilter[] filters, //
String dateFormat, //
int defaultFeatures, //
SerializerFeature... features) {
SerializeWriter out = new SerializeWriter(null, defaultFeatures, features);
try {
JSONSerializer serializer = new JSONSerializer(out, config);
if (dateFormat != null && dateFormat.length() != 0) {
serializer.setDateFormat(dateFormat);
serializer.config(SerializerFeature.WriteDateUseDateFormat, true);
}
if (filters != null) {
for (SerializeFilter filter : filters) {
serializer.addFilter(filter);
}
}
serializer.write(object);
return out.toString();
} finally {
out.close();
}
}
我们看方法中的最后一行return out.toString();说明我们最终的转成的json字符串是写到out中去的,那么我们的重点对象就是这个out了也就是SerializeWriter了。
out.toString()方法:我们可以看到SerializeWriter中维护了一个字符数组buf[]来写入数据的。
private final static Charset UTF8 = Charset.forName("UTF-8");
private final static ThreadLocal bufLocal = new ThreadLocal();
private final static ThreadLocal bytesBufLocal = new ThreadLocal();
protected char buf[];
/**
* The number of chars in the buffer.
*/
protected int count;
public String toString() {
return new String(buf, 0, count);
}
那是如何写入到out对象中的buf呢?那就还得回去看我们的toJSONString方法了,我们可以看到serializer.write(object)这行,这个是写入out的方法,但是在写入对象之前,serializer进行了初始化并设置了一些参数:
JSONSerializer serializer = new JSONSerializer(out, config);
if (dateFormat != null && dateFormat.length() != 0) {
serializer.setDateFormat(dateFormat);
serializer.config(SerializerFeature.WriteDateUseDateFormat, true);
}
if (filters != null) {
for (SerializeFilter filter : filters) {
serializer.addFilter(filter);
}
}
serializer.write(object);
JSONSerializer serializer = new JSONSerializer(out,config);这行代码说明了,serilaizer对象中维护着out和config两个东西,out就是我们刚才说的out了,而config是什么东西呢?部分代码如下:
我们可以看到该类维护一个主要的map对象IdentityHashMap
* circular references detect
*
* @author wenshao[[email protected]]
*/
public class SerializeConfig {
public final static SerializeConfig globalInstance = new SerializeConfig();
private static boolean awtError = false;
private static boolean jdk8Error = false;
private static boolean oracleJdbcError = false;
private static boolean springfoxError = false;
private static boolean guavaError = false;
private boolean asm = !ASMUtils.IS_ANDROID;
private ASMSerializerFactory asmFactory;
protected String typeKey = JSON.DEFAULT_TYPE_KEY;
public PropertyNamingStrategy propertyNamingStrategy;
private final IdentityHashMap serializers;
public SerializeConfig() {
this(1024);
}
public SerializeConfig(int tableSize) {
serializers = new IdentityHashMap(1024);
try {
if (asm) {
asmFactory = new ASMSerializerFactory();
}
} catch (Throwable eror) {
asm = false;
// } catch (ExceptionInInitializerError error) {
// asm = false;
}
put(Boolean.class, BooleanCodec.instance);
put(Character.class, CharacterCodec.instance);
put(Byte.class, IntegerCodec.instance);
put(Short.class, IntegerCodec.instance);
put(Integer.class, IntegerCodec.instance);
put(Long.class, LongCodec.instance);
put(Float.class, FloatCodec.instance);
put(Double.class, DoubleSerializer.instance);
put(BigDecimal.class, BigDecimalCodec.instance);
put(BigInteger.class, BigIntegerCodec.instance);
put(String.class, StringCodec.instance);
put(byte[].class, PrimitiveArraySerializer.instance);
put(short[].class, PrimitiveArraySerializer.instance);
put(int[].class, PrimitiveArraySerializer.instance);
put(long[].class, PrimitiveArraySerializer.instance);
put(float[].class, PrimitiveArraySerializer.instance);
put(double[].class, PrimitiveArraySerializer.instance);
put(boolean[].class, PrimitiveArraySerializer.instance);
put(char[].class, PrimitiveArraySerializer.instance);
put(Object[].class, ObjectArrayCodec.instance);
put(Class.class, MiscCodec.instance);
put(SimpleDateFormat.class, MiscCodec.instance);
put(Currency.class, new MiscCodec());
put(TimeZone.class, MiscCodec.instance);
put(InetAddress.class, MiscCodec.instance);
put(Inet4Address.class, MiscCodec.instance);
put(Inet6Address.class, MiscCodec.instance);
put(InetSocketAddress.class, MiscCodec.instance);
put(File.class, MiscCodec.instance);
put(Appendable.class, AppendableSerializer.instance);
put(StringBuffer.class, AppendableSerializer.instance);
put(StringBuilder.class, AppendableSerializer.instance);
put(Charset.class, ToStringSerializer.instance);
put(Pattern.class, ToStringSerializer.instance);
put(Locale.class, ToStringSerializer.instance);
put(URI.class, ToStringSerializer.instance);
put(URL.class, ToStringSerializer.instance);
put(UUID.class, ToStringSerializer.instance);
// atomic
put(AtomicBoolean.class, AtomicCodec.instance);
put(AtomicInteger.class, AtomicCodec.instance);
put(AtomicLong.class, AtomicCodec.instance);
put(AtomicReference.class, ReferenceCodec.instance);
put(AtomicIntegerArray.class, AtomicCodec.instance);
put(AtomicLongArray.class, AtomicCodec.instance);
put(WeakReference.class, ReferenceCodec.instance);
put(SoftReference.class, ReferenceCodec.instance);
}
我们知道了serializer里面放了out和config就够了,接下来看我们serializer.writer(object);方法是如何执行的:
看的第一眼是不是觉得,怎么可以这么简单(哈哈~我第一样反正是这样认为的)。
public final void write(Object object) {
if (object == null) {
out.writeNull();
return;
}
Class> clazz = object.getClass();
ObjectSerializer writer = getObjectWriter(clazz);
try {
writer.write(this, object, null, null, 0);
} catch (IOException e) {
throw new JSONException(e.getMessage(), e);
}
}
我们一行一行来看。我的习惯是先看最后一行也就是return行,此方法没有return那我们就看最后一行,writer.writer(this,object,null,null,0);当我们跟进去看源码时发现是个接口,没有具体的方法实现,所以我们现在要找出的是writer这个对象具体是哪个类中的write方法(这是我们的重点看的地方),然后我们接着看,if语句不用看我传的obj不可能为null的,所以就剩两行了,准确的说是一行:ObjectSerializer writer = getObjectWriter(clazz);我们继续:
public ObjectSerializer getObjectWriter(Class> clazz) {
return config.getObjectWriter(clazz);
}
咦~,这个config有没有很熟悉啊,就是我们刚才维护map的那个config,这行的代码就是从map里获取一个serializer,我们可以回过头看一下刚才config初始化时放了什么,都是一些java原始的类对应的serializer,并没有我们clazz对应的value值,获取的应该是null啊,别着急,我们继续看config.getObjectWriter(clazz);
哇,是真的长,但是关键的就那几步:
public ObjectSerializer getObjectWriter(Class> clazz) {
return getObjectWriter(clazz, true);
}
private ObjectSerializer getObjectWriter(Class> clazz, boolean create) {
ObjectSerializer writer = serializers.get(clazz);
if (writer == null) {
try {
final ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
for (Object o : ServiceLoader.load(AutowiredObjectSerializer.class, classLoader)) {
if (!(o instanceof AutowiredObjectSerializer)) {
continue;
}
AutowiredObjectSerializer autowired = (AutowiredObjectSerializer) o;
for (Type forType : autowired.getAutowiredFor()) {
put(forType, autowired);
}
}
} catch (ClassCastException ex) {
// skip
}
writer = serializers.get(clazz);
}
if (writer == null) {
final ClassLoader classLoader = JSON.class.getClassLoader();
if (classLoader != Thread.currentThread().getContextClassLoader()) {
try {
for (Object o : ServiceLoader.load(AutowiredObjectSerializer.class, classLoader)) {
if (!(o instanceof AutowiredObjectSerializer)) {
continue;
}
AutowiredObjectSerializer autowired = (AutowiredObjectSerializer) o;
for (Type forType : autowired.getAutowiredFor()) {
put(forType, autowired);
}
}
} catch (ClassCastException ex) {
// skip
}
writer = serializers.get(clazz);
}
}
if (writer == null) {
if (Map.class.isAssignableFrom(clazz)) {
put(clazz, MapSerializer.instance);
} else if (List.class.isAssignableFrom(clazz)) {
put(clazz, ListSerializer.instance);
} else if (Collection.class.isAssignableFrom(clazz)) {
put(clazz, CollectionCodec.instance);
} else if (Date.class.isAssignableFrom(clazz)) {
put(clazz, DateCodec.instance);
} else if (JSONAware.class.isAssignableFrom(clazz)) {
put(clazz, JSONAwareSerializer.instance);
} else if (JSONSerializable.class.isAssignableFrom(clazz)) {
put(clazz, JSONSerializableSerializer.instance);
} else if (JSONStreamAware.class.isAssignableFrom(clazz)) {
put(clazz, MiscCodec.instance);
} else if (clazz.isEnum() || (clazz.getSuperclass() != null && clazz.getSuperclass().isEnum())) {
JSONType jsonType = clazz.getAnnotation(JSONType.class);
if (jsonType != null && jsonType.serializeEnumAsJavaBean()) {
put(clazz, createJavaBeanSerializer(clazz));
} else {
put(clazz, EnumSerializer.instance);
}
} else if (clazz.isArray()) {
Class> componentType = clazz.getComponentType();
ObjectSerializer compObjectSerializer = getObjectWriter(componentType);
put(clazz, new ArraySerializer(componentType, compObjectSerializer));
} else if (Throwable.class.isAssignableFrom(clazz)) {
SerializeBeanInfo beanInfo = TypeUtils.buildBeanInfo(clazz, null, propertyNamingStrategy);
beanInfo.features |= SerializerFeature.WriteClassName.mask;
put(clazz, new JavaBeanSerializer(beanInfo));
} else if (TimeZone.class.isAssignableFrom(clazz) || Map.Entry.class.isAssignableFrom(clazz)) {
put(clazz, MiscCodec.instance);
} else if (Appendable.class.isAssignableFrom(clazz)) {
put(clazz, AppendableSerializer.instance);
} else if (Charset.class.isAssignableFrom(clazz)) {
put(clazz, ToStringSerializer.instance);
} else if (Enumeration.class.isAssignableFrom(clazz)) {
put(clazz, EnumerationSerializer.instance);
} else if (Calendar.class.isAssignableFrom(clazz) //
|| XMLGregorianCalendar.class.isAssignableFrom(clazz)) {
put(clazz, CalendarCodec.instance);
} else if (Clob.class.isAssignableFrom(clazz)) {
put(clazz, ClobSeriliazer.instance);
} else if (TypeUtils.isPath(clazz)) {
put(clazz, ToStringSerializer.instance);
} else if (Iterator.class.isAssignableFrom(clazz)) {
put(clazz, MiscCodec.instance);
} else {
String className = clazz.getName();
if (className.startsWith("java.awt.") //
&& AwtCodec.support(clazz) //
) {
// awt
if (!awtError) {
try {
put(Class.forName("java.awt.Color"), AwtCodec.instance);
put(Class.forName("java.awt.Font"), AwtCodec.instance);
put(Class.forName("java.awt.Point"), AwtCodec.instance);
put(Class.forName("java.awt.Rectangle"), AwtCodec.instance);
} catch (Throwable e) {
awtError = true;
// skip
}
}
return AwtCodec.instance;
}
// jdk8
if ((!jdk8Error) //
&& (className.startsWith("java.time.") //
|| className.startsWith("java.util.Optional") //
|| className.equals("java.util.concurrent.atomic.LongAdder")
|| className.equals("java.util.concurrent.atomic.DoubleAdder")
)) {
try {
put(Class.forName("java.time.LocalDateTime"), Jdk8DateCodec.instance);
put(Class.forName("java.time.LocalDate"), Jdk8DateCodec.instance);
put(Class.forName("java.time.LocalTime"), Jdk8DateCodec.instance);
put(Class.forName("java.time.ZonedDateTime"), Jdk8DateCodec.instance);
put(Class.forName("java.time.OffsetDateTime"), Jdk8DateCodec.instance);
put(Class.forName("java.time.OffsetTime"), Jdk8DateCodec.instance);
put(Class.forName("java.time.ZoneOffset"), Jdk8DateCodec.instance);
put(Class.forName("java.time.ZoneRegion"), Jdk8DateCodec.instance);
put(Class.forName("java.time.Period"), Jdk8DateCodec.instance);
put(Class.forName("java.time.Duration"), Jdk8DateCodec.instance);
put(Class.forName("java.time.Instant"), Jdk8DateCodec.instance);
put(Class.forName("java.util.Optional"), OptionalCodec.instance);
put(Class.forName("java.util.OptionalDouble"), OptionalCodec.instance);
put(Class.forName("java.util.OptionalInt"), OptionalCodec.instance);
put(Class.forName("java.util.OptionalLong"), OptionalCodec.instance);
put(Class.forName("java.util.concurrent.atomic.LongAdder"), AdderSerializer.instance);
put(Class.forName("java.util.concurrent.atomic.DoubleAdder"), AdderSerializer.instance);
writer = serializers.get(clazz);
if (writer != null) {
return writer;
}
} catch (Throwable e) {
// skip
jdk8Error = true;
}
}
if ((!oracleJdbcError) //
&& className.startsWith("oracle.sql.")) {
try {
put(Class.forName("oracle.sql.DATE"), DateCodec.instance);
put(Class.forName("oracle.sql.TIMESTAMP"), DateCodec.instance);
writer = serializers.get(clazz);
if (writer != null) {
return writer;
}
} catch (Throwable e) {
// skip
oracleJdbcError = true;
}
}
if ((!springfoxError) //
&& className.equals("springfox.documentation.spring.web.json.Json")) {
try {
put(Class.forName("springfox.documentation.spring.web.json.Json"), //
SwaggerJsonSerializer.instance);
writer = serializers.get(clazz);
if (writer != null) {
return writer;
}
} catch (ClassNotFoundException e) {
// skip
springfoxError = true;
}
}
if ((!guavaError) //
&& className.startsWith("com.google.common.collect.")) {
try {
put(Class.forName("com.google.common.collect.HashMultimap"), //
GuavaCodec.instance);
put(Class.forName("com.google.common.collect.LinkedListMultimap"), //
GuavaCodec.instance);
put(Class.forName("com.google.common.collect.ArrayListMultimap"), //
GuavaCodec.instance);
put(Class.forName("com.google.common.collect.TreeMultimap"), //
GuavaCodec.instance);
writer = serializers.get(clazz);
if (writer != null) {
return writer;
}
} catch (ClassNotFoundException e) {
// skip
guavaError = true;
}
}
if (className.equals("net.sf.json.JSONNull")) {
try {
put(Class.forName("net.sf.json.JSONNull"), //
MiscCodec.instance);
} catch (ClassNotFoundException e) {
// skip
}
writer = serializers.get(clazz);
if (writer != null) {
return writer;
}
}
if (TypeUtils.isProxy(clazz)) {
Class> superClazz = clazz.getSuperclass();
ObjectSerializer superWriter = getObjectWriter(superClazz);
put(clazz, superWriter);
return superWriter;
}
if (create) {
put(clazz, createJavaBeanSerializer(clazz));
}
}
writer = serializers.get(clazz);
}
return writer;
}
一:ObjectSerializer writer = serializers.get(clazz);(先从map中取,肯定null的)
二:如果不是null,就去看这个class是不是map、list、array、collection等等,如果是从config中获取对应的serializer,最后发现都不是
三:都不是返回什么?你都没有就给你创建一个呗?最后执行到
put方法?,此时才去创建了一个JavaBeanSerializer放到了config中,也就是我们最终拿到那个writer就是createJavaBeanSerializer(clazz);返回的东西,我们不就是找这个吗?果断进去看下返回的JavaBeanSerializer是什么东西,里面的write方法是怎么写如到buff[]里面的。我们把部分代码和write方法摘出来看一下
/**
* @author wenshao[[email protected]]
*/
public class JavaBeanSerializer extends SerializeFilterable implements ObjectSerializer {
// serializers
protected final FieldSerializer[] getters;
protected final FieldSerializer[] sortedGetters;
protected SerializeBeanInfo beanInfo;
public void write(JSONSerializer serializer, //
Object object, //
Object fieldName, //
Type fieldType, //
int features) throws IOException {
SerializeWriter out = serializer.out;
if (object == null) {
out.writeNull();
return;
}
if (writeReference(serializer, object, features)) {
return;
}
final FieldSerializer[] getters;
if (out.sortField) {
getters = this.sortedGetters;
} else {
getters = this.getters;
}
SerialContext parent = serializer.context;
serializer.setContext(parent, object, fieldName, this.beanInfo.features, features);
final boolean writeAsArray = isWriteAsArray(serializer, features);
try {
final char startSeperator = writeAsArray ? '[' : '{';
final char endSeperator = writeAsArray ? ']' : '}';
out.append(startSeperator);
if (getters.length > 0 && out.isEnabled(SerializerFeature.PrettyFormat)) {
serializer.incrementIndent();
serializer.println();
}
boolean commaFlag = false;
if ((this.beanInfo.features & SerializerFeature.WriteClassName.mask) != 0
|| serializer.isWriteClassName(fieldType, object)) {
Class> objClass = object.getClass();
if (objClass != fieldType) {
writeClassName(serializer, object);
commaFlag = true;
}
}
char seperator = commaFlag ? ',' : '\0';
final boolean directWritePrefix = out.quoteFieldNames && !out.useSingleQuotes;
char newSeperator = this.writeBefore(serializer, object, seperator);
commaFlag = newSeperator == ',';
final boolean skipTransient = out.isEnabled(SerializerFeature.SkipTransientField);
final boolean ignoreNonFieldGetter = out.isEnabled(SerializerFeature.IgnoreNonFieldGetter);
for (int i = 0; i < getters.length; ++i) {
FieldSerializer fieldSerializer = getters[i];
Field field = fieldSerializer.fieldInfo.field;
FieldInfo fieldInfo = fieldSerializer.fieldInfo;
String fieldInfoName = fieldInfo.name;
Class> fieldClass = fieldInfo.fieldClass;
if (skipTransient) {
if (field != null) {
if (fieldInfo.fieldTransient) {
continue;
}
}
}
if (ignoreNonFieldGetter) {
if (field == null) {
continue;
}
}
if ((!this.applyName(serializer, object, fieldInfo.name)) //
|| !this.applyLabel(serializer, fieldInfo.label)) {
continue;
}
Object propertyValue;
try {
propertyValue = fieldSerializer.getPropertyValueDirect(object);
} catch (InvocationTargetException ex) {
if (out.isEnabled(SerializerFeature.IgnoreErrorGetter)) {
propertyValue = null;
} else {
throw ex;
}
}
if (!this.apply(serializer, object, fieldInfoName, propertyValue)) {
continue;
}
String key = fieldInfoName;
key = this.processKey(serializer, object, key, propertyValue);
Object originalValue = propertyValue;
propertyValue = this.processValue(serializer, fieldSerializer.fieldContext, object, fieldInfoName,
propertyValue);
if (propertyValue == null && !writeAsArray) {
if ((!fieldSerializer.writeNull) && (!out.isEnabled(SerializerFeature.WRITE_MAP_NULL_FEATURES))) {
continue;
}
}
if (propertyValue != null && out.notWriteDefaultValue) {
Class> fieldCLass = fieldInfo.fieldClass;
if (fieldCLass == byte.class && propertyValue instanceof Byte
&& ((Byte) propertyValue).byteValue() == 0) {
continue;
} else if (fieldCLass == short.class && propertyValue instanceof Short
&& ((Short) propertyValue).shortValue() == 0) {
continue;
} else if (fieldCLass == int.class && propertyValue instanceof Integer
&& ((Integer) propertyValue).intValue() == 0) {
continue;
} else if (fieldCLass == long.class && propertyValue instanceof Long
&& ((Long) propertyValue).longValue() == 0L) {
continue;
} else if (fieldCLass == float.class && propertyValue instanceof Float
&& ((Float) propertyValue).floatValue() == 0F) {
continue;
} else if (fieldCLass == double.class && propertyValue instanceof Double
&& ((Double) propertyValue).doubleValue() == 0D) {
continue;
} else if (fieldCLass == boolean.class && propertyValue instanceof Boolean
&& !((Boolean) propertyValue).booleanValue()) {
continue;
}
}
if (commaFlag) {
out.write(',');
if (out.isEnabled(SerializerFeature.PrettyFormat)) {
serializer.println();
}
}
if (key != fieldInfoName) {
if (!writeAsArray) {
out.writeFieldName(key, true);
}
serializer.write(propertyValue);
} else if (originalValue != propertyValue) {
if (!writeAsArray) {
fieldSerializer.writePrefix(serializer);
}
serializer.write(propertyValue);
} else {
if (!writeAsArray) {
if (directWritePrefix) {
out.write(fieldInfo.name_chars, 0, fieldInfo.name_chars.length);
} else {
fieldSerializer.writePrefix(serializer);
}
}
if (!writeAsArray) {
JSONField fieldAnnotation = fieldInfo.getAnnotation();
if (fieldClass == String.class && (fieldAnnotation == null || fieldAnnotation.serializeUsing() == Void.class)) {
if (propertyValue == null) {
if ((out.features & SerializerFeature.WriteNullStringAsEmpty.mask) != 0
|| (fieldSerializer.features
& SerializerFeature.WriteNullStringAsEmpty.mask) != 0) {
out.writeString("");
} else {
out.writeNull();
}
} else {
String propertyValueString = (String) propertyValue;
if (out.useSingleQuotes) {
out.writeStringWithSingleQuote(propertyValueString);
} else {
out.writeStringWithDoubleQuote(propertyValueString, (char) 0);
}
}
} else {
fieldSerializer.writeValue(serializer, propertyValue);
}
} else {
fieldSerializer.writeValue(serializer, propertyValue);
}
}
commaFlag = true;
}
this.writeAfter(serializer, object, commaFlag ? ',' : '\0');
if (getters.length > 0 && out.isEnabled(SerializerFeature.PrettyFormat)) {
serializer.decrementIdent();
serializer.println();
}
out.append(endSeperator);
} catch (Exception e) {
String errorMessage = "write javaBean error";
if (object != null) {
errorMessage += ", class " + object.getClass().getName();
}
if (fieldName != null) {
errorMessage += ", fieldName : " + fieldName;
}
if (e.getMessage() != null) {
errorMessage += (", " + e.getMessage());
}
throw new JSONException(errorMessage, e);
} finally {
serializer.context = parent;
}
}
首先里面有两个数组和一个beanInfo,getters里面放的是obj的变量名称、变量类型、method等信息,最终利用这些拼接起来的写入的out对象里的,beanInfo就是obj类名、class类型等class的属性。
这就是fastjson中toJSONString()方法的大致流程了,不知道小伙伴们了解吗?