Package com.sun.json

Source Code of com.sun.json.JSONDeserializer$Deserializer$PropertySetter

/*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met: Redistributions of source code
* must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution. Neither the name of the Sun Microsystems nor the names of
* is contributors may be used to endorse or promote products derived from this software
* without specific prior written permission.

* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/

package com.sun.json;

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.IOException;
import java.io.Reader;
import java.lang.reflect.Array;
import java.lang.reflect.Method;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONTokener;
import static com.sun.json.JSONConstants.*;

/**
* Deserializer a JSON reader (or from a String) into a Map
* or a bean (depending on boolean flag). Unlike most other
* JSON readers, this handles circular graphs using the special
* $id and $idref properties. In addition, $class property, if
* available, is used to map JSON to JavaBeans.
*
* @author A. Sundararajan
*/
public class JSONDeserializer {
    // don't create me!
    private JSONDeserializer() {}

    // simple test main
    public static void main(String[] args) throws Exception {
        Reader reader = new java.io.FileReader(args[0]);
        System.out.println(JSONDeserializer.read(reader, true));
    }

    /**
     * Read (deserialize) an object from a JSON reader.         
     */
    public static Object read(Reader in)
                     throws IOException, JSONException {
        return read(in, false);
    }

    /**
     * Read (deserialize) an object from a JSON reader.
     * Specify whether to map to JavaBeans using $class property
     * or not.
     */
    public static Object read(Reader in,
                     boolean useClass)
                     throws IOException, JSONException {
        String str = readFully(in);
        return read(str, useClass);       
    }

    /**
     * Read (deserialize) an object from a JSON string. 
     */
    public static Object read(String str)
                     throws IOException, JSONException {
        return read(str, false);
    }

    /**
     * Read (deserialize) an object from a JSON string.
     * Specify whether to map to JavaBeans using $class property
     * or not.
     */
    public static Object read(String str,
                     boolean useClass)
                     throws IOException, JSONException {
        Deserializer deserializer = new Deserializer(str, useClass);      
        return deserializer.read();
    }

    /**
     * Read (deserialize) an object from a Map into the given Class
     */
    public static Object read(Class clazz, Map map)
                     throws IOException, JSONException {
        Deserializer deserializer = new Deserializer(null, false);      
        return deserializer.read(clazz, map);
    }
   
    // reads all contents from a Reader and returns a string
    private static String readFully(Reader reader)
                      throws IOException {
        char[] arr = new char[8*1024]; // 8K at a time
        StringBuffer buf = new StringBuffer();
        int numChars;
        while ((numChars = reader.read(arr, 0, arr.length)) > 0) {
            buf.append(arr, 0, numChars);
        }
        return buf.toString();
    }

    // private class to manage the deserialization process
    private static class Deserializer {
        // JSON string we are reading
        private String str;
        // to use $class property or not?
        private boolean useClass;
        // map $id value to the corresponding Object
        private Map<String, Object> idToObj;

        // used to resolve (circular) references from
        // $idref properties.
        private interface PropertySetter {
            void set() throws Exception;
        }
        // list of "places" to resolve forward/backward
        // reference
        private List<PropertySetter> idRefSetters;

        Deserializer(String str, boolean useClass) {
            this.str = str;
            this.useClass = useClass;
        }

        // create $id-to-Object map on demand
        private Map<String, Object> idToObj() {
            if (idToObj == null) {
                idToObj = new HashMap<String, Object>();
            }
            return idToObj;
        }

        // create property setters list on demand
        private List<PropertySetter> idRefSetters() {
            if (idRefSetters == null) {
                idRefSetters = new ArrayList<PropertySetter>();
            }
            return idRefSetters;
        }


        public Object read() throws JSONException {
            return read(null);
        }         

        public Object read(Class target)
                     throws JSONException {
            JSONTokener tokener = new JSONTokener(str);
            JSONObject jobj = new JSONObject(tokener);
            Object obj = convert(jobj, target);
            fixIdReferences();
            return obj;
        }

