blob: 132d5eff2f40b6713bb492a47c3e226a51a26bf9 [file] [log] [blame]
/*
* 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();
}
}