Author: etnu
Date: Tue Mar 17 22:08:11 2009
New Revision: 755421
URL: http://svn.apache.org/viewvc?rev=755421&view=rev
Log:
Patch for SHINDIG-912, enhancing parsing / conversion ability of
BeanJsonConverter. After these changes, double / triple parsing of input json
in JsonRpcServlet should no longer be necessary, and more classes can take
advantage of BeanJsonConverter as a generic parsing facility.
Modified:
incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/protocol/conversion/BeanJsonConverter.java
incubator/shindig/trunk/java/common/src/test/java/org/apache/shindig/common/JsonAssert.java
incubator/shindig/trunk/java/common/src/test/java/org/apache/shindig/protocol/JsonRpcServletTest.java
incubator/shindig/trunk/java/common/src/test/java/org/apache/shindig/protocol/conversion/BeanJsonConverterTest.java
incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/opensocial/service/AppDataHandler.java
incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/opensocial/service/AppDataHandlerTest.java
Modified:
incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/protocol/conversion/BeanJsonConverter.java
URL:
http://svn.apache.org/viewvc/incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/protocol/conversion/BeanJsonConverter.java?rev=755421&r1=755420&r2=755421&view=diff
==============================================================================
---
incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/protocol/conversion/BeanJsonConverter.java
(original)
+++
incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/protocol/conversion/BeanJsonConverter.java
Tue Mar 17 22:08:11 2009
@@ -23,8 +23,6 @@
import org.apache.shindig.protocol.model.Enum;
import org.apache.shindig.protocol.model.EnumImpl;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
import com.google.common.collect.MapMaker;
import com.google.inject.Inject;
import com.google.inject.Injector;
@@ -37,17 +35,22 @@
import java.io.IOException;
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.util.ArrayList;
import java.util.Collection;
import java.util.Date;
-import java.util.Iterator;
+import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Set;
/**
- * Converts pojos to json objects.
- * TODO: Replace with standard library
+ * Converts between JSON and java objects.
+ *
+ * TODO: Eliminate BeanConverter interface.
*/
public class BeanJsonConverter implements BeanConverter {
@@ -61,50 +64,35 @@
this.injector = injector;
}
- public String getContentType() {
- return "application/json";
- }
-
- /**
- * Convert the passed in object to a string.
- *
- * @param pojo The object to convert
- * @return An object whos toString method will return json
- */
- public String convertToString(final Object pojo) {
- return JsonSerializer.serialize(pojo);
- }
-
public void append(Appendable buf, Object pojo) throws IOException {
JsonSerializer.append(buf, pojo);
}
- private static Map<String, Method> getSetters(Object pojo) {
- Class<?> clazz = pojo.getClass();
+ private static Map<String, Method> getSetters(Class<?> type) {
+ Map<String, Method> methods = setters.get(type);
- Map<String, Method> methods = setters.get(clazz);
if (methods != null) {
return methods;
}
- // Ensure consistent method ordering by using a linked hash map.
- methods = Maps.newHashMap();
- for (Method method : clazz.getMethods()) {
+ methods = new HashMap<String, Method>();
+
+ for (Method method : type.getMethods()) {
String name = getPropertyName(method);
if (name != null) {
methods.put(name, method);
}
}
- setters.put(clazz, methods);
+ setters.put(type, methods);
return methods;
}
- private static String getPropertyName(Method method) {
- JsonProperty property = method.getAnnotation(JsonProperty.class);
+ private static String getPropertyName(Method setter) {
+ JsonProperty property = setter.getAnnotation(JsonProperty.class);
if (property == null) {
- String name = method.getName();
- if (name.startsWith("set")) {
+ String name = setter.getName();
+ if (name.startsWith("set") && !Modifier.isStatic(setter.getModifiers()))
{
return name.substring(3, 4).toLowerCase() + name.substring(4);
}
return null;
@@ -113,183 +101,158 @@
}
}
- public <T> T convertToObject(String json, Class<T> className) {
- String errorMessage = "Could not convert " + json + " to " + className;
+ public <T> T convertToObject(String string, Class<T> className) {
+ return convertToObject(string, (Type) className);
+ }
+
+ public String convertToString(Object pojo) {
+ return JsonSerializer.serialize(pojo);
+ }
+
+ public String getContentType() {
+ return "application/json";
+ }
+ @SuppressWarnings("unchecked")
+ public <T> T convertToObject(String json, Type type) {
try {
- T pojo = injector.getInstance(className);
- return convertToObject(json, pojo);
+ return (T) convertToObject(new JSONObject(json), type);
} catch (JSONException e) {
- throw new RuntimeException(errorMessage, e);
- } catch (InvocationTargetException e) {
- throw new RuntimeException(errorMessage, e);
- } catch (IllegalAccessException e) {
- throw new RuntimeException(errorMessage, e);
- } catch (NoSuchFieldException e) {
- throw new RuntimeException(errorMessage, e);
+ throw new RuntimeException(e);
}
}
- @SuppressWarnings("unchecked")
- private <T> T convertToObject(String json, T pojo)
- throws JSONException, InvocationTargetException, IllegalAccessException,
- NoSuchFieldException {
-
- if (pojo instanceof String) {
- pojo = (T) json; // This is a weird cast...
-
- } else if (pojo instanceof Map) {
- // TODO: Figure out how to get the actual generic type for the
- // second Map parameter. Right now we are hardcoding to String
- Class<?> mapValueClass = String.class;
-
- JSONObject jsonObject = new JSONObject(json);
- Iterator<?> iterator = jsonObject.keys();
- while (iterator.hasNext()) {
- String key = (String) iterator.next();
- Object value = convertToObject(jsonObject.getString(key),
mapValueClass);
- ((Map<String, Object>) pojo).put(key, value);
+ private Object convertToObject(Object value, Type type) {
+ if (type == null || type.equals(Object.class)) {
+ // Use the source type instead.
+ if (value instanceof JSONObject) {
+ return convertToMap((JSONObject) value, null);
+ } else if (value instanceof JSONArray) {
+ return convertToCollection((JSONArray) value, new ArrayList<Object>(),
null);
+ }
+ return value;
+ } else if (type instanceof ParameterizedType) {
+ return convertGeneric(value, (ParameterizedType) type);
+ } else if (type.equals(String.class)) {
+ return String.valueOf(value);
+ } else if (type.equals(Boolean.class) || type.equals(Boolean.TYPE)) {
+ return Boolean.TRUE.equals(value);
+ } else if (type.equals(Integer.class) || type.equals(Integer.TYPE)) {
+ return value instanceof String ? Integer.valueOf((String) value) :
((Number) value).intValue();
+ } else if (type.equals(Long.class) || type.equals(Long.TYPE)) {
+ return value instanceof String ? Long.valueOf((String) value) :
((Number) value).longValue();
+ } else if (type.equals(Double.class) || type.equals(Double.TYPE)) {
+ return value instanceof String ? Double.valueOf((String) value) :
((Number) value).doubleValue();
+ } else if (type.equals(Float.class) || type.equals(Float.TYPE)) {
+ return value instanceof String ? Float.valueOf((String) value) :
((Number) value).floatValue();
+ } else if (type.equals(Date.class)) {
+ return new DateTime(String.valueOf(value)).toDate();
+ } else if (type.equals(Uri.class)) {
+ return Uri.parse(String.valueOf(value));
+ } else if (type.equals(Map.class)) {
+ return convertToMap((JSONObject) value, null);
+ } else if (type.equals(List.class) || type.equals(Collection.class)) {
+ return convertToCollection((JSONArray) value, new ArrayList<Object>(),
null);
+ } else if (type.equals(Set.class)) {
+ return convertToCollection((JSONArray) value, new HashSet<Object>(),
null);
+ }
+
+ Class<?> clazz = (Class<?>) type;
+
+ if (clazz.isEnum()) {
+ return convertToEnum((String) value, clazz);
+ }
+
+ return convertToClass((JSONObject) value, clazz);
+ }
+
+ private Object convertGeneric(Object value, ParameterizedType type) {
+ Type[] typeArgs = type.getActualTypeArguments();
+ Class<?> clazz = (Class<?>) type.getRawType();
+
+ if (Set.class.isAssignableFrom(clazz)) {
+ return convertToCollection((JSONArray) value, new HashSet<Object>(),
typeArgs[0]);
+ } else if (Collection.class.isAssignableFrom(clazz)) {
+ return convertToCollection((JSONArray) value, new ArrayList<Object>(),
typeArgs[0]);
+ } else if (Map.class.isAssignableFrom(clazz)) {
+ return convertToMap((JSONObject) value, typeArgs[1]);
+ } else if
(org.apache.shindig.protocol.model.Enum.class.isAssignableFrom(clazz)) {
+ // Special case for opensocial Enum objects. These really need to be
refactored to not require
+ // this handling.
+ return convertToOsEnum((JSONObject) value, (Class<?>) typeArgs[0]);
+ }
+ return convertToClass((JSONObject) value, clazz);
+ }
+
+ private Enum<Enum.EnumKey> convertToOsEnum(JSONObject json, Class<?>
enumKeyType) {
+ Enum<Enum.EnumKey> value;
+ String val = Enum.Field.VALUE.toString();
+ String display = Enum.Field.DISPLAY_VALUE.toString();
+ if (json.has(val)) {
+ Enum.EnumKey enumKey;
+ try {
+ enumKey = (Enum.EnumKey)
enumKeyType.getField(json.optString(val)).get(null);
+ } catch (IllegalArgumentException e) {
+ throw new RuntimeException(e);
+ } catch (SecurityException e) {
+ throw new RuntimeException(e);
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(e);
+ } catch (NoSuchFieldException e) {
+ throw new RuntimeException(e);
}
-
- } else if (pojo instanceof Collection) {
- JSONArray array = new JSONArray(json);
- for (int i = 0; i < array.length(); i++) {
- ((Collection<Object>) pojo).add(array.get(i));
+ String displayValue = null;
+ if (json.has(display)) {
+ displayValue = json.optString(display);
}
+ value = new EnumImpl<Enum.EnumKey>(enumKey,displayValue);
} else {
- JSONObject jsonObject = new JSONObject(json);
- for (Map.Entry<String, Method> setter : getSetters(pojo).entrySet()) {
- if (jsonObject.has(setter.getKey())) {
- callSetterWithValue(pojo, setter.getValue(), jsonObject,
setter.getKey());
- }
- }
+ value = new EnumImpl<Enum.EnumKey>(null, json.optString(display));
}
- return pojo;
+ return value;
}
- @SuppressWarnings("boxing")
- private <T> void callSetterWithValue(T pojo, Method method,
- JSONObject jsonObject, String fieldName)
- throws IllegalAccessException, InvocationTargetException,
NoSuchFieldException,
- JSONException {
-
- Class<?> expectedType = method.getParameterTypes()[0];
- Object value = null;
-
- if (!jsonObject.has(fieldName)) {
- // Skip
- } else if (expectedType.equals(List.class)) {
- ParameterizedType genericListType
- = (ParameterizedType) method.getGenericParameterTypes()[0];
- Type type = genericListType.getActualTypeArguments()[0];
- Class<?> rawType;
- Class<?> listElementClass;
- if (type instanceof ParameterizedType) {
- listElementClass =
(Class<?>)((ParameterizedType)type).getActualTypeArguments()[0];
- rawType = (Class<?>)((ParameterizedType)type).getRawType();
- } else {
- listElementClass = (Class<?>) type;
- rawType = listElementClass;
- }
-
- List<Object> list = Lists.newArrayList();
- JSONArray jsonArray = jsonObject.getJSONArray(fieldName);
- for (int i = 0; i < jsonArray.length(); i++) {
- if (org.apache.shindig.protocol.model.Enum.class
- .isAssignableFrom(rawType)) {
- list.add(convertEnum(listElementClass, jsonArray.getJSONObject(i)));
- } else {
- list.add(convertToObject(jsonArray.getString(i), listElementClass));
- }
+ private Object convertToEnum(String value, Class<?> type) {
+ for (Object o : type.getEnumConstants()) {
+ if (o.toString().equals(value)) {
+ return o;
}
+ }
+ throw new IllegalArgumentException("No enum value " + value + " in " +
type.getName());
+ }
- value = list;
-
- } else if (expectedType.equals(Map.class)) {
- ParameterizedType genericListType
- = (ParameterizedType) method.getGenericParameterTypes()[0];
- Type[] types = genericListType.getActualTypeArguments();
- Class<?> valueClass = (Class<?>) types[1];
-
- // We only support keys being typed as Strings.
- // Nothing else really makes sense in json.
- Map<String, Object> map = Maps.newHashMap();
- JSONObject jsonMap = jsonObject.getJSONObject(fieldName);
-
- Iterator<?> keys = jsonMap.keys();
- while (keys.hasNext()) {
- String keyName = (String) keys.next();
- map.put(keyName, convertToObject(jsonMap.getString(keyName),
- valueClass));
- }
-
- value = map;
-
- } else if (org.apache.shindig.protocol.model.Enum.class
- .isAssignableFrom(expectedType)) {
- // TODO Need to stop using Enum as a class name :(
- value = convertEnum(
- (Class<?>)((ParameterizedType) method.getGenericParameterTypes()[0]).
- getActualTypeArguments()[0],
- jsonObject.getJSONObject(fieldName));
- } else if (expectedType.isEnum()) {
- if (jsonObject.has(fieldName)) {
- for (Object v : expectedType.getEnumConstants()) {
- if (v.toString().equals(jsonObject.getString(fieldName))) {
- value = v;
- break;
- }
- }
- if (value == null) {
- throw new IllegalArgumentException(
- "No enum value '" + jsonObject.getString(fieldName)
- + "' in " + expectedType.getName());
- }
- }
- } else if (expectedType.equals(Uri.class)) {
- value = Uri.parse(jsonObject.getString(fieldName));
- } else if (expectedType.equals(String.class)) {
- value = jsonObject.getString(fieldName);
- } else if (expectedType.equals(Date.class)) {
- // Use JODA ISO parsing for the conversion
- value = new DateTime(jsonObject.getString(fieldName)).toDate();
- } else if (expectedType.equals(Long.class) ||
expectedType.equals(Long.TYPE)) {
- value = jsonObject.getLong(fieldName);
- } else if (expectedType.equals(Integer.class) ||
expectedType.equals(Integer.TYPE)) {
- value = jsonObject.getInt(fieldName);
- } else if (expectedType.equals(Boolean.class) ||
expectedType.equals(Boolean.TYPE)) {
- value = jsonObject.getBoolean(fieldName);
- } else if (expectedType.equals(Float.class) ||
expectedType.equals(Float.TYPE)) {
- value = ((Double) jsonObject.getDouble(fieldName)).floatValue();
- } else if (expectedType.equals(Double.class) ||
expectedType.equals(Double.TYPE)) {
- value = jsonObject.getDouble(fieldName);
- } else {
- // Assume its an injected type
- value = convertToObject(jsonObject.getJSONObject(fieldName).toString(),
expectedType);
+ private Map<String, Object> convertToMap(JSONObject in, Type type) {
+ Map<String, Object> out = new HashMap<String, Object>(in.length(), 1);
+ for (String name : JSONObject.getNames(in)) {
+ out.put(name, convertToObject(in.opt(name), type));
}
+ return out;
+ }
- if (value != null) {
- method.invoke(pojo, value);
+ private Collection<Object> convertToCollection(JSONArray in,
Collection<Object> out, Type type) {
+ for (int i = 0, j = in.length(); i < j; ++i) {
+ out.add(convertToObject(in.opt(i), type));
}
+ return out;
}
- private Object convertEnum(Class<?> enumKeyType, JSONObject jsonEnum)
- throws JSONException, IllegalAccessException, NoSuchFieldException {
- // TODO This isnt injector friendly but perhaps implementors dont need it.
If they do a
- // refactoring of the Enum handling in general is needed.
- Object value;
- if (jsonEnum.has(Enum.Field.VALUE.toString())) {
- Enum.EnumKey enumKey = (Enum.EnumKey) enumKeyType
- .getField(jsonEnum.getString(Enum.Field.VALUE.toString())).get(null);
- String displayValue = null;
- if (jsonEnum.has(Enum.Field.DISPLAY_VALUE.toString())) {
- displayValue = jsonEnum.getString(Enum.Field.DISPLAY_VALUE.toString());
+ private Object convertToClass(JSONObject in, Class<?> type) {
+ Object out = injector.getInstance(type);
+ for (Map.Entry<String, Method> entry : getSetters(type).entrySet()) {
+ Object value = in.opt(entry.getKey());
+ if (value != null) {
+ Method method = entry.getValue();
+ try {
+ method.invoke(out, convertToObject(value,
method.getGenericParameterTypes()[0]));
+ } catch (IllegalArgumentException e) {
+ throw new RuntimeException(e);
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(e);
+ } catch (InvocationTargetException e) {
+ throw new RuntimeException(e);
+ }
}
- value = new EnumImpl<Enum.EnumKey>(enumKey,displayValue);
- } else {
- value = new EnumImpl<Enum.EnumKey>(null,
- jsonEnum.getString(Enum.Field.DISPLAY_VALUE.toString()));
}
- return value;
+ return out;
}
}
Modified:
incubator/shindig/trunk/java/common/src/test/java/org/apache/shindig/common/JsonAssert.java
URL:
http://svn.apache.org/viewvc/incubator/shindig/trunk/java/common/src/test/java/org/apache/shindig/common/JsonAssert.java?rev=755421&r1=755420&r2=755421&view=diff
==============================================================================
---
incubator/shindig/trunk/java/common/src/test/java/org/apache/shindig/common/JsonAssert.java
(original)
+++
incubator/shindig/trunk/java/common/src/test/java/org/apache/shindig/common/JsonAssert.java
Tue Mar 17 22:08:11 2009
@@ -18,11 +18,12 @@
*/
package org.apache.shindig.common;
-import org.json.JSONArray;
-import org.json.JSONObject;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
+import org.json.JSONArray;
+import org.json.JSONObject;
+
public final class JsonAssert {
private JsonAssert() {}
@@ -53,7 +54,7 @@
assertEquals("Objects are not of equal size", left.toString(2),
right.toString(2));
}
- // Both are emtpy so skip
+ // Both are empty so skip
if (JSONObject.getNames(left) == null && JSONObject.getNames(right) ==
null) {
return;
}
Modified:
incubator/shindig/trunk/java/common/src/test/java/org/apache/shindig/protocol/JsonRpcServletTest.java
URL:
http://svn.apache.org/viewvc/incubator/shindig/trunk/java/common/src/test/java/org/apache/shindig/protocol/JsonRpcServletTest.java?rev=755421&r1=755420&r2=755421&view=diff
==============================================================================
---
incubator/shindig/trunk/java/common/src/test/java/org/apache/shindig/protocol/JsonRpcServletTest.java
(original)
+++
incubator/shindig/trunk/java/common/src/test/java/org/apache/shindig/protocol/JsonRpcServletTest.java
Tue Mar 17 22:08:11 2009
@@ -17,9 +17,13 @@
*/
package org.apache.shindig.protocol;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.expectLastCall;
+import static org.easymock.EasyMock.isA;
+import static org.easymock.classextension.EasyMock.reset;
+
import org.apache.shindig.common.JsonAssert;
import org.apache.shindig.common.testing.FakeGadgetToken;
-import org.apache.shindig.protocol.conversion.BeanConverter;
import org.apache.shindig.protocol.conversion.BeanJsonConverter;
import org.apache.shindig.protocol.multipart.FormDataItem;
import org.apache.shindig.protocol.multipart.MultipartFormParser;
@@ -27,14 +31,10 @@
import com.google.common.collect.ImmutableMap;
import com.google.inject.Guice;
-import junit.framework.TestCase;
-
-import static org.easymock.EasyMock.expect;
-import static org.easymock.EasyMock.expectLastCall;
-import static org.easymock.EasyMock.isA;
import org.easymock.IMocksControl;
import org.easymock.classextension.EasyMock;
-import static org.easymock.classextension.EasyMock.reset;
+
+import junit.framework.TestCase;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
@@ -60,15 +60,11 @@
private static final String IMAGE_FIELDNAME = "profile-photo";
private static final byte[] IMAGE_DATA = "image data".getBytes();
private static final String IMAGE_TYPE = "image/jpeg";
-
+
private HttpServletRequest req;
private HttpServletResponse res;
private JsonRpcServlet servlet;
private MultipartFormParser multipartFormParser;
-
- private BeanJsonConverter jsonConverter;
- private BeanConverter xmlConverter;
- protected BeanConverter atomConverter;
private final IMocksControl mockControl = EasyMock.createNiceControl();
@@ -80,20 +76,19 @@
servlet = new JsonRpcServlet();
req = mockControl.createMock(HttpServletRequest.class);
res = mockControl.createMock(HttpServletResponse.class);
- jsonConverter = new BeanJsonConverter(Guice.createInjector());
- xmlConverter = mockControl.createMock(BeanConverter.class);
- atomConverter = mockControl.createMock(BeanConverter.class);
multipartFormParser = mockControl.createMock(MultipartFormParser.class);
EasyMock.expect(multipartFormParser.isMultipartContent(req)).andStubReturn(false);
servlet.setMultipartFormParser(multipartFormParser);
-
- HandlerRegistry registry = new DefaultHandlerRegistry(null, jsonConverter,
+
+ BeanJsonConverter converter = new
BeanJsonConverter(Guice.createInjector());
+
+ HandlerRegistry registry = new DefaultHandlerRegistry(null, null,
new HandlerExecutionListener.NoOpHandlerExecutionListener());
registry.addHandlers(Collections.<Object>singleton(handler));
servlet.setHandlerRegistry(registry);
- servlet.setBeanConverters(jsonConverter, xmlConverter, atomConverter);
+ servlet.setBeanConverters(converter, null, null);
handler.setMock(new TestHandler() {
@Override
public Object get(RequestItem req) {
@@ -122,7 +117,7 @@
public void testPostMultipartFormData() throws Exception {
reset(multipartFormParser);
-
+
handler.setMock(new TestHandler() {
@Override
public Object get(RequestItem req) {
@@ -137,11 +132,11 @@
expect(req.getCharacterEncoding()).andStubReturn("UTF-8");
res.setCharacterEncoding("UTF-8");
res.setContentType("application/json");
-
+
List<FormDataItem> formItems = new ArrayList<FormDataItem>();
String request = "{method:test.get,id:id,params:" +
"{userId:5,groupId:@self,image-ref:@" + IMAGE_FIELDNAME + "}}";
- formItems.add(mockFormDataItem(JsonRpcServlet.REQUEST_PARAM,
"application/json",
+ formItems.add(mockFormDataItem(JsonRpcServlet.REQUEST_PARAM,
"application/json",
request.getBytes(), true));
formItems.add(mockFormDataItem(IMAGE_FIELDNAME, IMAGE_TYPE, IMAGE_DATA,
false));
expect(multipartFormParser.isMultipartContent(req)).andReturn(true);
@@ -153,15 +148,15 @@
servlet.service(req, res);
mockControl.verify();
- JsonAssert.assertJsonEquals("{id: 'id', data: {image-data:'" + new
String(IMAGE_DATA) +
+ JsonAssert.assertJsonEquals("{id: 'id', data: {image-data:'" + new
String(IMAGE_DATA) +
"', image-type:'" + IMAGE_TYPE + "', image-ref:'@" + IMAGE_FIELDNAME +
"'}}", getOutput());
}
-
- /**
+
+ /**
* Tests whether mime part with content type appliction/json is picked up as
* request even when its fieldname is not "request".
*/
- public void testPostMultipartFormDataWithNoExplicitRequestField() throws
Exception {
+ public void testPostMultipartFormDataWithNoExplicitRequestField() throws
Exception {
reset(multipartFormParser);
handler.setMock(new TestHandler() {
@@ -178,12 +173,12 @@
expect(req.getCharacterEncoding()).andStubReturn("UTF-8");
res.setCharacterEncoding("UTF-8");
res.setContentType("application/json");
-
+
List<FormDataItem> formItems = new ArrayList<FormDataItem>();
String request = "{method:test.get,id:id,params:" +
"{userId:5,groupId:@self,image-ref:@" + IMAGE_FIELDNAME + "}}";
formItems.add(mockFormDataItem(IMAGE_FIELDNAME, IMAGE_TYPE, IMAGE_DATA,
false));
- formItems.add(mockFormDataItem("json", "application/json",
+ formItems.add(mockFormDataItem("json", "application/json",
request.getBytes(), true));
expect(multipartFormParser.isMultipartContent(req)).andReturn(true);
expect(multipartFormParser.parse(req)).andReturn(formItems);
@@ -194,11 +189,11 @@
servlet.service(req, res);
mockControl.verify();
- JsonAssert.assertJsonEquals("{id: 'id', data: {image-data:'" + new
String(IMAGE_DATA) +
+ JsonAssert.assertJsonEquals("{id: 'id', data: {image-data:'" + new
String(IMAGE_DATA) +
"', image-type:'" + IMAGE_TYPE + "', image-ref:'@" + IMAGE_FIELDNAME +
"'}}", getOutput());
}
-
+
public void testInvalidService() throws Exception {
setupRequest("{method:junk.get,id:id,params:{userId:5,groupId:@self}}");
@@ -228,7 +223,7 @@
mockControl.replay();
servlet.service(req, res);
mockControl.verify();
-
+
JsonAssert.assertJsonEquals(
"{id:id,error:{message:'badRequest: FAILURE_MESSAGE',code:400}}",
getOutput());
}
Modified:
incubator/shindig/trunk/java/common/src/test/java/org/apache/shindig/protocol/conversion/BeanJsonConverterTest.java
URL:
http://svn.apache.org/viewvc/incubator/shindig/trunk/java/common/src/test/java/org/apache/shindig/protocol/conversion/BeanJsonConverterTest.java?rev=755421&r1=755420&r2=755421&view=diff
==============================================================================
---
incubator/shindig/trunk/java/common/src/test/java/org/apache/shindig/protocol/conversion/BeanJsonConverterTest.java
(original)
+++
incubator/shindig/trunk/java/common/src/test/java/org/apache/shindig/protocol/conversion/BeanJsonConverterTest.java
Tue Mar 17 22:08:11 2009
@@ -23,10 +23,13 @@
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.inject.Guice;
+import com.google.inject.TypeLiteral;
import junit.framework.TestCase;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
@@ -39,6 +42,69 @@
beanJsonConverter = new BeanJsonConverter(Guice.createInjector());
}
+ public static class TestObject {
+ static String staticValue;
+ String hello;
+ int count;
+ List<TestObject> children;
+ TestEnum testEnum;
+
+ public static void setSomeStatic(String staticValue) {
+ TestObject.staticValue = staticValue;
+ }
+
+ public void setHello(String hello) {
+ this.hello = hello;
+ }
+
+ public void setCount(int count) {
+ this.count = count;
+ }
+
+ public void setChildren(List<TestObject> children) {
+ this.children = children;
+ }
+
+ public enum TestEnum {
+ foo, bar, baz;
+ }
+
+ public void setTestEnum(TestEnum testEnum) {
+ this.testEnum = testEnum;
+ }
+ }
+
+ public void testJsonToObject() throws Exception {
+ String json = "{" +
+ "hello:'world'," +
+ "count:10," +
+ "someStatic:'foo'," +
+ "testEnum:'bar'," +
+ "children:[{hello:'world-2',count:11},{hello:'world-3',count:12}]}";
+
+ TestObject object = beanJsonConverter.convertToObject(json,
TestObject.class);
+
+ assertEquals("world", object.hello);
+ assertEquals(10, object.count);
+ assertEquals("world-2", object.children.get(0).hello);
+ assertEquals(11, object.children.get(0).count);
+ assertEquals("world-3", object.children.get(1).hello);
+ assertEquals(12, object.children.get(1).count);
+ assertNull("Should not set static values", TestObject.staticValue);
+ assertEquals(TestObject.TestEnum.bar, object.testEnum);
+ }
+
+ public void testJsonToPrimitives() throws Exception {
+ String simpleJson = "{hello:'world',count:10}";
+
+ Object object = beanJsonConverter.convertToObject(simpleJson, null);
+
+ Map<String, Object> map = (Map<String, Object>) object;
+
+ assertEquals("world", map.get("hello"));
+ assertEquals(10, map.get("count"));
+ }
+
public void testJsonToCar() throws Exception {
String carJson =
"{engine:[{value:DIESEL},{value:TURBO}],parkingTickets:{SF:$137,NY:'$301'}," +
"passengers:[{gender:female,name:'Mum'},
{gender:male,name:'Dad'}]}";
@@ -59,12 +125,30 @@
assertEquals(dad.getName(), "Dad");
}
- @SuppressWarnings("unchecked")
public void testJsonToMap() throws Exception {
String jsonActivity = "{count : 0, favoriteColor : 'yellow'}";
+ Map<String, Object> data = Maps.newHashMap();
+ data = beanJsonConverter.convertToObject(jsonActivity,
+ new TypeLiteral<Map<String, Object>>(){}.getType());
+
+ assertEquals(2, data.size());
+
+ for (Entry<String, Object> entry : data.entrySet()) {
+ String key = entry.getKey();
+ Object value = entry.getValue();
+ if (key.equals("count")) {
+ assertEquals(0, value);
+ } else if (key.equals("favoriteColor")) {
+ assertEquals("yellow", value);
+ }
+ }
+ }
+
+ public void testJsonToMapWithConversion() throws Exception {
+ String jsonActivity = "{count : 0, favoriteColor : 'yellow'}";
Map<String, String> data = Maps.newHashMap();
data = beanJsonConverter.convertToObject(jsonActivity,
- (Class<Map<String, String>>) data.getClass());
+ new TypeLiteral<Map<String, String>>(){}.getType());
assertEquals(2, data.size());
@@ -78,4 +162,16 @@
}
}
}
+
+ public void testJsonToNestedGeneric() throws Exception {
+ String jsonActivity = "{key0:[0,1,2],key1:[3,4,5]}";
+ Map<String, List<Integer>> data = Maps.newHashMap();
+ data = beanJsonConverter.convertToObject(jsonActivity,
+ new TypeLiteral<Map<String, List<Integer>>>(){}.getType());
+
+ assertEquals(2, data.size());
+
+ assertEquals(Arrays.asList(0, 1, 2), data.get("key0"));
+ assertEquals(Arrays.asList(3, 4, 5), data.get("key1"));
+ }
}
Modified:
incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/opensocial/service/AppDataHandler.java
URL:
http://svn.apache.org/viewvc/incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/opensocial/service/AppDataHandler.java?rev=755421&r1=755420&r2=755421&view=diff
==============================================================================
---
incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/opensocial/service/AppDataHandler.java
(original)
+++
incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/opensocial/service/AppDataHandler.java
Tue Mar 17 22:08:11 2009
@@ -27,7 +27,6 @@
import com.google.inject.Inject;
-import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Future;
@@ -93,8 +92,7 @@
HandlerPreconditions.requireNotEmpty(userIds, "No userId specified");
HandlerPreconditions.requireSingular(userIds, "Multiple userIds not
supported");
- @SuppressWarnings("unchecked")
- Map<String, String> values = request.getTypedParameter("data",
HashMap.class);
+ Map<String, String> values = request.getTypedParameter("data", Map.class);
for (String key : values.keySet()) {
if (!isValidKey(key)) {
throw new SocialSpiException(ResponseError.BAD_REQUEST,
Modified:
incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/opensocial/service/AppDataHandlerTest.java
URL:
http://svn.apache.org/viewvc/incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/opensocial/service/AppDataHandlerTest.java?rev=755421&r1=755420&r2=755421&view=diff
==============================================================================
---
incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/opensocial/service/AppDataHandlerTest.java
(original)
+++
incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/opensocial/service/AppDataHandlerTest.java
Tue Mar 17 22:08:11 2009
@@ -17,6 +17,8 @@
*/
package org.apache.shindig.social.opensocial.service;
+import static org.easymock.EasyMock.eq;
+
import org.apache.shindig.common.EasyMockTestCase;
import org.apache.shindig.common.testing.FakeGadgetToken;
import org.apache.shindig.common.util.ImmediateFuture;
@@ -36,7 +38,6 @@
import com.google.common.collect.Sets;
import org.easymock.classextension.EasyMock;
-import static org.easymock.classextension.EasyMock.eq;
import java.io.StringReader;
import java.util.Collections;
@@ -147,7 +148,7 @@
params.put("fields", new String[]{"pandas"});
HashMap<String, String> values = Maps.newHashMap();
- org.easymock.EasyMock.expect(converter.convertToObject(eq(jsonAppData),
eq(HashMap.class)))
+ org.easymock.EasyMock.expect(converter.convertToObject(eq(jsonAppData),
eq(Map.class)))
.andReturn(values);
org.easymock.EasyMock.expect(appDataService.updatePersonData(eq(JOHN_DOE.iterator().next()),
@@ -184,7 +185,7 @@
// create an invalid set of app data and inject
values.put("Aokkey", "an ok key");
values.put("", "an empty value");
- org.easymock.EasyMock.expect(converter.convertToObject(eq(jsonAppData),
eq(HashMap.class)))
+ org.easymock.EasyMock.expect(converter.convertToObject(eq(jsonAppData),
eq(Map.class)))
.andReturn(values);
replay();
@@ -213,7 +214,7 @@
// create an invalid set of app data and inject
values.put("Aokkey", "an ok key");
values.put("a bad key", "a good value");
- org.easymock.EasyMock.expect(converter.convertToObject(eq(jsonAppData),
eq(HashMap.class)))
+ org.easymock.EasyMock.expect(converter.convertToObject(eq(jsonAppData),
eq(Map.class)))
.andReturn(values);
replay();