Author: doll
Date: Tue Jun 10 14:38:00 2008
New Revision: 666336

URL: http://svn.apache.org/viewvc?rev=666336&view=rev
Log:
Added the ability to convert from json to pojo (as opposed to pojo to json) to 
the beanJsonConverter class. Used this new functionality to support activity 
creation in the java json wire format. 

Also changed the javascript to convert the activity and media items to proper 
json objects. (before they had an odd format dependant on inner fields)


Modified:
    incubator/shindig/trunk/features/opensocial-current/jsonactivity.js
    incubator/shindig/trunk/features/opensocial-current/jsoncontainer.js
    
incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/opensocial/OpenSocialDataHandler.java
    
incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/opensocial/model/DataCollection.java
    
incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/opensocial/util/BeanJsonConverter.java
    
incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/opensocial/util/BeanJsonConverterTest.java
    
incubator/shindig/trunk/javascript/samplecontainer/examples/SocialActivitiesWorld.xml

Modified: incubator/shindig/trunk/features/opensocial-current/jsonactivity.js
URL: 
http://svn.apache.org/viewvc/incubator/shindig/trunk/features/opensocial-current/jsonactivity.js?rev=666336&r1=666335&r2=666336&view=diff
==============================================================================
--- incubator/shindig/trunk/features/opensocial-current/jsonactivity.js 
(original)
+++ incubator/shindig/trunk/features/opensocial-current/jsonactivity.js Tue Jun 
10 14:38:00 2008
@@ -23,14 +23,29 @@
  * @private
  * @constructor
  */
-JsonActivity = function(opt_params) {
+JsonActivity = function(opt_params, opt_skipConversions) {
   opt_params = opt_params || {};
-
-  JsonActivity.constructArrayObject(opt_params, "mediaItems", JsonMediaItem);
+  if (!opt_skipConversions) {
+    JsonActivity.constructArrayObject(opt_params, "mediaItems", JsonMediaItem);
+  }
   opensocial.Activity.call(this, opt_params);
 };
 JsonActivity.inherits(opensocial.Activity);
 
+JsonActivity.prototype.toJsonObject = function() {
+  var jsonObject = JsonActivity.copyFields(this.fields_);
+
+  var oldMediaItems = jsonObject['mediaItems'];
+  var newMediaItems = [];
+  for (var i = 0; i < oldMediaItems.length; i++) {
+    newMediaItems[i] = oldMediaItems[i].toJsonObject();
+  }
+  jsonObject['mediaItems'] = newMediaItems;
+
+  return jsonObject;
+}
+
+
 // TODO: Split into separate class
 JsonMediaItem = function(opt_params) {
   opensocial.MediaItem.call(this, opt_params['mimeType'],
@@ -38,6 +53,11 @@
 }
 JsonMediaItem.inherits(opensocial.MediaItem);
 
+JsonMediaItem.prototype.toJsonObject = function() {
+  return JsonActivity.copyFields(this.fields_);
+}
+
+
 // TODO: Pull this method into a common class, it is from jsonperson.js
 JsonActivity.constructArrayObject = function(map, fieldName, className) {
   var fieldValue = map[fieldName];
@@ -47,3 +67,12 @@
     }
   }
 }
+
+// TODO: Pull into common class as well
+JsonActivity.copyFields = function(oldObject) {
+  var newObject = {};
+  for (var field in oldObject) {
+    newObject[field] = oldObject[field];
+  }
+  return newObject;
+}

Modified: incubator/shindig/trunk/features/opensocial-current/jsoncontainer.js
URL: 
http://svn.apache.org/viewvc/incubator/shindig/trunk/features/opensocial-current/jsoncontainer.js?rev=666336&r1=666335&r2=666336&view=diff
==============================================================================
--- incubator/shindig/trunk/features/opensocial-current/jsoncontainer.js 
(original)
+++ incubator/shindig/trunk/features/opensocial-current/jsoncontainer.js Tue 
Jun 10 14:38:00 2008
@@ -191,11 +191,22 @@
       });
 };
 