        public Object read(Class target, Map map)
                throws JSONException {
          JSONObject jobj = new JSONObject(map);
          Object obj = convert(jobj, target);
          fixIdReferences();
          return obj;
       }

        private void fixIdReferences() throws JSONException {
            if (idRefSetters != null) {
                for (PropertySetter setter : idRefSetters) {
                    try {
                        setter.set();
                    } catch (Exception exp) {
                        throw makeJSONException(exp);
                    }
                }
            }
        }
 
        private Object convert(Object obj, Class target)
                     throws JSONException {
            if (obj == null || obj.equals(JSONObject.NULL)) {
                return null;
            }

            if (obj instanceof JSONObject) {
                JSONObject jobj = (JSONObject)obj;
                boolean hasId = jobj.has(ID);
                if (useClass) {
                    boolean hasClass = jobj.has(CLASS);
                    if (hasClass) {               
                        target = getClassFrom((JSONObject)obj);
                        jobj.remove(CLASS);
                    }
                }
                String id = null;
                if (hasId) {
                    id = jobj.get(ID).toString();
                    jobj.remove(ID);
                    if (jobj.has(ARRAYDATA)) {
                        Object value = convert(jobj.get(ARRAYDATA), target);
                        idToObj().put(id, value);
                        return value;          
                    }
                }
                Object bean = createBean(jobj, target);
                if (id != null) { idToObj().put(id, bean); }
                setProperties(bean, jobj);
                return bean;
            } else if (obj instanceof JSONArray) {
                JSONArray jarr = (JSONArray)obj;
                int len = jarr.length();
                Object bean = createBean(jarr, target);
                setProperties(bean, jarr);
                return bean;
            } else {
                if (target != null &&
                    !target.isAssignableFrom(obj.getClass())) {
                    if (target.isPrimitive() ||
                        isPrimitiveWrapper(target)) {
                        return toPrimitive(obj, target);
                    } else if (target == String.class) {
                        return obj.toString();
                    } else if (obj instanceof Number) {
                        return fromNumber((Number)obj, target);
                    } else if (obj instanceof String) {
                        return fromString((String)obj, target);
                    } else {
                        throw new JSONException("cannot convert " +
                            obj.getClass() + " to " + target);
                    }
                } else {
                    return obj;
                }
            }
        }

        private Class getClassFrom(JSONObject jobj)
                                   throws JSONException {
            String className = jobj.get(CLASS).toString();
            try {
                return Class.forName(className);
            } catch (Exception exp) {
                throw makeJSONException(exp);
            }
        }

        private Object createBean(JSONObject jobj, Class clazz)
                                  throws JSONException {
            if (clazz != null) {
                try {
                    return clazz.newInstance();
                } catch (Exception exp) {
                    throw makeJSONException(exp);
                }
            } else {
                return new HashMap();
            }
        }

        private Object createBean(JSONArray jarr, Class clazz)
                                  throws JSONException {
            if (clazz != null) {               
                try {
                    if (clazz.isArray()) {
                        return Array.newInstance(
                            clazz.getComponentType(),
                            jarr.length());
                    } else {
                        return clazz.newInstance();
                    }
                } catch (Exception exp) {
                    throw makeJSONException(exp);
                }
            } else {
                return new ArrayList(jarr.length());
            }
        }

