/* * Copyright 1999-2011 Alibaba Group. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.alibaba.dubbo.common.json; import java.io.IOException; import java.lang.reflect.Array; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import com.alibaba.dubbo.common.bytecode.Wrapper; import com.alibaba.dubbo.common.utils.Stack; import com.alibaba.dubbo.common.utils.StringUtils; /** * JSON to Object visitor. * * @author qian.lei. */ class J2oVisitor implements JSONVisitor { public static final boolean[] EMPTY_BOOL_ARRAY = new boolean[0]; public static final byte[] EMPTY_BYTE_ARRAY = new byte[0]; public static final char[] EMPTY_CHAR_ARRAY = new char[0]; public static final short[] EMPTY_SHORT_ARRAY = new short[0]; public static final int[] EMPTY_INT_ARRAY = new int[0]; public static final long[] EMPTY_LONG_ARRAY = new long[0]; public static final float[] EMPTY_FLOAT_ARRAY = new float[0]; public static final double[] EMPTY_DOUBLE_ARRAY = new double[0]; public static final String[] EMPTY_STRING_ARRAY = new String[0]; private Class<?>[] mTypes; private Class<?> mType = Object[].class; private Object mValue; private Wrapper mWrapper; private JSONConverter mConverter; private Stack<Object> mStack = new Stack<Object>(); J2oVisitor(Class<?> type, JSONConverter jc) { mType = type; mConverter = jc; } J2oVisitor(Class<?>[] types, JSONConverter jc) { mTypes = types; mConverter = jc; } public void begin() {} public Object end(Object obj, boolean isValue) throws ParseException { mStack.clear(); try { return mConverter.readValue(mType, obj); } catch (IOException e) { throw new IllegalStateException(e.getMessage(), e); } } public void objectBegin() throws ParseException { mStack.push(mValue); mStack.push(mType); mStack.push(mWrapper); if( mType == Object.class || Map.class.isAssignableFrom(mType) ) { if (! mType.isInterface() && mType != Object.class) { try { mValue = mType.newInstance(); } catch (Exception e) { throw new IllegalStateException(e.getMessage(), e); } } else if (mType == ConcurrentMap.class) { mValue = new ConcurrentHashMap<String, Object>(); } else { mValue = new HashMap<String, Object>(); } mWrapper = null; } else { try { mValue = mType.newInstance(); mWrapper = Wrapper.getWrapper(mType); } catch(IllegalAccessException e){ throw new ParseException(StringUtils.toString(e)); } catch(InstantiationException e){ throw new ParseException(StringUtils.toString(e)); } } } public Object objectEnd(int count) { Object ret = mValue; mWrapper = (Wrapper)mStack.pop(); mType = (Class<?>)mStack.pop(); mValue = mStack.pop(); return ret; } public void objectItem(String name) { mStack.push(name); // push name. mType = ( mWrapper == null ? Object.class : mWrapper.getPropertyType(name) ); } @SuppressWarnings("unchecked") public void objectItemValue(Object obj, boolean isValue) throws ParseException { String name = (String)mStack.pop(); // pop name. if( mWrapper == null ) { ((Map<String, Object>)mValue).put(name, obj); } else { if( mType != null ) { if( isValue && obj != null ) { try { obj = mConverter.readValue(mType, obj); } catch(IOException e) { throw new ParseException(StringUtils.toString(e)); } } if (mValue instanceof Throwable && "message".equals(name)) { try { Field field = Throwable.class.getDeclaredField("detailMessage"); if (! field.isAccessible()) { field.setAccessible(true); } field.set(mValue, obj); } catch (NoSuchFieldException e) { throw new ParseException(StringUtils.toString(e)); } catch (IllegalAccessException e) { throw new ParseException(StringUtils.toString(e)); } } else if (! CLASS_PROPERTY.equals(name)) { mWrapper.setPropertyValue(mValue, name, obj); } } } } public void arrayBegin() throws ParseException { mStack.push(mType); if( mType.isArray() ) mType = mType.getComponentType(); else if( mType == Object.class || Collection.class.isAssignableFrom(mType) ) mType = Object.class; else throw new ParseException("Convert error, can not load json array data into class [" + mType.getName() + "]."); } @SuppressWarnings("unchecked") public Object arrayEnd(int count) throws ParseException { Object ret; mType = (Class<?>)mStack.get(-1-count); if( mType.isArray() ) { ret = toArray(mType.getComponentType(), mStack, count); } else { Collection<Object> items; if( mType == Object.class || Collection.class.isAssignableFrom(mType)) { if (! mType.isInterface() && mType != Object.class) { try { items = (Collection<Object>) mType.newInstance(); } catch (Exception e) { throw new IllegalStateException(e.getMessage(), e); } } else if (mType.isAssignableFrom(ArrayList.class)) { // List items = new ArrayList<Object>(count); } else if (mType.isAssignableFrom(HashSet.class)) { // Set items = new HashSet<Object>(count); } else if (mType.isAssignableFrom(LinkedList.class)) { // Queue items = new LinkedList<Object>(); } else { // Other items = new ArrayList<Object>(count); } } else { throw new ParseException("Convert error, can not load json array data into class [" + mType.getName() + "]."); } for(int i=0;i<count;i++) items.add(mStack.remove(i-count)); ret = items; } mStack.pop(); return ret; } public void arrayItem(int index) throws ParseException { if( mTypes != null && mStack.size() == index+1 ) { if( index < mTypes.length ) mType = mTypes[index]; else throw new ParseException("Can not load json array data into [" + name(mTypes) + "]."); } } public void arrayItemValue(int index, Object obj, boolean isValue) throws ParseException { if( isValue && obj != null ) { try { obj = mConverter.readValue(mType, obj); } catch(IOException e) { throw new ParseException(e.getMessage()); } } mStack.push(obj); } private static Object toArray(Class<?> c, Stack<Object> list, int len) throws ParseException { if( c == String.class ) { if( len == 0 ) { return EMPTY_STRING_ARRAY; } else { Object o; String ss[] = new String[len]; for(int i=len-1;i>=0;i--) { o = list.pop(); ss[i] = ( o == null ? null : o.toString() ); } return ss; } } if( c == boolean.class ) { if( len == 0 ) return EMPTY_BOOL_ARRAY; Object o; boolean[] ret = new boolean[len]; for(int i=len-1;i>=0;i--) { o = list.pop(); if( o instanceof Boolean ) ret[i] = ((Boolean)o).booleanValue(); } return ret; } if( c == int.class ) { if( len == 0 ) return EMPTY_INT_ARRAY; Object o; int[] ret = new int[len]; for(int i=len-1;i>=0;i--) { o = list.pop(); if( o instanceof Number ) ret[i] = ((Number)o).intValue(); } return ret; } if( c == long.class ) { if( len == 0 ) return EMPTY_LONG_ARRAY; Object o; long[] ret = new long[len]; for(int i=len-1;i>=0;i--) { o = list.pop(); if( o instanceof Number ) ret[i] = ((Number)o).longValue(); } return ret; } if( c == float.class ) { if( len == 0 ) return EMPTY_FLOAT_ARRAY; Object o; float[] ret = new float[len]; for(int i=len-1;i>=0;i--) { o = list.pop(); if( o instanceof Number ) ret[i] = ((Number)o).floatValue(); } return ret; } if( c == double.class ) { if( len == 0 ) return EMPTY_DOUBLE_ARRAY; Object o; double[] ret = new double[len]; for(int i=len-1;i>=0;i--) { o = list.pop(); if( o instanceof Number ) ret[i] = ((Number)o).doubleValue(); } return ret; } if( c == byte.class ) { if( len == 0 ) return EMPTY_BYTE_ARRAY; Object o; byte[] ret = new byte[len]; for(int i=len-1;i>=0;i--) { o = list.pop(); if( o instanceof Number ) ret[i] = ((Number)o).byteValue(); } return ret; } if( c == char.class ) { if( len == 0 ) return EMPTY_CHAR_ARRAY; Object o; char[] ret = new char[len]; for(int i=len-1;i>=0;i--) { o = list.pop(); if( o instanceof Character ) ret[i] = ((Character)o).charValue(); } return ret; } if( c == short.class ) { if( len == 0 ) return EMPTY_SHORT_ARRAY; Object o; short[] ret = new short[len]; for(int i=len-1;i>=0;i--) { o = list.pop(); if( o instanceof Number ) ret[i] = ((Number)o).shortValue(); } return ret; } Object ret = Array.newInstance(c, len); for(int i=len-1;i>=0;i--) Array.set(ret, i, list.pop()); return ret; } private static String name(Class<?>[] types) { StringBuilder sb = new StringBuilder(); for(int i=0;i<types.length;i++) { if( i > 0 ) sb.append(", "); sb.append(types[i].getName()); } return sb.toString(); } }