JSONObject转换分析
net.sf.json.JSONObject采用反射的方式,对POJO进行转换。JSONObject类实现了JSON、Map和Comparable接口,如下:
class JSONObject extends AbstractJSON implements JSON, Map, Comparable
以Person类为例分析源码:
public class Person { private String name; private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
fromObject(Object object)方法:
代码实现主要在JSONObject defaultBeanProcessing(Object bean, JsonConfig jsonConfig)方法中,如下:
private static JSONObject defaultBeanProcessing(Object bean, JsonConfig jsonConfig) { Class beanClass = bean.getClass(); //获取类对象 class net.sf.json.mytest.Person PropertyNameProcessor propertyNameProcessor = jsonConfig.findJsonPropertyNameProcessor( beanClass ); Collection exclusions = jsonConfig.getMergedExcludes( beanClass );//需要排除的类信息,[metaClass, declaringClass, class] JSONObject jsonObject = new JSONObject(); try{ PropertyDescriptor[] pds = PropertyUtils.getPropertyDescriptors( bean );//获取POJO类的描述信息,包括属性、属性对应的读写操作,
//[java.beans.PropertyDescriptor[name=age; propertyType=int; readMethod=public int net.sf.json.mytest.Person.getAge(); writeMethod=public void net.sf.json.mytest.Person.setAge(int)],
//java.beans.PropertyDescriptor[name=class; propertyType=class java.lang.Class; readMethod=public final native java.lang.Class java.lang.Object.getClass()],
//java.beans.PropertyDescriptor[name=name; propertyType=class java.lang.String; readMethod=public java.lang.String net.sf.json.mytest.Person.getName(); writeMethod=public void net.sf.json.mytest.Person.setName(java.lang.String)]] PropertyFilter jsonPropertyFilter = jsonConfig.getJsonPropertyFilter(); //循环对所有属性进行处理 for( int i = 0; i < pds.length; i++ ){ boolean bypass = false; //获取属性名 String key = pds[i].getName(); if( exclusions.contains( key ) ){ continue; } if( jsonConfig.isIgnoreTransientFields() && isTransientField( key, beanClass ) ){ continue; } Class type = pds[i].getPropertyType(); try { pds[i].getReadMethod(); } catch( Exception e ) { // bug 2565295 String warning = "Property '" + key + "' of "+ beanClass+" has no read method. SKIPPED"; fireWarnEvent( warning, jsonConfig ); log.info( warning ); continue; } if( pds[i].getReadMethod() != null ){ Object value = PropertyUtils.getProperty( bean, key ); if( jsonPropertyFilter != null && jsonPropertyFilter.apply( bean, key, value ) ){ continue; } JsonValueProcessor jsonValueProcessor = jsonConfig.findJsonValueProcessor( beanClass, type, key ); if( jsonValueProcessor != null ){ value = jsonValueProcessor.processObjectValue( key, value, jsonConfig ); bypass = true; if( !JsonVerifier.isValidJsonValue( value ) ){ throw new JSONException( "Value is not a valid JSON value. " + value ); } } if( propertyNameProcessor != null ){ key = propertyNameProcessor.processPropertyName( beanClass, key ); } //设置属性值 setValue( jsonObject, key, value, type, jsonConfig, bypass ); }else{ String warning = "Property '" + key + "' of "+ beanClass+" has no read method. SKIPPED"; fireWarnEvent( warning, jsonConfig ); log.info( warning ); } } ....... }catch( JSONException jsone ){ removeInstance( bean ); fireErrorEvent( jsone, jsonConfig ); throw jsone; }catch( Exception e ){ removeInstance( bean ); JSONException jsone = new JSONException( e ); fireErrorEvent( jsone, jsonConfig ); throw jsone; } return jsonObject; }
toBean(JSONObject object, Class clazz)方法
由JSONObject对象转为对应类实例,关键代码在Object toBean( JSONObject jsonObject, JsonConfig jsonConfig )中,如下:
public static Object toBean( JSONObject jsonObject, JsonConfig jsonConfig ) {
if( jsonObject == null || jsonObject.isNullObject() ){ return null; } Class beanClass = jsonConfig.getRootClass();//类对象 Map classMap = jsonConfig.getClassMap(); if( beanClass == null ){ return toBean( jsonObject ); } if( classMap == null ){ classMap = Collections.EMPTY_MAP; } Object bean = null; try{ if( beanClass.isInterface() ){ if( !Map.class.isAssignableFrom( beanClass ) ){ throw new JSONException( "beanClass is an interface. " + beanClass ); }else{ bean = new HashMap(); } }else{ bean = jsonConfig.getNewBeanInstanceStrategy() //实例化 .newInstance( beanClass, jsonObject ); } }catch( JSONException jsone ){ throw jsone; }catch( Exception e ){ throw new JSONException( e ); } Map props = JSONUtils.getProperties( jsonObject );//属性及属性类型 {name=class java.lang.String, age=class java.lang.Integer} PropertyFilter javaPropertyFilter = jsonConfig.getJavaPropertyFilter(); for( Iterator entries = jsonObject.names( jsonConfig ) .iterator(); entries.hasNext(); ){ String name = (String) entries.next();//属性名 Class type = (Class) props.get( name );//属性类型 Object value = jsonObject.get( name );//属性值,如果属性值为null,返回的值为JSONNull对象 if( javaPropertyFilter != null && javaPropertyFilter.apply( bean, name, value ) ){ continue; } String key = Map.class.isAssignableFrom( beanClass ) && jsonConfig.isSkipJavaIdentifierTransformationInMapKeys() ? name : JSONUtils.convertToJavaIdentifier( name, jsonConfig ); PropertyNameProcessor propertyNameProcessor = jsonConfig.findJavaPropertyNameProcessor( beanClass ); if( propertyNameProcessor != null ){ key = propertyNameProcessor.processPropertyName( beanClass, key ); } //设置实例对象的属性(处理各种情况) try{ if( Map.class.isAssignableFrom( beanClass ) ){//Map对象单独处理 // no type info available for conversion if( JSONUtils.isNull( value ) ){ setProperty( bean, key, value, jsonConfig ); }else if( value instanceof JSONArray ){ setProperty( bean, key, convertPropertyValueToCollection( key, value, jsonConfig, name, classMap, List.class ), jsonConfig ); }else if( String.class.isAssignableFrom( type ) || JSONUtils.isBoolean( type ) || JSONUtils.isNumber( type ) || JSONUtils.isString( type ) || JSONFunction.class.isAssignableFrom( type ) ){ if( jsonConfig.isHandleJettisonEmptyElement() && "".equals( value ) ){ setProperty( bean, key, null, jsonConfig ); }else{ setProperty( bean, key, value, jsonConfig ); } }else{ Class targetClass = resolveClass(classMap, key, name, type); JsonConfig jsc = jsonConfig.copy(); jsc.setRootClass( targetClass ); jsc.setClassMap( classMap ); if( targetClass != null ){ setProperty( bean, key, toBean( (JSONObject) value, jsc ), jsonConfig ); }else{ setProperty( bean, key, toBean( (JSONObject) value ), jsonConfig ); } } }else{ PropertyDescriptor pd = PropertyUtils.getPropertyDescriptor( bean, key );//获取属性描述
//java.beans.PropertyDescriptor[name=name; propertyType=class java.lang.String; readMethod=public java.lang.String net.sf.json.mytest.Person.getName(); writeMethod=public void net.sf.json.mytest.Person.setName(java.lang.String)] if( pd != null && pd.getWriteMethod() == null ){ log.info( "Property '" + key + "' of "+ bean.getClass()+" has no write method. SKIPPED." ); continue; } if( pd != null ){ Class targetType = pd.getPropertyType(); if( !JSONUtils.isNull( value ) ){ if( value instanceof JSONArray ){ //JSONArray值 if( List.class.isAssignableFrom( pd.getPropertyType() ) ){ setProperty( bean, key, convertPropertyValueToCollection( key, value, jsonConfig, name, classMap, pd.getPropertyType() ), jsonConfig ); }else if( Set.class.isAssignableFrom( pd.getPropertyType() ) ){ setProperty( bean, key, convertPropertyValueToCollection( key, value, jsonConfig, name, classMap, pd.getPropertyType() ), jsonConfig ); }else{ setProperty( bean, key, convertPropertyValueToArray( key, value, targetType, jsonConfig, classMap ), jsonConfig ); } }else if( String.class.isAssignableFrom( type ) || JSONUtils.isBoolean( type ) //基本类型 || JSONUtils.isNumber( type ) || JSONUtils.isString( type ) || JSONFunction.class.isAssignableFrom( type ) ){ if( pd != null ){ if( jsonConfig.isHandleJettisonEmptyElement() && "".equals( value ) ){ setProperty( bean, key, null, jsonConfig ); }else if( !targetType.isInstance( value ) ){ setProperty( bean, key, morphPropertyValue( key, value, type, targetType ), jsonConfig ); }else{ setProperty( bean, key, value, jsonConfig );//对String进行处理 } }else if( beanClass == null || bean instanceof Map ){ setProperty( bean, key, value, jsonConfig ); }else{ log.warn( "Tried to assign property " + key + ":" + type.getName() + " to bean of class " + bean.getClass() .getName() ); } }else{ if( jsonConfig.isHandleJettisonSingleElementArray() ){ JSONArray array = new JSONArray().element( value, jsonConfig ); Class newTargetClass = resolveClass(classMap, key, name, type); JsonConfig jsc = jsonConfig.copy(); jsc.setRootClass( newTargetClass ); jsc.setClassMap( classMap ); if( targetType.isArray() ){ setProperty( bean, key, JSONArray.toArray( array, jsc ), jsonConfig ); }else if( JSONArray.class.isAssignableFrom( targetType ) ){ setProperty( bean, key, array, jsonConfig ); }else if( List.class.isAssignableFrom( targetType ) || Set.class.isAssignableFrom( targetType ) ){ jsc.setCollectionType( targetType ); setProperty( bean, key, JSONArray.toCollection( array, jsc ), jsonConfig ); }else{ setProperty( bean, key, toBean( (JSONObject) value, jsc ), jsonConfig ); } }else{ if( targetType == Object.class || targetType.isInterface() ) { Class targetTypeCopy = targetType; targetType = findTargetClass( key, classMap ); targetType = targetType == null ? findTargetClass( name, classMap ) : targetType; targetType = targetType == null && targetTypeCopy.isInterface() ? targetTypeCopy : targetType; } JsonConfig jsc = jsonConfig.copy(); jsc.setRootClass( targetType ); jsc.setClassMap( classMap ); setProperty( bean, key, toBean( (JSONObject) value, jsc ), jsonConfig ); } } }else{ if( type.isPrimitive() ){ // assume assigned default value log.warn( "Tried to assign null value to " + key + ":" + type.getName() ); setProperty( bean, key, JSONUtils.getMorpherRegistry() .morph( type, null ), jsonConfig ); }else{ setProperty( bean, key, null, jsonConfig ); } } }else{ // pd is null if( !JSONUtils.isNull( value ) ){ if( value instanceof JSONArray ){ setProperty( bean, key, convertPropertyValueToCollection( key, value, jsonConfig, name, classMap, List.class ), jsonConfig ); }else if( String.class.isAssignableFrom( type ) || JSONUtils.isBoolean( type ) || JSONUtils.isNumber( type ) || JSONUtils.isString( type ) || JSONFunction.class.isAssignableFrom( type ) ){ if( beanClass == null || bean instanceof Map || jsonConfig.getPropertySetStrategy() != null || !jsonConfig.isIgnorePublicFields() ){ setProperty( bean, key, value, jsonConfig ); }else{ log.warn( "Tried to assign property " + key + ":" + type.getName() + " to bean of class " + bean.getClass() .getName() ); } }else{ if( jsonConfig.isHandleJettisonSingleElementArray() ){ Class newTargetClass = resolveClass(classMap, key, name, type); JsonConfig jsc = jsonConfig.copy(); jsc.setRootClass( newTargetClass ); jsc.setClassMap( classMap ); setProperty( bean, key, toBean( (JSONObject) value, jsc ), jsonConfig ); }else{ setProperty( bean, key, value, jsonConfig ); } } }else{ if( type.isPrimitive() ){ // assume assigned default value log.warn( "Tried to assign null value to " + key + ":" + type.getName() ); setProperty( bean, key, JSONUtils.getMorpherRegistry() .morph( type, null ), jsonConfig ); }else{ setProperty( bean, key, null, jsonConfig ); } } } } }catch( JSONException jsone ){ throw jsone; }catch( Exception e ){ throw new JSONException( "Error while setting property=" + name + " type " + type, e ); } } return bean; }
另外,Map转JSONObject问题:
会将Map结构({key=value})转换为json格式(“key”:"value")。
(1)java中的null,会转换为JSONNull对象,不能直接将该对象转为String。
(2)net.sf.json.JSONObject不支持Map中key为null的情况。
举例如下:
import java.util.HashMap; import java.util.Map; import net.sf.json.JSONNull; import net.sf.json.JSONObject; public class Test { public static void main(String[] args) { Map<String, String> data1 = new HashMap<>(); // data1.put(null, "empty"); //报JSON keys cannot be null. data1.put("ts", null); System.out.println(data1.toString()); if(data1.get("ts")==null){ System.out.println("Map中的null"); } JSONObject jsonObject = JSONObject.fromObject(data1); System.out.println(jsonObject.toString()); if(JSONNull.getInstance().equals(jsonObject.get("ts"))){ System.out.println("Map中的null,转为net.sf.json.JSONObject后,变成net.sf.json.JSONNull"); } Map<String, Object> map = (Map<String, Object>) JSONObject.toBean(jsonObject, HashMap.class); System.out.println(map.get("ts").toString()); // Map<String, String> map = (Map<String, String>) JSONObject.toBean(jsonObject, HashMap.class); // System.out.println(map.get("ts").toString()); //java.lang.ClassCastException: net.sf.json.JSONNull cannot be cast to java.lang.String } }
结果:
{ts=null} Map中的null {"ts":null} Map中的null,转为net.sf.json.JSONObject后,变成net.sf.json.JSONNull
这是水木竹水的博客