        private void setProperties(final Object bean, JSONObject jobj)
                                   throws JSONException {           
            Iterator props = jobj.keys();
            if (bean instanceof Map) {
                final Map map = (Map)bean;
                while (props.hasNext()) {
                    final String name = props.next().toString();                   
                    Object value = jobj.get(name);
                    final String idRef;
                    if ((idRef = getIdRef(value)) != null) {
                        idRefSetters().add(new PropertySetter() {
                                public void set() throws Exception {
                                    map.put(name, idToObj().get(idRef));
                                }
                            });
                    } else {
                        map.put(name, convert(value, null));
                    }
                }
            } else {
                try {
                    BeanInfo binfo = Introspector.getBeanInfo(bean.getClass());
                    PropertyDescriptor[] propDescs = binfo.getPropertyDescriptors();
                   
                    for (PropertyDescriptor pd : propDescs) {
                      String pdName = pd.getName();
                      Object value = jobj.opt(pdName);
                      if (value == null) continue;

                        final Method m = pd.getWriteMethod();
                        if (m != null) {                                   
                          final String idRef = getIdRef(value);
                            if (idRef != null) {
                                idRefSetters().add(new PropertySetter() {
                                    public void set() throws Exception {
                                        m.invoke(bean, idToObj().get(idRef));
                                    }
                                });
                            } else {
                                Class type = pd.getPropertyType();
                                m.invoke(bean, convert(value, type));
                            }
                        }
                    }
                } catch (Exception exp) {
                    throw makeJSONException(exp);
                }
            }
        }

        private void setProperties(final Object bean, JSONArray jarr)
                                   throws JSONException {
            if (bean instanceof List) {
                final List list  = (List)bean;
                int len = jarr.length();          
                for (int index = 0; index < len; index++) {
                    Object value = jarr.get(index);
                    final String idRef = getIdRef(value);
                    final int curIndex = index;
                    if (idRef != null) {                       
                        idRefSetters().add(new PropertySetter() {
                                public void set() throws Exception {                                   
                                    list.set(curIndex, idToObj().get(idRef));
                                }
                            });
                        list.add(null);
                    } else {
                        list.add(convert(value, null));
                    }
                }
            } else {
                int len = jarr.length();
                Class compType = bean.getClass().getComponentType();
                for (int index = 0; index < len; index++) {
                    Object value =  jarr.get(index);
                    final String idRef = getIdRef(value);
                    final int curIndex = index;
                    if (idRef != null) {
                        idRefSetters().add(new PropertySetter() {
                                public void set() throws Exception {
                                    Array.set(bean, curIndex, idToObj().get(idRef));
                                }
                            });
                    } else {
                        try {
                            Array.set(bean, index,
                                convert(value, compType));
                        } catch (Exception exp) {
                            throw makeJSONException(exp);
                        }
                    }
                }
            }
        }

        private Object toPrimitive(Object obj, Class target)
                                   throws JSONException {
            if (target == Byte.class || target == Byte.TYPE) {
                if (obj instanceof Number) {
                    return new Byte(((Number)obj).byteValue());
                } else if (obj instanceof String) {
                    return Byte.valueOf((String)obj);
                }
            } else if (target == Short.class || target == Short.TYPE) {
                if (obj instanceof Number) {
                    return new Short(((Number)obj).shortValue());
                } else if (obj instanceof String) {
                    return Short.valueOf((String)obj);
                }
            } else if (target == Integer.class || target == Integer.TYPE) {
                if (obj instanceof Number) {
                    return new Integer(((Number)obj).intValue());
                } else if (obj instanceof String) {
                    return Integer.valueOf((String)obj);
                }
            } else if (target == Long.class || target == Long.TYPE) {
                if (obj instanceof Number) {
                    return new Long(((Number)obj).longValue());
                } else if (obj instanceof String) {
                    return Long.valueOf((String)obj);
                }
            } if (target == Float.class || target == Float.TYPE) {
                if (obj instanceof Number) {
                    return new Float(((Number)obj).floatValue());
                } else if (obj instanceof String) {
                    return Float.valueOf((String)obj);
                }
            } if (target == Double.class || target == Double.TYPE) {
                if (obj instanceof Number) {
                    return new Double(((Number)obj).doubleValue());
                } else if (obj instanceof String) {
                    return Double.valueOf((String)obj);
                }
            } else if (target == Character.class || target == Character.TYPE) {
                if (obj instanceof String &&
                    ((String)obj).length() == 1) {
                    return Character.valueOf(((String)obj).charAt(0));
                }
            } else if (target == Boolean.class || target == Boolean.TYPE) {
                if (obj instanceof String) {
                    return (((String)obj).length() == 0)?
                           Boolean.FALSE : Boolean.TRUE;
                } else if (obj instanceof Number) {
                    return (((Number)obj).doubleValue() == 0.0)?
                           Boolean.FALSE : Boolean.TRUE;
                } else if (obj instanceof Character) {
                    return ((Character)obj).charValue() == ' ' ?
                           Boolean.FALSE : Boolean.TRUE;
                } else {        
                    return obj == null? Boolean.FALSE : Boolean.TRUE;
                }
            }

            throw new JSONException("cannot convert " +
                        obj.getClass() + " to " + target);
        }

