You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@struts.apache.org by mu...@apache.org on 2009/07/30 00:44:29 UTC
svn commit: r799110 [2/7] - in /struts/sandbox/trunk/struts2-json-plugin: ./
src/main/java/org/apache/struts2/json/
src/main/java/org/apache/struts2/json/annotations/
src/main/java/org/apache/struts2/json/rpc/
src/main/java/org/apache/struts2/json/smd/...
Modified: struts/sandbox/trunk/struts2-json-plugin/src/main/java/org/apache/struts2/json/JSONPopulator.java
URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-json-plugin/src/main/java/org/apache/struts2/json/JSONPopulator.java?rev=799110&r1=799109&r2=799110&view=diff
==============================================================================
--- struts/sandbox/trunk/struts2-json-plugin/src/main/java/org/apache/struts2/json/JSONPopulator.java (original)
+++ struts/sandbox/trunk/struts2-json-plugin/src/main/java/org/apache/struts2/json/JSONPopulator.java Wed Jul 29 22:44:26 2009
@@ -1,424 +1,444 @@
-package org.apache.struts2.json;
-
-import java.beans.BeanInfo;
-import java.beans.IntrospectionException;
-import java.beans.Introspector;
-import java.beans.PropertyDescriptor;
-import java.lang.reflect.Array;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.lang.reflect.ParameterizedType;
-import java.lang.reflect.Type;
-import java.math.BigDecimal;
-import java.math.BigInteger;
-import java.text.DateFormat;
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Set;
-
-import org.apache.struts2.json.annotations.JSON;
-
-import com.opensymphony.xwork2.util.logging.Logger;
-import com.opensymphony.xwork2.util.logging.LoggerFactory;
-
-/**
- * Isolate the process of populating JSON objects from the Interceptor class
- * itself.
- */
-public class JSONPopulator {
-
- private static final Logger LOG = LoggerFactory.getLogger(JSONPopulator.class);
-
- private String dateFormat = JSONUtil.RFC3339_FORMAT;
-
- public JSONPopulator() {
- }
-
- public JSONPopulator(String dateFormat) {
- this.dateFormat = dateFormat;
- }
-
- public String getDateFormat() {
- return dateFormat;
- }
-
- public void setDateFormat(String dateFormat) {
- this.dateFormat = dateFormat;
- }
-
- @SuppressWarnings("unchecked")
- public void populateObject(Object object, final Map elements) throws IllegalAccessException,
- InvocationTargetException, NoSuchMethodException, IntrospectionException,
- IllegalArgumentException, JSONException, InstantiationException {
- Class clazz = object.getClass();
-
- BeanInfo info = Introspector.getBeanInfo(clazz);
- PropertyDescriptor[] props = info.getPropertyDescriptors();
-
- // iterate over class fields
- for (int i = 0; i < props.length; ++i) {
- PropertyDescriptor prop = props[i];
- String name = prop.getName();
-
- if (elements.containsKey(name)) {
- Object value = elements.get(name);
- Method method = prop.getWriteMethod();
-
- if (method != null) {
- JSON json = method.getAnnotation(JSON.class);
- if ((json != null) && !json.deserialize()) {
- continue;
- }
-
- // use only public setters
- if (Modifier.isPublic(method.getModifiers())) {
- Class[] paramTypes = method.getParameterTypes();
- Type[] genericTypes = method.getGenericParameterTypes();
-
- if (paramTypes.length == 1) {
- Object convertedValue = this.convert(paramTypes[0], genericTypes[0], value,
- method);
- method.invoke(object, new Object[] { convertedValue });
- }
- }
- }
- }
- }
- }
-
- @SuppressWarnings("unchecked")
- public Object convert(Class clazz, Type type, Object value, Method method)
- throws IllegalArgumentException, JSONException, IllegalAccessException,
- InvocationTargetException, InstantiationException, NoSuchMethodException, IntrospectionException {
-
- if (value == null) {
- // if it is a java primitive then get a default value, otherwise
- // leave it as null
- return clazz.isPrimitive() ? convertPrimitive(clazz, value, method) : null;
- } else if (isJSONPrimitive(clazz))
- return convertPrimitive(clazz, value, method);
- else if (Collection.class.isAssignableFrom(clazz))
- return convertToCollection(clazz, type, value, method);
- else if (Map.class.isAssignableFrom(clazz))
- return convertToMap(clazz, type, value, method);
- else if (clazz.isArray())
- return convertToArray(clazz, type, value, method);
- else if (value instanceof Map) {
- // nested bean
- Object convertedValue = clazz.newInstance();
- this.populateObject(convertedValue, (Map) value);
- return convertedValue;
- } else if (BigDecimal.class.equals(clazz)) {
- return new BigDecimal(value != null ? value.toString() : "0");
- } else if (BigInteger.class.equals(clazz)) {
- return new BigInteger(value != null ? value.toString() : "0");
- } else
- throw new JSONException("Incompatible types for property " + method.getName());
- }
-
- private static boolean isJSONPrimitive(Class clazz) {
- return clazz.isPrimitive() || clazz.equals(String.class) || clazz.equals(Date.class)
- || clazz.equals(Boolean.class) || clazz.equals(Byte.class) || clazz.equals(Character.class)
- || clazz.equals(Double.class) || clazz.equals(Float.class) || clazz.equals(Integer.class)
- || clazz.equals(Long.class) || clazz.equals(Short.class) || clazz.equals(Locale.class)
- || clazz.isEnum();
- }
-
- @SuppressWarnings("unchecked")
- private Object convertToArray(Class clazz, Type type, Object value, Method accessor)
- throws JSONException, IllegalArgumentException, IllegalAccessException,
- InvocationTargetException, InstantiationException, NoSuchMethodException, IntrospectionException {
- if (value == null)
- return null;
- else if (value instanceof List) {
- Class arrayType = clazz.getComponentType();
- List values = (List) value;
- Object newArray = Array.newInstance(arrayType, values.size());
-
- // create an object for each element
- for (int j = 0; j < values.size(); j++) {
- Object listValue = values.get(j);
-
- if (arrayType.equals(Object.class)) {
- // Object[]
- Array.set(newArray, j, listValue);
- } else if (isJSONPrimitive(arrayType)) {
- // primitive array
- Array.set(newArray, j, this.convertPrimitive(arrayType, listValue, accessor));
- } else if (listValue instanceof Map) {
- // array of other class
- Object newObject = null;
- if (Map.class.isAssignableFrom(arrayType)) {
- newObject = convertToMap(arrayType, type, listValue, accessor);
- } else if (List.class.isAssignableFrom(arrayType)) {
- newObject = convertToCollection(arrayType, type, listValue, accessor);
- } else {
- newObject = arrayType.newInstance();
- this.populateObject(newObject, (Map) listValue);
- }
-
- Array.set(newArray, j, newObject);
- } else
- throw new JSONException("Incompatible types for property " + accessor.getName());
- }
-
- return newArray;
- } else
- throw new JSONException("Incompatible types for property " + accessor.getName());
- }
-
- @SuppressWarnings("unchecked")
- private Object convertToCollection(Class clazz, Type type, Object value, Method accessor)
- throws JSONException, IllegalArgumentException, IllegalAccessException,
- InvocationTargetException, InstantiationException, NoSuchMethodException, IntrospectionException {
- if (value == null)
- return null;
- else if (value instanceof List) {
- Class itemClass = Object.class;
- Type itemType = null;
- if ((type != null) && (type instanceof ParameterizedType)) {
- ParameterizedType ptype = (ParameterizedType) type;
- itemType = ptype.getActualTypeArguments()[0];
- if (itemType.getClass().equals(Class.class)) {
- itemClass = (Class) itemType;
- } else {
- itemClass = (Class) ((ParameterizedType) itemType).getRawType();
- }
- }
- List values = (List) value;
-
- Collection newCollection = null;
- try {
- newCollection = (Collection) clazz.newInstance();
- } catch (InstantiationException ex) {
- // fallback if clazz represents an interface or abstract class
- if (Set.class.isAssignableFrom(clazz)) {
- newCollection = new HashSet();
- } else {
- newCollection = new ArrayList();
- }
- }
-
- // create an object for each element
- for (int j = 0; j < values.size(); j++) {
- Object listValue = values.get(j);
-
- if (itemClass.equals(Object.class)) {
- // Object[]
- newCollection.add(listValue);
- } else if (isJSONPrimitive(itemClass)) {
- // primitive array
- newCollection.add(this.convertPrimitive(itemClass, listValue, accessor));
- } else if (Map.class.isAssignableFrom(itemClass)) {
- Object newObject = convertToMap(itemClass, itemType, listValue, accessor);
- newCollection.add(newObject);
- } else if (List.class.isAssignableFrom(itemClass)) {
- Object newObject = convertToCollection(itemClass, itemType, listValue, accessor);
- newCollection.add(newObject);
- } else if (listValue instanceof Map) {
- // array of beans
- Object newObject = itemClass.newInstance();
- this.populateObject(newObject, (Map) listValue);
- newCollection.add(newObject);
- } else
- throw new JSONException("Incompatible types for property " + accessor.getName());
- }
-
- return newCollection;
- } else
- throw new JSONException("Incompatible types for property " + accessor.getName());
- }
-
- @SuppressWarnings("unchecked")
- private Object convertToMap(Class clazz, Type type, Object value, Method accessor) throws JSONException,
- IllegalArgumentException, IllegalAccessException, InvocationTargetException,
- InstantiationException, NoSuchMethodException, IntrospectionException {
- if (value == null)
- return null;
- else if (value instanceof Map) {
- Class itemClass = Object.class;
- Type itemType = null;
- if ((type != null) && (type instanceof ParameterizedType)) {
- ParameterizedType ptype = (ParameterizedType) type;
- itemType = ptype.getActualTypeArguments()[1];
- if (itemType.getClass().equals(Class.class)) {
- itemClass = (Class) itemType;
- } else {
- itemClass = (Class) ((ParameterizedType) itemType).getRawType();
- }
- }
- Map values = (Map) value;
-
- Map newMap = null;
- try {
- newMap = (Map) clazz.newInstance();
- } catch (InstantiationException ex) {
- // fallback if clazz represents an interface or abstract class
- newMap = new HashMap();
- }
-
- // create an object for each element
- Iterator iter = values.entrySet().iterator();
- while (iter.hasNext()) {
- Map.Entry entry = (Map.Entry) iter.next();
- String key = (String) entry.getKey();
- Object v = entry.getValue();
-
- if (itemClass.equals(Object.class)) {
- // String, Object
- newMap.put(key, v);
- } else if (isJSONPrimitive(itemClass)) {
- // primitive map
- newMap.put(key, this.convertPrimitive(itemClass, v, accessor));
- } else if (Map.class.isAssignableFrom(itemClass)) {
- Object newObject = convertToMap(itemClass, itemType, v, accessor);
- newMap.put(key, newObject);
- } else if (List.class.isAssignableFrom(itemClass)) {
- Object newObject = convertToCollection(itemClass, itemType, v, accessor);
- newMap.put(key, newObject);
- } else if (v instanceof Map) {
- // map of beans
- Object newObject = itemClass.newInstance();
- this.populateObject(newObject, (Map) v);
- newMap.put(key, newObject);
- } else
- throw new JSONException("Incompatible types for property " + accessor.getName());
- }
-
- return newMap;
- } else
- throw new JSONException("Incompatible types for property " + accessor.getName());
- }
-
- /**
- * Converts numbers to the desired class, if possible
- *
- * @throws JSONException
- */
- @SuppressWarnings("unchecked")
- private Object convertPrimitive(Class clazz, Object value, Method method) throws JSONException {
- if (value == null) {
- if (Short.TYPE.equals(clazz) || Short.class.equals(clazz))
- return (short) 0;
- else if (Byte.TYPE.equals(clazz) || Byte.class.equals(clazz))
- return (byte) 0;
- else if (Integer.TYPE.equals(clazz) || Integer.class.equals(clazz))
- return 0;
- else if (Long.TYPE.equals(clazz) || Long.class.equals(clazz))
- return 0L;
- else if (Float.TYPE.equals(clazz) || Float.class.equals(clazz))
- return 0f;
- else if (Double.TYPE.equals(clazz) || Double.class.equals(clazz))
- return 0d;
- else if (Boolean.TYPE.equals(clazz) || Boolean.class.equals(clazz))
- return Boolean.FALSE;
- else
- return null;
- } else if (value instanceof Number) {
- Number number = (Number) value;
-
- if (Short.TYPE.equals(clazz))
- return number.shortValue();
- else if (Short.class.equals(clazz))
- return new Short(number.shortValue());
- else if (Byte.TYPE.equals(clazz))
- return number.byteValue();
- else if (Byte.class.equals(clazz))
- return new Byte(number.byteValue());
- else if (Integer.TYPE.equals(clazz))
- return number.intValue();
- else if (Integer.class.equals(clazz))
- return new Integer(number.intValue());
- else if (Long.TYPE.equals(clazz))
- return number.longValue();
- else if (Long.class.equals(clazz))
- return new Long(number.longValue());
- else if (Float.TYPE.equals(clazz))
- return number.floatValue();
- else if (Float.class.equals(clazz))
- return new Float(number.floatValue());
- else if (Double.TYPE.equals(clazz))
- return number.doubleValue();
- else if (Double.class.equals(clazz))
- return new Double(number.doubleValue());
- else if (String.class.equals(clazz))
- return value.toString();
- } else if (clazz.equals(Date.class)) {
- try {
- JSON json = method.getAnnotation(JSON.class);
-
- DateFormat formatter = new SimpleDateFormat(
- (json != null) && (json.format().length() > 0) ? json.format() : this.dateFormat);
- return formatter.parse((String) value);
- } catch (ParseException e) {
- LOG.error(e.getMessage(), e);
- throw new JSONException("Unable to parse date from: " + value);
- }
- } else if (clazz.isEnum()) {
- String sValue = (String) value;
- return Enum.valueOf(clazz, sValue);
- } else if (value instanceof String) {
- String sValue = (String) value;
- if (Boolean.TYPE.equals(clazz))
- return Boolean.parseBoolean(sValue);
- else if (Boolean.class.equals(clazz))
- return Boolean.valueOf(sValue);
- else if (Short.TYPE.equals(clazz))
- return Short.parseShort(sValue);
- else if (Short.class.equals(clazz))
- return Short.valueOf(sValue);
- else if (Byte.TYPE.equals(clazz))
- return Byte.parseByte(sValue);
- else if (Byte.class.equals(clazz))
- return Byte.valueOf(sValue);
- else if (Integer.TYPE.equals(clazz))
- return Integer.parseInt(sValue);
- else if (Integer.class.equals(clazz))
- return Integer.valueOf(sValue);
- else if (Long.TYPE.equals(clazz))
- return Long.parseLong(sValue);
- else if (Long.class.equals(clazz))
- return Long.valueOf(sValue);
- else if (Float.TYPE.equals(clazz))
- return Float.parseFloat(sValue);
- else if (Float.class.equals(clazz))
- return Float.valueOf(sValue);
- else if (Double.TYPE.equals(clazz))
- return Double.parseDouble(sValue);
- else if (Double.class.equals(clazz))
- return Double.valueOf(sValue);
- else if (Character.TYPE.equals(clazz) || Character.class.equals(clazz)) {
- char charValue = 0;
- if (sValue.length() > 0) {
- charValue = sValue.charAt(0);
- }
- if (Character.TYPE.equals(clazz))
- return charValue;
- else
- return new Character(charValue);
- } else if (clazz.equals(Locale.class)) {
- String[] components = sValue.split("_", 2);
- if (components.length == 2) {
- return new Locale(components[0], components[1]);
- } else {
- return new Locale(sValue);
- }
- } else if (Enum.class.isAssignableFrom(clazz)) {
- return Enum.valueOf(clazz, sValue);
- }
- }
-
- return value;
- }
-
-}
+/*
+ * $Id$
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.struts2.json;
+
+import java.beans.BeanInfo;
+import java.beans.IntrospectionException;
+import java.beans.Introspector;
+import java.beans.PropertyDescriptor;
+import java.lang.reflect.Array;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.struts2.json.annotations.JSON;
+
+import com.opensymphony.xwork2.util.logging.Logger;
+import com.opensymphony.xwork2.util.logging.LoggerFactory;
+
+/**
+ * Isolate the process of populating JSON objects from the Interceptor class
+ * itself.
+ */
+public class JSONPopulator {
+
+ private static final Logger LOG = LoggerFactory.getLogger(JSONPopulator.class);
+
+ private String dateFormat = JSONUtil.RFC3339_FORMAT;
+
+ public JSONPopulator() {
+ }
+
+ public JSONPopulator(String dateFormat) {
+ this.dateFormat = dateFormat;
+ }
+
+ public String getDateFormat() {
+ return dateFormat;
+ }
+
+ public void setDateFormat(String dateFormat) {
+ this.dateFormat = dateFormat;
+ }
+
+ @SuppressWarnings("unchecked")
+ public void populateObject(Object object, final Map elements) throws IllegalAccessException,
+ InvocationTargetException, NoSuchMethodException, IntrospectionException,
+ IllegalArgumentException, JSONException, InstantiationException {
+ Class clazz = object.getClass();
+
+ BeanInfo info = Introspector.getBeanInfo(clazz);
+ PropertyDescriptor[] props = info.getPropertyDescriptors();
+
+ // iterate over class fields
+ for (int i = 0; i < props.length; ++i) {
+ PropertyDescriptor prop = props[i];
+ String name = prop.getName();
+
+ if (elements.containsKey(name)) {
+ Object value = elements.get(name);
+ Method method = prop.getWriteMethod();
+
+ if (method != null) {
+ JSON json = method.getAnnotation(JSON.class);
+ if ((json != null) && !json.deserialize()) {
+ continue;
+ }
+
+ // use only public setters
+ if (Modifier.isPublic(method.getModifiers())) {
+ Class[] paramTypes = method.getParameterTypes();
+ Type[] genericTypes = method.getGenericParameterTypes();
+
+ if (paramTypes.length == 1) {
+ Object convertedValue = this.convert(paramTypes[0], genericTypes[0], value,
+ method);
+ method.invoke(object, new Object[] { convertedValue });
+ }
+ }
+ }
+ }
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public Object convert(Class clazz, Type type, Object value, Method method)
+ throws IllegalArgumentException, JSONException, IllegalAccessException,
+ InvocationTargetException, InstantiationException, NoSuchMethodException, IntrospectionException {
+
+ if (value == null) {
+ // if it is a java primitive then get a default value, otherwise
+ // leave it as null
+ return clazz.isPrimitive() ? convertPrimitive(clazz, value, method) : null;
+ } else if (isJSONPrimitive(clazz))
+ return convertPrimitive(clazz, value, method);
+ else if (Collection.class.isAssignableFrom(clazz))
+ return convertToCollection(clazz, type, value, method);
+ else if (Map.class.isAssignableFrom(clazz))
+ return convertToMap(clazz, type, value, method);
+ else if (clazz.isArray())
+ return convertToArray(clazz, type, value, method);
+ else if (value instanceof Map) {
+ // nested bean
+ Object convertedValue = clazz.newInstance();
+ this.populateObject(convertedValue, (Map) value);
+ return convertedValue;
+ } else if (BigDecimal.class.equals(clazz)) {
+ return new BigDecimal(value != null ? value.toString() : "0");
+ } else if (BigInteger.class.equals(clazz)) {
+ return new BigInteger(value != null ? value.toString() : "0");
+ } else
+ throw new JSONException("Incompatible types for property " + method.getName());
+ }
+
+ private static boolean isJSONPrimitive(Class clazz) {
+ return clazz.isPrimitive() || clazz.equals(String.class) || clazz.equals(Date.class)
+ || clazz.equals(Boolean.class) || clazz.equals(Byte.class) || clazz.equals(Character.class)
+ || clazz.equals(Double.class) || clazz.equals(Float.class) || clazz.equals(Integer.class)
+ || clazz.equals(Long.class) || clazz.equals(Short.class) || clazz.equals(Locale.class)
+ || clazz.isEnum();
+ }
+
+ @SuppressWarnings("unchecked")
+ private Object convertToArray(Class clazz, Type type, Object value, Method accessor)
+ throws JSONException, IllegalArgumentException, IllegalAccessException,
+ InvocationTargetException, InstantiationException, NoSuchMethodException, IntrospectionException {
+ if (value == null)
+ return null;
+ else if (value instanceof List) {
+ Class arrayType = clazz.getComponentType();
+ List values = (List) value;
+ Object newArray = Array.newInstance(arrayType, values.size());
+
+ // create an object for each element
+ for (int j = 0; j < values.size(); j++) {
+ Object listValue = values.get(j);
+
+ if (arrayType.equals(Object.class)) {
+ // Object[]
+ Array.set(newArray, j, listValue);
+ } else if (isJSONPrimitive(arrayType)) {
+ // primitive array
+ Array.set(newArray, j, this.convertPrimitive(arrayType, listValue, accessor));
+ } else if (listValue instanceof Map) {
+ // array of other class
+ Object newObject = null;
+ if (Map.class.isAssignableFrom(arrayType)) {
+ newObject = convertToMap(arrayType, type, listValue, accessor);
+ } else if (List.class.isAssignableFrom(arrayType)) {
+ newObject = convertToCollection(arrayType, type, listValue, accessor);
+ } else {
+ newObject = arrayType.newInstance();
+ this.populateObject(newObject, (Map) listValue);
+ }
+
+ Array.set(newArray, j, newObject);
+ } else
+ throw new JSONException("Incompatible types for property " + accessor.getName());
+ }
+
+ return newArray;
+ } else
+ throw new JSONException("Incompatible types for property " + accessor.getName());
+ }
+
+ @SuppressWarnings("unchecked")
+ private Object convertToCollection(Class clazz, Type type, Object value, Method accessor)
+ throws JSONException, IllegalArgumentException, IllegalAccessException,
+ InvocationTargetException, InstantiationException, NoSuchMethodException, IntrospectionException {
+ if (value == null)
+ return null;
+ else if (value instanceof List) {
+ Class itemClass = Object.class;
+ Type itemType = null;
+ if ((type != null) && (type instanceof ParameterizedType)) {
+ ParameterizedType ptype = (ParameterizedType) type;
+ itemType = ptype.getActualTypeArguments()[0];
+ if (itemType.getClass().equals(Class.class)) {
+ itemClass = (Class) itemType;
+ } else {
+ itemClass = (Class) ((ParameterizedType) itemType).getRawType();
+ }
+ }
+ List values = (List) value;
+
+ Collection newCollection = null;
+ try {
+ newCollection = (Collection) clazz.newInstance();
+ } catch (InstantiationException ex) {
+ // fallback if clazz represents an interface or abstract class
+ if (Set.class.isAssignableFrom(clazz)) {
+ newCollection = new HashSet();
+ } else {
+ newCollection = new ArrayList();
+ }
+ }
+
+ // create an object for each element
+ for (int j = 0; j < values.size(); j++) {
+ Object listValue = values.get(j);
+
+ if (itemClass.equals(Object.class)) {
+ // Object[]
+ newCollection.add(listValue);
+ } else if (isJSONPrimitive(itemClass)) {
+ // primitive array
+ newCollection.add(this.convertPrimitive(itemClass, listValue, accessor));
+ } else if (Map.class.isAssignableFrom(itemClass)) {
+ Object newObject = convertToMap(itemClass, itemType, listValue, accessor);
+ newCollection.add(newObject);
+ } else if (List.class.isAssignableFrom(itemClass)) {
+ Object newObject = convertToCollection(itemClass, itemType, listValue, accessor);
+ newCollection.add(newObject);
+ } else if (listValue instanceof Map) {
+ // array of beans
+ Object newObject = itemClass.newInstance();
+ this.populateObject(newObject, (Map) listValue);
+ newCollection.add(newObject);
+ } else
+ throw new JSONException("Incompatible types for property " + accessor.getName());
+ }
+
+ return newCollection;
+ } else
+ throw new JSONException("Incompatible types for property " + accessor.getName());
+ }
+
+ @SuppressWarnings("unchecked")
+ private Object convertToMap(Class clazz, Type type, Object value, Method accessor) throws JSONException,
+ IllegalArgumentException, IllegalAccessException, InvocationTargetException,
+ InstantiationException, NoSuchMethodException, IntrospectionException {
+ if (value == null)
+ return null;
+ else if (value instanceof Map) {
+ Class itemClass = Object.class;
+ Type itemType = null;
+ if ((type != null) && (type instanceof ParameterizedType)) {
+ ParameterizedType ptype = (ParameterizedType) type;
+ itemType = ptype.getActualTypeArguments()[1];
+ if (itemType.getClass().equals(Class.class)) {
+ itemClass = (Class) itemType;
+ } else {
+ itemClass = (Class) ((ParameterizedType) itemType).getRawType();
+ }
+ }
+ Map values = (Map) value;
+
+ Map newMap = null;
+ try {
+ newMap = (Map) clazz.newInstance();
+ } catch (InstantiationException ex) {
+ // fallback if clazz represents an interface or abstract class
+ newMap = new HashMap();
+ }
+
+ // create an object for each element
+ Iterator iter = values.entrySet().iterator();
+ while (iter.hasNext()) {
+ Map.Entry entry = (Map.Entry) iter.next();
+ String key = (String) entry.getKey();
+ Object v = entry.getValue();
+
+ if (itemClass.equals(Object.class)) {
+ // String, Object
+ newMap.put(key, v);
+ } else if (isJSONPrimitive(itemClass)) {
+ // primitive map
+ newMap.put(key, this.convertPrimitive(itemClass, v, accessor));
+ } else if (Map.class.isAssignableFrom(itemClass)) {
+ Object newObject = convertToMap(itemClass, itemType, v, accessor);
+ newMap.put(key, newObject);
+ } else if (List.class.isAssignableFrom(itemClass)) {
+ Object newObject = convertToCollection(itemClass, itemType, v, accessor);
+ newMap.put(key, newObject);
+ } else if (v instanceof Map) {
+ // map of beans
+ Object newObject = itemClass.newInstance();
+ this.populateObject(newObject, (Map) v);
+ newMap.put(key, newObject);
+ } else
+ throw new JSONException("Incompatible types for property " + accessor.getName());
+ }
+
+ return newMap;
+ } else
+ throw new JSONException("Incompatible types for property " + accessor.getName());
+ }
+
+ /**
+ * Converts numbers to the desired class, if possible
+ *
+ * @throws JSONException
+ */
+ @SuppressWarnings("unchecked")
+ private Object convertPrimitive(Class clazz, Object value, Method method) throws JSONException {
+ if (value == null) {
+ if (Short.TYPE.equals(clazz) || Short.class.equals(clazz))
+ return (short) 0;
+ else if (Byte.TYPE.equals(clazz) || Byte.class.equals(clazz))
+ return (byte) 0;
+ else if (Integer.TYPE.equals(clazz) || Integer.class.equals(clazz))
+ return 0;
+ else if (Long.TYPE.equals(clazz) || Long.class.equals(clazz))
+ return 0L;
+ else if (Float.TYPE.equals(clazz) || Float.class.equals(clazz))
+ return 0f;
+ else if (Double.TYPE.equals(clazz) || Double.class.equals(clazz))
+ return 0d;
+ else if (Boolean.TYPE.equals(clazz) || Boolean.class.equals(clazz))
+ return Boolean.FALSE;
+ else
+ return null;
+ } else if (value instanceof Number) {
+ Number number = (Number) value;
+
+ if (Short.TYPE.equals(clazz))
+ return number.shortValue();
+ else if (Short.class.equals(clazz))
+ return new Short(number.shortValue());
+ else if (Byte.TYPE.equals(clazz))
+ return number.byteValue();
+ else if (Byte.class.equals(clazz))
+ return new Byte(number.byteValue());
+ else if (Integer.TYPE.equals(clazz))
+ return number.intValue();
+ else if (Integer.class.equals(clazz))
+ return new Integer(number.intValue());
+ else if (Long.TYPE.equals(clazz))
+ return number.longValue();
+ else if (Long.class.equals(clazz))
+ return new Long(number.longValue());
+ else if (Float.TYPE.equals(clazz))
+ return number.floatValue();
+ else if (Float.class.equals(clazz))
+ return new Float(number.floatValue());
+ else if (Double.TYPE.equals(clazz))
+ return number.doubleValue();
+ else if (Double.class.equals(clazz))
+ return new Double(number.doubleValue());
+ else if (String.class.equals(clazz))
+ return value.toString();
+ } else if (clazz.equals(Date.class)) {
+ try {
+ JSON json = method.getAnnotation(JSON.class);
+
+ DateFormat formatter = new SimpleDateFormat(
+ (json != null) && (json.format().length() > 0) ? json.format() : this.dateFormat);
+ return formatter.parse((String) value);
+ } catch (ParseException e) {
+ LOG.error(e.getMessage(), e);
+ throw new JSONException("Unable to parse date from: " + value);
+ }
+ } else if (clazz.isEnum()) {
+ String sValue = (String) value;
+ return Enum.valueOf(clazz, sValue);
+ } else if (value instanceof String) {
+ String sValue = (String) value;
+ if (Boolean.TYPE.equals(clazz))
+ return Boolean.parseBoolean(sValue);
+ else if (Boolean.class.equals(clazz))
+ return Boolean.valueOf(sValue);
+ else if (Short.TYPE.equals(clazz))
+ return Short.parseShort(sValue);
+ else if (Short.class.equals(clazz))
+ return Short.valueOf(sValue);
+ else if (Byte.TYPE.equals(clazz))
+ return Byte.parseByte(sValue);
+ else if (Byte.class.equals(clazz))
+ return Byte.valueOf(sValue);
+ else if (Integer.TYPE.equals(clazz))
+ return Integer.parseInt(sValue);
+ else if (Integer.class.equals(clazz))
+ return Integer.valueOf(sValue);
+ else if (Long.TYPE.equals(clazz))
+ return Long.parseLong(sValue);
+ else if (Long.class.equals(clazz))
+ return Long.valueOf(sValue);
+ else if (Float.TYPE.equals(clazz))
+ return Float.parseFloat(sValue);
+ else if (Float.class.equals(clazz))
+ return Float.valueOf(sValue);
+ else if (Double.TYPE.equals(clazz))
+ return Double.parseDouble(sValue);
+ else if (Double.class.equals(clazz))
+ return Double.valueOf(sValue);
+ else if (Character.TYPE.equals(clazz) || Character.class.equals(clazz)) {
+ char charValue = 0;
+ if (sValue.length() > 0) {
+ charValue = sValue.charAt(0);
+ }
+ if (Character.TYPE.equals(clazz))
+ return charValue;
+ else
+ return new Character(charValue);
+ } else if (clazz.equals(Locale.class)) {
+ String[] components = sValue.split("_", 2);
+ if (components.length == 2) {
+ return new Locale(components[0], components[1]);
+ } else {
+ return new Locale(sValue);
+ }
+ } else if (Enum.class.isAssignableFrom(clazz)) {
+ return Enum.valueOf(clazz, sValue);
+ }
+ }
+
+ return value;
+ }
+
+}
Propchange: struts/sandbox/trunk/struts2-json-plugin/src/main/java/org/apache/struts2/json/JSONPopulator.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: struts/sandbox/trunk/struts2-json-plugin/src/main/java/org/apache/struts2/json/JSONPopulator.java
------------------------------------------------------------------------------
svn:keywords = Id
Modified: struts/sandbox/trunk/struts2-json-plugin/src/main/java/org/apache/struts2/json/JSONReader.java
URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-json-plugin/src/main/java/org/apache/struts2/json/JSONReader.java?rev=799110&r1=799109&r2=799110&view=diff
==============================================================================
--- struts/sandbox/trunk/struts2-json-plugin/src/main/java/org/apache/struts2/json/JSONReader.java (original)
+++ struts/sandbox/trunk/struts2-json-plugin/src/main/java/org/apache/struts2/json/JSONReader.java Wed Jul 29 22:44:26 2009
@@ -1,289 +1,289 @@
-/*
- * $Id$
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you 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 org.apache.struts2.json;
-
-import java.text.CharacterIterator;
-import java.text.StringCharacterIterator;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * <p>
- * Deserializes and object from a JSON string
- * </p>
- */
-class JSONReader {
- private static final Object OBJECT_END = new Object();
- private static final Object ARRAY_END = new Object();
- private static final Object COLON = new Object();
- private static final Object COMMA = new Object();
- private static Map<Character, Character> escapes = new HashMap<Character, Character>();
-
- static {
- escapes.put(new Character('"'), new Character('"'));
- escapes.put(new Character('\\'), new Character('\\'));
- escapes.put(new Character('/'), new Character('/'));
- escapes.put(new Character('b'), new Character('\b'));
- escapes.put(new Character('f'), new Character('\f'));
- escapes.put(new Character('n'), new Character('\n'));
- escapes.put(new Character('r'), new Character('\r'));
- escapes.put(new Character('t'), new Character('\t'));
- }
-
- private CharacterIterator it;
- private char c;
- private Object token;
- private StringBuilder buf = new StringBuilder();
-
- private char next() {
- this.c = this.it.next();
-
- return this.c;
- }
-
- private void skipWhiteSpace() {
- while (Character.isWhitespace(this.c)) {
- this.next();
- }
- }
-
- public Object read(String string) throws JSONException {
- this.it = new StringCharacterIterator(string);
- this.c = this.it.first();
-
- return this.read();
- }
-
- private Object read() throws JSONException {
- Object ret = null;
-
- this.skipWhiteSpace();
-
- if (this.c == '"') {
- this.next();
- ret = this.string('"');
- } else if (this.c == '\'') {
- this.next();
- ret = this.string('\'');
- } else if (this.c == '[') {
- this.next();
- ret = this.array();
- } else if (this.c == ']') {
- ret = ARRAY_END;
- this.next();
- } else if (this.c == ',') {
- ret = COMMA;
- this.next();
- } else if (this.c == '{') {
- this.next();
- ret = this.object();
- } else if (this.c == '}') {
- ret = OBJECT_END;
- this.next();
- } else if (this.c == ':') {
- ret = COLON;
- this.next();
- } else if ((this.c == 't') && (this.next() == 'r') && (this.next() == 'u') && (this.next() == 'e')) {
- ret = Boolean.TRUE;
- this.next();
- } else if ((this.c == 'f') && (this.next() == 'a') && (this.next() == 'l') && (this.next() == 's')
- && (this.next() == 'e')) {
- ret = Boolean.FALSE;
- this.next();
- } else if ((this.c == 'n') && (this.next() == 'u') && (this.next() == 'l') && (this.next() == 'l')) {
- ret = null;
- this.next();
- } else if (Character.isDigit(this.c) || (this.c == '-')) {
- ret = this.number();
- } else {
- throw buildInvalidInputException();
- }
-
- this.token = ret;
-
- return ret;
- }
-
- @SuppressWarnings("unchecked")
- private Map object() throws JSONException {
- Map ret = new HashMap();
- Object next = this.read();
- if (next != OBJECT_END) {
- String key = (String) next;
- while (this.token != OBJECT_END) {
- this.read(); // should be a colon
-
- if (this.token != OBJECT_END) {
- ret.put(key, this.read());
-
- if (this.read() == COMMA) {
- Object name = this.read();
-
- if (name instanceof String) {
- key = (String) name;
- } else
- throw buildInvalidInputException();
- }
- }
- }
- }
-
- return ret;
- }
-
- private JSONException buildInvalidInputException() {
- return new JSONException("Input string is not well formed JSON (invalid char " + this.c + ")");
- }
-
- @SuppressWarnings("unchecked")
- private List array() throws JSONException {
- List ret = new ArrayList();
- Object value = this.read();
-
- while (this.token != ARRAY_END) {
- ret.add(value);
-
- Object read = this.read();
- if (read == COMMA) {
- value = this.read();
- } else if (read != ARRAY_END) {
- throw buildInvalidInputException();
- }
- }
-
- return ret;
- }
-
- private Object number() {
- this.buf.setLength(0);
-
- if (this.c == '-') {
- this.add();
- }
-
- this.addDigits();
-
- if (this.c == '.') {
- this.add();
- this.addDigits();
- }
-
- if ((this.c == 'e') || (this.c == 'E')) {
- this.add();
-
- if ((this.c == '+') || (this.c == '-')) {
- this.add();
- }
-
- this.addDigits();
- }
-
- return (this.buf.indexOf(".") >= 0) ? (Object) Double.parseDouble(this.buf.toString())
- : (Object) Long.parseLong(this.buf.toString());
- }
-
- private Object string(char quote) {
- this.buf.setLength(0);
-
- while ((this.c != quote) && (this.c != CharacterIterator.DONE)) {
- if (this.c == '\\') {
- this.next();
-
- if (this.c == 'u') {
- this.add(this.unicode());
- } else {
- Object value = escapes.get(new Character(this.c));
-
- if (value != null) {
- this.add(((Character) value).charValue());
- }
- }
- } else {
- this.add();
- }
- }
-
- this.next();
-
- return this.buf.toString();
- }
-
- private void add(char cc) {
- this.buf.append(cc);
- this.next();
- }
-
- private void add() {
- this.add(this.c);
- }
-
- private void addDigits() {
- while (Character.isDigit(this.c)) {
- this.add();
- }
- }
-
- private char unicode() {
- int value = 0;
-
- for (int i = 0; i < 4; ++i) {
- switch (this.next()) {
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- value = (value << 4) + (this.c - '0');
-
- break;
-
- case 'a':
- case 'b':
- case 'c':
- case 'd':
- case 'e':
- case 'f':
- value = (value << 4) + (this.c - 'W');
-
- break;
-
- case 'A':
- case 'B':
- case 'C':
- case 'D':
- case 'E':
- case 'F':
- value = (value << 4) + (this.c - '7');
-
- break;
- }
- }
-
- return (char) value;
- }
-}
+/*
+ * $Id$
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.struts2.json;
+
+import java.text.CharacterIterator;
+import java.text.StringCharacterIterator;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * <p>
+ * Deserializes and object from a JSON string
+ * </p>
+ */
+class JSONReader {
+ private static final Object OBJECT_END = new Object();
+ private static final Object ARRAY_END = new Object();
+ private static final Object COLON = new Object();
+ private static final Object COMMA = new Object();
+ private static Map<Character, Character> escapes = new HashMap<Character, Character>();
+
+ static {
+ escapes.put(new Character('"'), new Character('"'));
+ escapes.put(new Character('\\'), new Character('\\'));
+ escapes.put(new Character('/'), new Character('/'));
+ escapes.put(new Character('b'), new Character('\b'));
+ escapes.put(new Character('f'), new Character('\f'));
+ escapes.put(new Character('n'), new Character('\n'));
+ escapes.put(new Character('r'), new Character('\r'));
+ escapes.put(new Character('t'), new Character('\t'));
+ }
+
+ private CharacterIterator it;
+ private char c;
+ private Object token;
+ private StringBuilder buf = new StringBuilder();
+
+ private char next() {
+ this.c = this.it.next();
+
+ return this.c;
+ }
+
+ private void skipWhiteSpace() {
+ while (Character.isWhitespace(this.c)) {
+ this.next();
+ }
+ }
+
+ public Object read(String string) throws JSONException {
+ this.it = new StringCharacterIterator(string);
+ this.c = this.it.first();
+
+ return this.read();
+ }
+
+ private Object read() throws JSONException {
+ Object ret = null;
+
+ this.skipWhiteSpace();
+
+ if (this.c == '"') {
+ this.next();
+ ret = this.string('"');
+ } else if (this.c == '\'') {
+ this.next();
+ ret = this.string('\'');
+ } else if (this.c == '[') {
+ this.next();
+ ret = this.array();
+ } else if (this.c == ']') {
+ ret = ARRAY_END;
+ this.next();
+ } else if (this.c == ',') {
+ ret = COMMA;
+ this.next();
+ } else if (this.c == '{') {
+ this.next();
+ ret = this.object();
+ } else if (this.c == '}') {
+ ret = OBJECT_END;
+ this.next();
+ } else if (this.c == ':') {
+ ret = COLON;
+ this.next();
+ } else if ((this.c == 't') && (this.next() == 'r') && (this.next() == 'u') && (this.next() == 'e')) {
+ ret = Boolean.TRUE;
+ this.next();
+ } else if ((this.c == 'f') && (this.next() == 'a') && (this.next() == 'l') && (this.next() == 's')
+ && (this.next() == 'e')) {
+ ret = Boolean.FALSE;
+ this.next();
+ } else if ((this.c == 'n') && (this.next() == 'u') && (this.next() == 'l') && (this.next() == 'l')) {
+ ret = null;
+ this.next();
+ } else if (Character.isDigit(this.c) || (this.c == '-')) {
+ ret = this.number();
+ } else {
+ throw buildInvalidInputException();
+ }
+
+ this.token = ret;
+
+ return ret;
+ }
+
+ @SuppressWarnings("unchecked")
+ private Map object() throws JSONException {
+ Map ret = new HashMap();
+ Object next = this.read();
+ if (next != OBJECT_END) {
+ String key = (String) next;
+ while (this.token != OBJECT_END) {
+ this.read(); // should be a colon
+
+ if (this.token != OBJECT_END) {
+ ret.put(key, this.read());
+
+ if (this.read() == COMMA) {
+ Object name = this.read();
+
+ if (name instanceof String) {
+ key = (String) name;
+ } else
+ throw buildInvalidInputException();
+ }
+ }
+ }
+ }
+
+ return ret;
+ }
+
+ private JSONException buildInvalidInputException() {
+ return new JSONException("Input string is not well formed JSON (invalid char " + this.c + ")");
+ }
+
+ @SuppressWarnings("unchecked")
+ private List array() throws JSONException {
+ List ret = new ArrayList();
+ Object value = this.read();
+
+ while (this.token != ARRAY_END) {
+ ret.add(value);
+
+ Object read = this.read();
+ if (read == COMMA) {
+ value = this.read();
+ } else if (read != ARRAY_END) {
+ throw buildInvalidInputException();
+ }
+ }
+
+ return ret;
+ }
+
+ private Object number() {
+ this.buf.setLength(0);
+
+ if (this.c == '-') {
+ this.add();
+ }
+
+ this.addDigits();
+
+ if (this.c == '.') {
+ this.add();
+ this.addDigits();
+ }
+
+ if ((this.c == 'e') || (this.c == 'E')) {
+ this.add();
+
+ if ((this.c == '+') || (this.c == '-')) {
+ this.add();
+ }
+
+ this.addDigits();
+ }
+
+ return (this.buf.indexOf(".") >= 0) ? (Object) Double.parseDouble(this.buf.toString())
+ : (Object) Long.parseLong(this.buf.toString());
+ }
+
+ private Object string(char quote) {
+ this.buf.setLength(0);
+
+ while ((this.c != quote) && (this.c != CharacterIterator.DONE)) {
+ if (this.c == '\\') {
+ this.next();
+
+ if (this.c == 'u') {
+ this.add(this.unicode());
+ } else {
+ Object value = escapes.get(new Character(this.c));
+
+ if (value != null) {
+ this.add(((Character) value).charValue());
+ }
+ }
+ } else {
+ this.add();
+ }
+ }
+
+ this.next();
+
+ return this.buf.toString();
+ }
+
+ private void add(char cc) {
+ this.buf.append(cc);
+ this.next();
+ }
+
+ private void add() {
+ this.add(this.c);
+ }
+
+ private void addDigits() {
+ while (Character.isDigit(this.c)) {
+ this.add();
+ }
+ }
+
+ private char unicode() {
+ int value = 0;
+
+ for (int i = 0; i < 4; ++i) {
+ switch (this.next()) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ value = (value << 4) + (this.c - '0');
+
+ break;
+
+ case 'a':
+ case 'b':
+ case 'c':
+ case 'd':
+ case 'e':
+ case 'f':
+ value = (value << 4) + (this.c - 'W');
+
+ break;
+
+ case 'A':
+ case 'B':
+ case 'C':
+ case 'D':
+ case 'E':
+ case 'F':
+ value = (value << 4) + (this.c - '7');
+
+ break;
+ }
+ }
+
+ return (char) value;
+ }
+}
Propchange: struts/sandbox/trunk/struts2-json-plugin/src/main/java/org/apache/struts2/json/JSONReader.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: struts/sandbox/trunk/struts2-json-plugin/src/main/java/org/apache/struts2/json/JSONReader.java
------------------------------------------------------------------------------
svn:keywords = Id