org.json包深解析JSON字符串并转化javaBean
前言
在使用org.json.JSONObject解析json字符串并转化为JavaBean的时候,发现只能进行浅解析,如果JavaBean的属性中含有JavaBean、Map、List等属性时,JSONObject无法进行解析转化。
在网上大量搜索,没有发现能够进行深解析的办法或公开代码
因此,无奈之下自己动手写了一个深解析的方法,用于将JSON字符串完全解析并转化为JavaBean,主要是利用Java 反射原理实现。
测试通过了JavaBean中包含Map、List、JavaBean、枚举类型等属性及这些属性的层层嵌套的情况,最终均成功完成深解析,获得完整属性填充的JavaBean对象。
代码如下、欢迎自取;
使用时通过调用jsonToBean方法,传入json字符串及需要转化的JavaBean类型即可。
public static<T> T jsonToBean(String jsonStr, Class<T> javaBeanClazz) throws NoSuchMethodException, NoSuchFieldException, InstantiationException, IllegalAccessException, InvocationTargetException {
return toJavaBean(new JSONObject(jsonStr), javaBeanClazz);
}
public static <T> T toJavaBean(JSONObject map, Class<T> javaBeanClazz)
throws JSONException, InvocationTargetException, IllegalAccessException, NoSuchFieldException, InstantiationException, NoSuchMethodException {
Method[] beanMethods = javaBeanClazz.getDeclaredMethods();
String methodProfix = "set";
T javaBean = null;
try {
//enum类型不进行实例化
if(!Enum.class.isAssignableFrom(javaBeanClazz)) {
javaBean = javaBeanClazz.newInstance();
} else {
//enum类型默认使用findByValue方法,特殊情况再特殊处理
methodProfix = "findBy";
//if(AdActionType.class.equals(javaBeanClazz)){
// methodProfix = "findBy";
//}
}
} catch (Exception e){
throw new JSONException("Can not create a instance of Class "
+ javaBeanClazz.getName() + ".");
}
for (Method method : beanMethods) {
if (method.getName().startsWith(methodProfix)) {
String field = method.getName();
field = field.substring(field.indexOf(methodProfix) + methodProfix.length());
field = field.toLowerCase().charAt(0) + field.substring(1);
Type declaredFieldType = javaBeanClazz.getDeclaredField(field).getGenericType();
//部分方法同样以set开头,但不是默认set方法
Class<?>[] parameterTypes = method.getParameterTypes();
if(!(parameterTypes.length == 1 &&
(ParameterizedType.class.isAssignableFrom(declaredFieldType.getClass())
&& ((ParameterizedType) declaredFieldType).getRawType().equals(parameterTypes[0]) ||
(parameterTypes[0] == declaredFieldType)))
){
continue;
}
Object fieldValue = null;
try {
fieldValue = map.get(field);
} catch (JSONException e){
//e.printStackTrace();
continue;
}
//enum类型
if(Enum.class.isAssignableFrom(javaBeanClazz)){
javaBean = (T) method.invoke(null, fieldValue);
break;
}
Object paddingField = getPaddingField(declaredFieldType, fieldValue);
method.invoke(javaBean, paddingField);
}
}
return javaBean;
}
private static <T> Object getPaddingField(Type declaredFieldType, Object fieldValue) throws InvocationTargetException, IllegalAccessException, NoSuchMethodException, NoSuchFieldException, InstantiationException {
Object result = fieldValue;
if(Class.class.isAssignableFrom(declaredFieldType.getClass())){
if(fieldValue.getClass() == JSONObject.class) {
result = toJavaBean((JSONObject) fieldValue, (Class) declaredFieldType);
} else {
if(!declaredFieldType.equals(fieldValue.getClass())) {
result = getBaseTypeField((Class) declaredFieldType, fieldValue.toString());
}
}
} else if(ParameterizedType.class.isAssignableFrom(declaredFieldType.getClass())) {
//具体集合/Map类型
Class<?> rawType = (Class<?>) ((ParameterizedType) declaredFieldType).getRawType();
if (Collection.class.isAssignableFrom(rawType)) {
Type elementType = ((ParameterizedType) declaredFieldType).getActualTypeArguments()[0];
Collection<Object> collection = null;
if (List.class.isAssignableFrom(rawType)) {//List默认ArrayList
collection = new ArrayList<>();
} else if (Set.class.isAssignableFrom(rawType)) {//Set默认HashSet
collection = new HashSet<>();
}
if(ParameterizedType.class.isAssignableFrom(elementType.getClass())){
//递归调用
for(Object element : (JSONArray)fieldValue){
collection.add(getPaddingField(elementType, element));
}
} else if(Class.class.isAssignableFrom(elementType.getClass())){
Class elementClass = (Class) elementType;
boolean isBaseType = isBaseType((Class) elementType);
for(Object element : (JSONArray)fieldValue){
if(isBaseType){
collection.add(element);
} else {
collection.add(toJavaBean((JSONObject) element, elementClass));
}
}
}
result = collection;
//Set默认使用HashSet
} else if (Map.class.isAssignableFrom((Class) rawType)) {
Type[] actualTypeArguments = ((ParameterizedType) declaredFieldType).getActualTypeArguments();
Class keyClass = (Class) actualTypeArguments[0];
Type valueType = actualTypeArguments[1];
boolean isCollectionOrMap = ParameterizedType.class.isAssignableFrom(valueType.getClass());
Class valueClass = !isCollectionOrMap ? (Class) actualTypeArguments[1] : null;
boolean isBaseType = !isCollectionOrMap ? isBaseType(valueClass) : false;
Map<Object, Object> resultMap = new HashMap<>();
Iterator<String> iterator = ((JSONObject) fieldValue).keys();
while (iterator.hasNext()) {
//默认key为普通类型
String keyStr = iterator.next();
Object key = getBaseTypeField(keyClass, keyStr);
Object value = ((JSONObject) fieldValue).get(keyStr);
if(isCollectionOrMap){
value = getPaddingField(valueType, value);
}else if (!isBaseType) {
value = toJavaBean((JSONObject) value, valueClass);
}
resultMap.put(key, value);
}
result = resultMap;
}
}
return result;
}
//认为String+八大基础类型为true
public static boolean isBaseType(Class clazz){
return clazz.isPrimitive() || clazz.equals(String.class) || clazz.equals(Integer.class) ||
clazz.equals(Long.class) || clazz.equals(Character.class) || clazz.equals(Double.class) ||
clazz.equals(Float.class) || clazz.equals(Boolean.class) || clazz.equals(Byte.class) || clazz.equals(Short.class);
}
//将str转化为基础字段
public static <T> T getBaseTypeField(Class<T> clazz, String str){
Object result = null;
if(String.class.equals(clazz)){
result = (T) str;
}
else if (int.class.equals(clazz) || Integer.class.equals(clazz)) {
result = Integer.parseInt(StringUtils.isBlank(str) ? "0" : str);
} else if(long.class.equals(clazz) || Long.class.equals(clazz)){
result = Long.parseLong(StringUtils.isBlank(str) ? "0" : str);
} else if(double.class.equals(clazz) || Double.class.equals(clazz)){
result = Double.parseDouble(StringUtils.isBlank(str) ? "0" : str);
} else if(float.class.equals(clazz) || Float.class.equals(clazz)){
result = Float.parseFloat(StringUtils.isBlank(str) ? "0" : str);
} else if(short.class.equals(clazz) || Short.class.equals(clazz)){
result = Short.parseShort(StringUtils.isBlank(str) ? "0" : str);
} else if(byte.class.equals(clazz) || Byte.class.equals(clazz)){
result = Byte.parseByte(StringUtils.isBlank(str) ? "0" : str);
} else if(char.class.equals(clazz) || Character.class.equals(clazz)){
result = Character.valueOf(StringUtils.isBlank(str) ? ' ' : str.charAt(0));
} else if(boolean.class.equals(clazz) || Boolean.class.equals(clazz)){
result = Boolean.parseBoolean(StringUtils.isBlank(str) ? "false" : str);
}
return (T) result;
}
注意:
- 枚举类型获取值的方法名用的是findByValue方法获取,不同时请修改第17行。
- JavaBean对象及嵌套对象中的属性需要声明set方法才会被解析并注入。
有问题欢迎大佬指出!
本文原创,转载请标明链接。