        private String getIdRef(Object obj) throws JSONException {
            if (obj instanceof JSONObject &&
                ((JSONObject)obj).has(IDREF)) {
                return ((JSONObject)obj).get(IDREF).toString();
            } else {
                return null;
            }
        }

        private static Map<Class, Class> primWrappers = new HashMap();
        static {
            primWrappers.put(Character.class, Character.class);
            primWrappers.put(Byte.class, Byte.class);
            primWrappers.put(Short.class, Short.class);
            primWrappers.put(Integer.class, Integer.class);
            primWrappers.put(Long.class, Long.class);
            primWrappers.put(Float.class, Float.class);
            primWrappers.put(Double.class, Double.class);
            primWrappers.put(Boolean.class, Boolean.class);
        }

        private static boolean isPrimitiveWrapper(Class clazz) {
            return primWrappers.get(clazz) != null;
        }

        private Object fromString(String str, Class target)
                                  throws JSONException {
            if (target == Class.class) {
                try {
                    return Class.forName(str);
                } catch (Exception exp) {
                    throw makeJSONException(exp);
                }
            }
            else if (target == java.util.UUID.class) {
                 return java.util.UUID.fromString(str);
            }

            // try String accepting constructor
            try {
                Constructor ctr = target.getConstructor(
                        new Class[] { String.class });
                return ctr.newInstance(str);
            } catch (Exception exp) {
                throw makeJSONException(exp);
            }
        }
       
        private Object fromNumber(Number num, Class target) throws JSONException {
            try {
              Class numClass = num.getClass();
             
              Constructor[] constructors = target.getConstructors();
              for (Constructor ctr : constructors) {
                Class[] parameterTypes = ctr.getParameterTypes();
                if (parameterTypes.length == 1) {
                  Class pClass = parameterTypes[0];
                  if (pClass == numClass) {
                      return ctr.newInstance(num);
                  }
                  else if (num instanceof Integer && pClass == int.class){
                    return ctr.newInstance(num.intValue());
                  }
                  else if (num instanceof Long && pClass == long.class){
                    return ctr.newInstance(num.longValue());
                  }
                  else if (num instanceof Float && pClass == float.class){
                    return ctr.newInstance(num.floatValue());
                  }
                  else if (num instanceof Double && pClass == double.class){
                    return ctr.newInstance(num.doubleValue());
                  }
                  else if (num instanceof Short && pClass == short.class){
                    return ctr.newInstance(num.shortValue());
                  }
                  else if (num instanceof Byte && pClass == byte.class){
                    return ctr.newInstance(num.byteValue());
                  }
                }
              }
              return num;
            } catch (Exception exp) {
                throw makeJSONException(exp);
            }
        }

        private JSONException makeJSONException(Exception exp) {
            JSONException jexp = new JSONException(exp.toString());
            jexp.initCause(exp);
            return jexp;
        }
    }
}
TOP

Related Classes of com.sun.json.JSONDeserializer$Deserializer$PropertySetter

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.