+JsonContainer.prototype.newActivity = function(opt_params) {
+  return new JsonActivity(opt_params, true);
+};
+
+JsonContainer.prototype.newMediaItem = function(mimeType, url, opt_params) {
+  opt_params = opt_params || {};
+  opt_params['mimeType'] = mimeType;
+  opt_params['url'] = url;
+  return new JsonMediaItem(opt_params);
+};
+
 JsonContainer.prototype.newCreateActivityRequest = function(idSpec,
     activity) {
   return new RequestItem({'type' : 'CREATE_ACTIVITY',
     'idSpec' : JsonContainer.translateIdSpec(idSpec),
-    'activity' : activity});
+    'activity' : activity.toJsonObject()});
 };
 
 JsonContainer.prototype.newRequestSendMessageRequest = function(idSpec,

Modified: 
incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/opensocial/OpenSocialDataHandler.java
URL: 
http://svn.apache.org/viewvc/incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/opensocial/OpenSocialDataHandler.java?rev=666336&r1=666335&r2=666336&view=diff
==============================================================================
--- 
incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/opensocial/OpenSocialDataHandler.java
 (original)
+++ 
incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/opensocial/OpenSocialDataHandler.java
 Tue Jun 10 14:38:00 2008
@@ -23,6 +23,7 @@
 import org.apache.shindig.social.ResponseItem;
 import org.apache.shindig.social.opensocial.model.Activity;
 import org.apache.shindig.social.opensocial.model.IdSpec;
+import org.apache.shindig.social.opensocial.util.BeanJsonConverter;
 
 import com.google.common.collect.Lists;
 import com.google.inject.Inject;
@@ -47,13 +48,16 @@
   private PeopleService peopleHandler;
   private DataService dataHandler;
   private ActivitiesService activitiesHandler;
+  private final BeanJsonConverter beanJsonConverter;
 
   @Inject
   public OpenSocialDataHandler(PeopleService peopleHandler,
-      DataService dataHandler, ActivitiesService activitiesHandler) {
+      DataService dataHandler, ActivitiesService activitiesHandler,
+      BeanJsonConverter beanJsonConverter) {
     this.peopleHandler = peopleHandler;
     this.dataHandler = dataHandler;
     this.activitiesHandler = activitiesHandler;
+    this.beanJsonConverter = beanJsonConverter;
   }
 
   public enum OpenSocialDataType {
@@ -140,10 +144,8 @@
           // We only support creating an activity for one person right now
           String personId = peopleIds.get(0);
 
-          // TODO: We need to get the other fields from the json..
-          // so json -> pojo
-          Activity activity = new Activity("5", personId);
-          activity.setTitle("Temporary title - we don't read json right now");
+          Activity activity = beanJsonConverter.convertToObject(
+              params.getString("activity"), Activity.class);
           response = activitiesHandler.createActivity(personId, activity,
               request.getToken());
           break;

Modified: 
incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/opensocial/model/DataCollection.java
URL: 
http://svn.apache.org/viewvc/incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/opensocial/model/DataCollection.java?rev=666336&r1=666335&r2=666336&view=diff
==============================================================================
--- 
incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/opensocial/model/DataCollection.java
 (original)
+++ 
incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/opensocial/model/DataCollection.java
 Tue Jun 10 14:38:00 2008
@@ -42,6 +42,8 @@
     String personId;
     Map<String, String> appdata;
 
+    public Data() {}
+
     public Data(String personId, Map<String, String> appdata) {
       this.personId = personId;
       this.appdata = appdata;
@@ -54,5 +56,13 @@
     public Map<String, String> getAppdata() {
       return appdata;
     }
+
+    public void setPersonId(String personId) {
+      this.personId = personId;
+    }
+
+    public void setAppdata(Map<String, String> appdata) {
+      this.appdata = appdata;
+    }
   }
 }

Modified: 
incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/opensocial/util/BeanJsonConverter.java
URL: 
http://svn.apache.org/viewvc/incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/opensocial/util/BeanJsonConverter.java?rev=666336&r1=666335&r2=666336&view=diff
==============================================================================
--- 
incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/opensocial/util/BeanJsonConverter.java
 (original)
+++ 
incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/opensocial/util/BeanJsonConverter.java
 Tue Jun 10 14:38:00 2008
@@ -17,18 +17,26 @@
  */
 package org.apache.shindig.social.opensocial.util;
 
+import org.apache.shindig.social.opensocial.model.MediaItem;
+
 import org.json.JSONArray;
 import org.json.JSONException;
 import org.json.JSONObject;
 
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
+import java.lang.reflect.Type;
+import java.lang.reflect.ParameterizedType;
 import java.util.Date;
 import java.util.List;
 import java.util.Map;
+import java.util.Iterator;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+
 /**
  * Converts pojos to json objects
  * TODO: Replace with standard library
@@ -36,8 +44,9 @@
 public class BeanJsonConverter {
 
   private static final Object[] EMPTY_OBJECT = {};
-  private static final String EXCLUDED_GETTER = "class";
+  private static final String EXCLUDED_FIELDS = "class";
   private static final Pattern GETTER = Pattern.compile("^get([a-zA-Z]+)$");
+  private static final Pattern SETTER = Pattern.compile("^set([a-zA-Z]+)$");
 
   /**
    * Convert the passed in object to a json object
@@ -99,51 +108,172 @@
    * @return A JSONObject representing this pojo
    */
   private JSONObject convertMethodsToJson(Object pojo) {
+    List<MethodPair> availableGetters = getMatchingMethods(pojo, GETTER);
+
     JSONObject toReturn = new JSONObject();
-    Method[] methods = pojo.getClass().getMethods();
-    for (Method method : methods) {
-      String errorMessage = "Could not encode the " + method + " method.";
+    for (MethodPair getter : availableGetters) {
+      String errorMessage = "Could not encode the " + getter.method + " 
method.";
       try {
-        addMethodValue(pojo, toReturn, method);
-      } catch (JSONException e) {
+        Object val = getter.method.invoke(pojo, EMPTY_OBJECT);
+        if (val != null) {
+          toReturn.put(getter.fieldName, translateObjectToJson(val));
+        }
+      } catch(JSONException e) {
         throw new RuntimeException(errorMessage, e);
-      } catch (IllegalAccessException e) {
+      } catch(IllegalAccessException e) {
         throw new RuntimeException(errorMessage, e);
-      } catch (InvocationTargetException e) {
+      } catch(InvocationTargetException e) {
         throw new RuntimeException(errorMessage, e);
       }
     }
     return toReturn;
   }
 
-  /**
-   * Convert java declared method and its value to an entry in the given
-   * [EMAIL PROTECTED] JSONObject}
-   *
-   * @param pojo The pojo being translated
-   * @param object the json object to put the field value in
-   * @param method the method to encode
-   * @throws JSONException thrown exception
-   * @throws IllegalAccessException thrown exception
-   * @throws InvocationTargetException thrown exception
-   */
-  private void addMethodValue(Object pojo, JSONObject object,
-      Method method) throws JSONException, IllegalAccessException,
-      InvocationTargetException {
-    Matcher matcher = GETTER.matcher(method.getName());
-    if (!matcher.matches()) {
-      return;
+  private static class MethodPair {
+    public Method method;
+    public String fieldName;
+
+    private MethodPair(Method method, String fieldName) {
+      this.method = method;
+      this.fieldName = fieldName;
+    }
+  }
+
+  private List<MethodPair> getMatchingMethods(Object pojo, Pattern pattern) {
+    List<MethodPair> availableGetters = Lists.newArrayList();
+
+    Method[] methods = pojo.getClass().getMethods();
+    for (Method method : methods) {
+      Matcher matcher = pattern.matcher(method.getName());
+      if (!matcher.matches()) {
+        continue;
+      }
+
+      String name = matcher.group();
+      String fieldName = name.substring(3, 4).toLowerCase() + 
name.substring(4);
+      if (fieldName.equalsIgnoreCase(EXCLUDED_FIELDS)) {
+        continue;
+      }
+      availableGetters.add(new MethodPair(method, fieldName));
     }
+    return availableGetters;
+  }
+
+  public <T> T convertToObject(String json, Class<T> className) {
+    String errorMessage = "Could not convert " + json + " to " + className;
+
+    T pojo;
+    try {
+      pojo = className.newInstance();
+    } catch (InstantiationException e) {
+      throw new RuntimeException(errorMessage);
+    } catch (IllegalAccessException e) {
+      throw new RuntimeException(errorMessage);
+    }
+
+    if (pojo instanceof String) {
+      return (T) json; // This is a weird cast...
+
+    } else if (pojo instanceof List) {
+      // TODO: process as a JSONArray
+      throw new UnsupportedOperationException("We don't support lists as a " +
+          "base json type yet.");
+
+    } else {
+      JSONObject jsonObject;
+      try {
+        jsonObject = new JSONObject(json);
+        return convertToObject(jsonObject, className);
+      } catch (JSONException e) {
+        throw new RuntimeException(errorMessage);
+      } catch (InvocationTargetException e) {
+        throw new RuntimeException(errorMessage);
+      } catch (IllegalAccessException e) {
+        throw new RuntimeException(errorMessage);
+      } catch (InstantiationException e) {
+        throw new RuntimeException(errorMessage);
+
+      }
+    }
+  }
+
+  public <T> T convertToObject(JSONObject jsonObject, Class<T> className)
+      throws JSONException, InvocationTargetException, IllegalAccessException,
+      InstantiationException {
+    T pojo = className.newInstance();
+
+    List<MethodPair> methods = getMatchingMethods(pojo, SETTER);
+    for (MethodPair setter : methods) {
+      if (jsonObject.has(setter.fieldName)) {
+        callSetterWithValue(pojo, setter.method, jsonObject, setter.fieldName);
+      }
+    }
+
+    return pojo;
+  }
+
+  private <T> void callSetterWithValue(T pojo, Method method,
+      JSONObject jsonObject, String fieldName)
+      throws IllegalAccessException, InvocationTargetException, JSONException {
+
+    Class<?> expectedType = method.getParameterTypes()[0];
+    Object value = null;
+
+    if (expectedType.equals(List.class)) {
+      ParameterizedType genericListType
+          = (ParameterizedType) method.getGenericParameterTypes()[0];
+      Class<?> listElementClass
+          = (Class) genericListType.getActualTypeArguments()[0];
+
+      List list = Lists.newArrayList();
+      JSONArray jsonArray = jsonObject.getJSONArray(fieldName);
+      for (int i = 0; i < jsonArray.length(); i++) {
+        list.add(convertToObject(jsonArray.getString(i), listElementClass));
+      }
+
+      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 (expectedType.getSuperclass().equals(Enum.class)) {
+      String enumString = jsonObject.getString(fieldName);
+      value = Enum.valueOf((Class<? extends Enum>) expectedType, enumString);
+
+    } else if (expectedType.equals(String.class)) {
+      value = jsonObject.getString(fieldName);
+
+    } else if (expectedType.equals(Date.class)) {
+      Long time = jsonObject.getLong(fieldName);
+      value = new Date(time);
+
+    } else if (expectedType.equals(Long.class)) {
+      value = jsonObject.getLong(fieldName);
 
-    String name = matcher.group();
-    String fieldName = name.substring(3, 4).toLowerCase() + name.substring(4);
-    if (fieldName.equalsIgnoreCase(EXCLUDED_GETTER)) {
-      return;
+    } else if (expectedType.equals(Float.class)) {
+      String stringFloat = jsonObject.getString(fieldName);
+      value = new Float(stringFloat);
     }
 
-    Object val = method.invoke(pojo, EMPTY_OBJECT);
-    if (val != null) {
-      object.put(fieldName, translateObjectToJson(val));
+    if (value != null) {
+      method.invoke(pojo, value);
     }
   }
-}
+}
\ No newline at end of file

Modified: 
incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/opensocial/util/BeanJsonConverterTest.java
URL: 
http://svn.apache.org/viewvc/incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/opensocial/util/BeanJsonConverterTest.java?rev=666336&r1=666335&r2=666336&view=diff
==============================================================================
--- 
incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/opensocial/util/BeanJsonConverterTest.java
 (original)
+++ 
incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/opensocial/util/BeanJsonConverterTest.java
 Tue Jun 10 14:38:00 2008
@@ -24,6 +24,7 @@
 import org.apache.shindig.social.opensocial.model.Name;
 import org.apache.shindig.social.opensocial.model.Person;
 import org.apache.shindig.social.opensocial.model.Phone;
+import org.apache.shindig.social.opensocial.model.DataCollection;
 
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
@@ -174,4 +175,44 @@
     assertEquals(colors[0], jsonArray.get(0));
   }
 
+  public void testJsonToActivity() throws Exception {
+    String jsonActivity = "{userId : 5, id : 6, mediaItems : [" +
+        "{url : 'hello', mimeType : 'mimey', type : 'VIDEO'}" +
+        "]}";
+    // TODO: rename the enums to be lowercase
+    Activity result = beanJsonConverter.convertToObject(jsonActivity,
+        Activity.class);
+
+    assertEquals("5", result.getUserId());
+    assertEquals("6", result.getId());
+
+    assertEquals(1, result.getMediaItems().size());
+
+    MediaItem actualItem = result.getMediaItems().get(0);
+
+    assertEquals("hello", actualItem.getUrl());
+    assertEquals("mimey", actualItem.getMimeType());
+    assertEquals("video", actualItem.getType().toString());
+  }
+
+  public void testJsonToMap() throws Exception {
+    String jsonActivity = "{personId : 'john.doe', " +
+        "appdata : {count : 0, favoriteColor : 'yellow'}}";
+    DataCollection.Data result = 
beanJsonConverter.convertToObject(jsonActivity,
+        DataCollection.Data.class);
+
+    assertEquals("john.doe", result.getPersonId());
+    Map<String, String> data = result.getAppdata();
+    assertEquals(2, data.size());
+
+    for (String key : data.keySet()) {
+      String value = data.get(key);
+      if (key.equals("count")) {
+        assertEquals("0", value);
+      } else if (key.equals("favoriteColor")) {
+        assertEquals("yellow", value);
+      }
+    }
+  }
+
 }

Modified: 
incubator/shindig/trunk/javascript/samplecontainer/examples/SocialActivitiesWorld.xml
URL: 
http://svn.apache.org/viewvc/incubator/shindig/trunk/javascript/samplecontainer/examples/SocialActivitiesWorld.xml?rev=666336&r1=666335&r2=666336&view=diff
==============================================================================
--- 
incubator/shindig/trunk/javascript/samplecontainer/examples/SocialActivitiesWorld.xml
 (original)
+++ 
incubator/shindig/trunk/javascript/samplecontainer/examples/SocialActivitiesWorld.xml
 Tue Jun 10 14:38:00 2008
@@ -113,7 +113,7 @@
 
 function postNewActivity() {
   var activityElement = document.getElementById('newActivity');
-  var mediaItem = new Array(opensocial.newActivityMediaItem("image", 
viewer.getField('thumbnailUrl'), {'type' : 'IMAGE'}));
+  var mediaItem = new Array(opensocial.newActivityMediaItem("image", 
"http://cdn.davesdaily.com/pictures/784-awesome-hands.jpg";, {'type' : 
'IMAGE'}));
   var activity = opensocial.newActivity({ 'title' : viewer.getDisplayName() + 
' wrote: ' + activityElement.value,
     'body' : 'write back!', 'mediaItems' : mediaItem});
 


Reply via email to