From d49eae96c9f00fbdf092be813df8417775388b8f Mon Sep 17 00:00:00 2001 From: Chris Lang Date: Thu, 15 Nov 2012 12:54:38 -0800 Subject: [PATCH] [android-sdk] Moved GraphObjectWrapper to GraphObject.Factory. Summary: GraphObjectWrapper had a name that did not clearly indicate its purpose. It is really a factory for GraphObjects, and as such it makes sense to nest it within GraphObject and call it Factory. This commit does that, and also shortens some of its method names, since it is clear from context now what they are creating. Fixed a warning in WebDialog.java. Test Plan: - Built all projects - Ran unit tests Revert Plan: Reviewers: mmarucheck, mingfli, karthiks Reviewed By: mingfli CC: ekoneil, caabernathy, platform-diffs@lists, security-diffs@lists Differential Revision: https://phabricator.fb.com/D632163 --- facebook/src/com/facebook/Response.java | 6 +- facebook/src/com/facebook/Settings.java | 3 +- .../src/com/facebook/model/GraphLocation.java | 2 +- .../com/facebook/model/GraphMultiResult.java | 2 +- .../src/com/facebook/model/GraphObject.java | 669 ++++++++++++++++- .../com/facebook/model/GraphObjectList.java | 2 +- .../facebook/model/GraphObjectWrapper.java | 686 ------------------ .../src/com/facebook/model/GraphPlace.java | 2 +- .../src/com/facebook/model/GraphUser.java | 2 +- .../com/facebook/model/OpenGraphAction.java | 2 +- .../facebook/widget/GraphObjectAdapter.java | 5 +- .../src/com/facebook/widget/WebDialog.java | 2 +- .../facebook/FacebookActivityTestCase.java | 3 +- .../src/com/facebook/GraphRequestTests.java | 5 +- .../tests/src/com/facebook/RequestTests.java | 2 +- .../model/GraphObjectWrapperTests.java | 169 +++-- .../samples/booleanog/LogicActivity.java | 8 +- .../scrumptious/SelectionFragment.java | 10 +- 18 files changed, 784 insertions(+), 796 deletions(-) delete mode 100644 facebook/src/com/facebook/model/GraphObjectWrapper.java diff --git a/facebook/src/com/facebook/Response.java b/facebook/src/com/facebook/Response.java index 14f47b8ad9..b5dec0f82a 100644 --- a/facebook/src/com/facebook/Response.java +++ b/facebook/src/com/facebook/Response.java @@ -19,7 +19,6 @@ import android.content.Context; import com.facebook.model.GraphObject; import com.facebook.model.GraphObjectList; -import com.facebook.model.GraphObjectWrapper; import com.facebook.internal.CacheableRequestBatch; import com.facebook.internal.FileLruCache; import com.facebook.internal.Logger; @@ -416,9 +415,10 @@ private static Response createResponseFromObject(Request request, HttpURLConnect GraphObject graphObject = null; GraphObjectList graphObjectList = null; if (body instanceof JSONObject) { - graphObject = GraphObjectWrapper.createGraphObject((JSONObject) body); + graphObject = GraphObject.Factory.create((JSONObject) body); } else if (body instanceof JSONArray) { - graphObjectList = GraphObjectWrapper.createGraphObjectList((JSONArray) body, GraphObject.class); + graphObjectList = GraphObject.Factory + .createList((JSONArray) body, GraphObject.class); } return new Response(request, connection, graphObject, graphObjectList, isFromCache); } else if (object == JSONObject.NULL) { diff --git a/facebook/src/com/facebook/Settings.java b/facebook/src/com/facebook/Settings.java index 60a62e78b7..39ce18792c 100644 --- a/facebook/src/com/facebook/Settings.java +++ b/facebook/src/com/facebook/Settings.java @@ -25,7 +25,6 @@ import android.os.Bundle; import com.facebook.android.Util; import com.facebook.model.GraphObject; -import com.facebook.model.GraphObjectWrapper; import com.facebook.internal.Validate; import org.json.JSONException; @@ -249,7 +248,7 @@ public static boolean publishInstallAndWait(final Context context, final String } if ((Boolean)doesSupportAttribution) { - GraphObject publishParams = GraphObjectWrapper.createGraphObject(); + GraphObject publishParams = GraphObject.Factory.create(); publishParams.setProperty(ANALYTICS_EVENT, MOBILE_INSTALL_EVENT); publishParams.setProperty(ATTRIBUTION_KEY, attributionId); diff --git a/facebook/src/com/facebook/model/GraphLocation.java b/facebook/src/com/facebook/model/GraphLocation.java index 7e455c00a7..e789caa8e8 100644 --- a/facebook/src/com/facebook/model/GraphLocation.java +++ b/facebook/src/com/facebook/model/GraphLocation.java @@ -19,7 +19,7 @@ /** * Provides a strongly-typed representation of a Location as defined by the Graph API. * - * Note that this interface is intended to be used with GraphObjectWrapper + * Note that this interface is intended to be used with GraphObject.Factory * and not implemented directly. */ public interface GraphLocation extends GraphObject { diff --git a/facebook/src/com/facebook/model/GraphMultiResult.java b/facebook/src/com/facebook/model/GraphMultiResult.java index f0f0d19296..2f811e5d6e 100644 --- a/facebook/src/com/facebook/model/GraphMultiResult.java +++ b/facebook/src/com/facebook/model/GraphMultiResult.java @@ -20,7 +20,7 @@ * Defines a GraphObject that represents the result of a query that returns multiple GraphObjects * nested under a "data" property. * - * Note that this interface is intended to be used with GraphObjectWrapper + * Note that this interface is intended to be used with GraphObject.Factory * and not implemented directly. */ public interface GraphMultiResult extends GraphObject { diff --git a/facebook/src/com/facebook/model/GraphObject.java b/facebook/src/com/facebook/model/GraphObject.java index d5684ccd10..935c39ff3c 100644 --- a/facebook/src/com/facebook/model/GraphObject.java +++ b/facebook/src/com/facebook/model/GraphObject.java @@ -16,15 +16,23 @@ package com.facebook.model; +import com.facebook.FacebookGraphObjectException; +import com.facebook.internal.Utility; +import com.facebook.internal.Validate; +import org.json.JSONArray; +import org.json.JSONException; import org.json.JSONObject; -import java.util.Map; +import java.lang.reflect.*; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.*; /** * GraphObject is the primary interface used by the Facebook SDK for Android to represent objects in the Facebook * Social Graph and the Facebook Open Graph (OG). It is the base interface for all typed access to graph objects * in the SDK. No concrete classes implement GraphObject or its derived interfaces. Rather, they are implemented as - * proxies (see the {@link GraphObjectWrapper GraphObjectWrapper} class) that provide strongly-typed property + * proxies (see the {@link com.facebook.model.GraphObject.Factory Factory} class) that provide strongly-typed property * getters and setters to access the underlying data. Since the primary use case for graph objects is sending and * receiving them over the wire to/from Facebook services, they are represented as JSONObjects. No validation is done * that a graph object is actually of a specific type -- any graph object can be treated as any GraphObject-derived @@ -72,4 +80,661 @@ public interface GraphObject { * @param propertyName the name of the property to remove */ public void removeProperty(String propertyName); + + /** + * Creates proxies that implement GraphObject, GraphObjectList, and their derived types. These proxies allow access + * to underlying collections and name/value property bags via strongly-typed property getters and setters. + *

+ * This supports get/set properties that use primitive types, JSON types, Date, other GraphObject types, Iterable, + * Collection, List, and GraphObjectList. + */ + final class Factory { + private static final HashSet> verifiedGraphObjectClasses = new HashSet>(); + private static final SimpleDateFormat[] dateFormats = new SimpleDateFormat[] { + new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.US), + new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.US), new SimpleDateFormat("yyyy-MM-dd", Locale.US), }; + + // No objects of this type should exist. + private Factory() { + } + + /** + * Creates a GraphObject proxy that provides typed access to the data in an underlying JSONObject. + * @param json the JSONObject containing the data to be exposed + * @return a GraphObject that represents the underlying data + * + * @throws com.facebook.FacebookException + * If the passed in Class is not a valid GraphObject interface + */ + public static GraphObject create(JSONObject json) { + return create(json, GraphObject.class); + } + + /** + * Creates a GraphObject-derived proxy that provides typed access to the data in an underlying JSONObject. + * @param json the JSONObject containing the data to be exposed + * @param graphObjectClass the GraphObject-derived type to return + * @return a graphObjectClass that represents the underlying data + * + * @throws com.facebook.FacebookException + * If the passed in Class is not a valid GraphObject interface + */ + public static T create(JSONObject json, Class graphObjectClass) { + return createGraphObjectProxy(graphObjectClass, json); + } + + /** + * Creates a GraphObject proxy that initially contains no data. + * @return a GraphObject with no data + * + * @throws com.facebook.FacebookException + * If the passed in Class is not a valid GraphObject interface + */ + public static GraphObject create() { + return create(GraphObject.class); + } + + /** + * Creates a GraphObject-derived proxy that initially contains no data. + * @param graphObjectClass the GraphObject-derived type to return + * @return a graphObjectClass with no data + * + * @throws com.facebook.FacebookException + * If the passed in Class is not a valid GraphObject interface + */ + public static T create(Class graphObjectClass) { + return createGraphObjectProxy(graphObjectClass, new JSONObject()); + } + + /** + * Determines if two GraphObjects represent the same underlying graph object, based on their IDs. + * @param a a graph object + * @param b another graph object + * @return true if both graph objects have an ID and it is the same ID, false otherwise + */ + public static boolean hasSameId(GraphObject a, GraphObject b) { + if (a == null || b == null || !a.asMap().containsKey("id") || !b.asMap().containsKey("id")) { + return false; + } + if (a.equals(b)) { + return true; + } + Object idA = a.getProperty("id"); + Object idB = b.getProperty("id"); + if (idA == null || idB == null || !(idA instanceof String) || !(idB instanceof String)) { + return false; + } + return idA.equals(idB); + } + + /** + * Creates a GraphObjectList-derived proxy that provides typed access to the data in an underlying JSONArray. + * @param array the JSONArray containing the data to be exposed + * @param graphObjectClass the GraphObject-derived type to return + * @return a graphObjectClass that represents the underlying data + * + * @throws com.facebook.FacebookException + * If the passed in Class is not a valid GraphObject interface + */ + public static GraphObjectList createList(JSONArray array, Class graphObjectClass) { + return new GraphObjectListImpl(array, graphObjectClass); + } + + /** + * Creates a GraphObjectList-derived proxy that initially contains no data. + * @param graphObjectClass the GraphObject-derived type to return + * @return a GraphObjectList with no data + * + * @throws com.facebook.FacebookException + * If the passed in Class is not a valid GraphObject interface + */ + public static GraphObjectList createList(Class graphObjectClass) { + return createList(new JSONArray(), graphObjectClass); + } + + private static T createGraphObjectProxy(Class graphObjectClass, JSONObject state) { + verifyCanProxyClass(graphObjectClass); + + Class[] interfaces = new Class[] { graphObjectClass }; + GraphObjectProxy graphObjectProxy = new GraphObjectProxy(state, graphObjectClass); + + @SuppressWarnings("unchecked") + T graphObject = (T) Proxy.newProxyInstance(GraphObject.class.getClassLoader(), interfaces, graphObjectProxy); + + return graphObject; + } + + private static Map createGraphObjectProxyForMap(JSONObject state) { + Class[] interfaces = new Class[]{Map.class}; + GraphObjectProxy graphObjectProxy = new GraphObjectProxy(state, Map.class); + + @SuppressWarnings("unchecked") + Map graphObject = (Map) Proxy + .newProxyInstance(GraphObject.class.getClassLoader(), interfaces, graphObjectProxy); + + return graphObject; + } + + private static synchronized boolean hasClassBeenVerified(Class graphObjectClass) { + return verifiedGraphObjectClasses.contains(graphObjectClass); + } + + private static synchronized void recordClassHasBeenVerified(Class graphObjectClass) { + verifiedGraphObjectClasses.add(graphObjectClass); + } + + private static void verifyCanProxyClass(Class graphObjectClass) { + if (hasClassBeenVerified(graphObjectClass)) { + return; + } + + if (!graphObjectClass.isInterface()) { + throw new FacebookGraphObjectException("Factory can only wrap interfaces, not class: " + + graphObjectClass.getName()); + } + + Method[] methods = graphObjectClass.getMethods(); + for (Method method : methods) { + String methodName = method.getName(); + int parameterCount = method.getParameterTypes().length; + Class returnType = method.getReturnType(); + boolean hasPropertyNameOverride = method.isAnnotationPresent(PropertyName.class); + + if (method.getDeclaringClass().isAssignableFrom(GraphObject.class)) { + // Don't worry about any methods from GraphObject or one of its base classes. + continue; + } else if (parameterCount == 1 && returnType == Void.TYPE) { + if (hasPropertyNameOverride) { + // If a property override is present, it MUST be valid. We don't fallback + // to using the method name + if (!Utility.isNullOrEmpty(method.getAnnotation(PropertyName.class).value())) { + continue; + } + } else if (methodName.startsWith("set") && methodName.length() > 3) { + // Looks like a valid setter + continue; + } + } else if (parameterCount == 0 && returnType != Void.TYPE) { + if (hasPropertyNameOverride) { + // If a property override is present, it MUST be valid. We don't fallback + // to using the method name + if (!Utility.isNullOrEmpty(method.getAnnotation(PropertyName.class).value())) { + continue; + } + } else if (methodName.startsWith("get") && methodName.length() > 3) { + // Looks like a valid getter + continue; + } + } + + throw new FacebookGraphObjectException("Factory can't proxy method: " + method.toString()); + } + + recordClassHasBeenVerified(graphObjectClass); + } + + // If expectedType is a generic type, expectedTypeAsParameterizedType must be provided in order to determine + // generic parameter types. + static U coerceValueToExpectedType(Object value, Class expectedType, + ParameterizedType expectedTypeAsParameterizedType) { + if (value == null) { + return null; + } + + Class valueType = value.getClass(); + if (expectedType.isAssignableFrom(valueType)) { + @SuppressWarnings("unchecked") + U result = (U) value; + return result; + } + + if (expectedType.isPrimitive()) { + // If the result is a primitive, let the runtime succeed or fail at unboxing it. + @SuppressWarnings("unchecked") + U result = (U) value; + return result; + } + + if (GraphObject.class.isAssignableFrom(expectedType)) { + @SuppressWarnings("unchecked") + Class graphObjectClass = (Class) expectedType; + + // We need a GraphObject, but we don't have one. + if (JSONObject.class.isAssignableFrom(valueType)) { + // We can wrap a JSONObject as a GraphObject. + @SuppressWarnings("unchecked") + U result = (U) createGraphObjectProxy(graphObjectClass, (JSONObject) value); + return result; + } else if (GraphObject.class.isAssignableFrom(valueType)) { + // We can cast a GraphObject-derived class to another GraphObject-derived class. + @SuppressWarnings("unchecked") + U result = (U) ((GraphObject) value).cast(graphObjectClass); + return result; + } else { + throw new FacebookGraphObjectException("Can't create GraphObject from " + valueType.getName()); + } + } else if (Iterable.class.equals(expectedType) || Collection.class.equals(expectedType) + || List.class.equals(expectedType) || GraphObjectList.class.equals(expectedType)) { + if (expectedTypeAsParameterizedType == null) { + throw new FacebookGraphObjectException("can't infer generic type of: " + expectedType.toString()); + } + + Type[] actualTypeArguments = expectedTypeAsParameterizedType.getActualTypeArguments(); + + if (actualTypeArguments == null || actualTypeArguments.length != 1 + || !(actualTypeArguments[0] instanceof Class)) { + throw new FacebookGraphObjectException( + "Expect collection properties to be of a type with exactly one generic parameter."); + } + Class collectionGenericArgument = (Class) actualTypeArguments[0]; + + if (JSONArray.class.isAssignableFrom(valueType)) { + JSONArray jsonArray = (JSONArray) value; + @SuppressWarnings("unchecked") + U result = (U) createList(jsonArray, collectionGenericArgument); + return result; + } else { + throw new FacebookGraphObjectException("Can't create Collection from " + valueType.getName()); + } + } else if (String.class.equals(expectedType)) { + if (Number.class.isAssignableFrom(valueType)) { + @SuppressWarnings("unchecked") + U result = (U) String.format("%d", value); + return result; + } + } else if (Date.class.equals(expectedType)) { + if (String.class.isAssignableFrom(valueType)) { + for (SimpleDateFormat format : dateFormats) { + try { + Date date = format.parse((String) value); + if (date != null) { + @SuppressWarnings("unchecked") + U result = (U) date; + return result; + } + } catch (ParseException e) { + // Keep going. + } + } + } + } + throw new FacebookGraphObjectException("Can't convert type" + valueType.getName() + " to " + + expectedType.getName()); + } + + static String convertCamelCaseToLowercaseWithUnderscores(String string) { + string = string.replaceAll("([a-z])([A-Z])", "$1_$2"); + return string.toLowerCase(); + } + + private static Object getUnderlyingJSONObject(Object obj) { + Class objClass = obj.getClass(); + if (GraphObject.class.isAssignableFrom(objClass)) { + GraphObject graphObject = (GraphObject) obj; + return graphObject.getInnerJSONObject(); + } else if (GraphObjectList.class.isAssignableFrom(objClass)) { + GraphObjectList graphObjectList = (GraphObjectList) obj; + return graphObjectList.getInnerJSONArray(); + } + return obj; + } + + private abstract static class ProxyBase implements InvocationHandler { + // Pre-loaded Method objects for the methods in java.lang.Object + private static final String EQUALS_METHOD = "equals"; + private static final String TOSTRING_METHOD = "toString"; + + protected final STATE state; + + protected ProxyBase(STATE state) { + this.state = state; + } + + // Declared to return Object just to simplify implementation of proxy helpers. + protected final Object throwUnexpectedMethodSignature(Method method) { + throw new FacebookGraphObjectException(getClass().getName() + " got an unexpected method signature: " + + method.toString()); + } + + protected final Object proxyObjectMethods(Object proxy, Method method, Object[] args) throws Throwable { + String methodName = method.getName(); + if (methodName.equals(EQUALS_METHOD)) { + Object other = args[0]; + + if (other == null) { + return false; + } + + InvocationHandler handler = Proxy.getInvocationHandler(other); + if (!(handler instanceof GraphObjectProxy)) { + return false; + } + GraphObjectProxy otherProxy = (GraphObjectProxy) handler; + return this.state.equals(otherProxy.state); + } else if (methodName.equals(TOSTRING_METHOD)) { + return toString(); + } + + // For others, just defer to the implementation object. + return method.invoke(this.state, args); + } + + } + + private final static class GraphObjectProxy extends ProxyBase { + private static final String CLEAR_METHOD = "clear"; + private static final String CONTAINSKEY_METHOD = "containsKey"; + private static final String CONTAINSVALUE_METHOD = "containsValue"; + private static final String ENTRYSET_METHOD = "entrySet"; + private static final String GET_METHOD = "get"; + private static final String ISEMPTY_METHOD = "isEmpty"; + private static final String KEYSET_METHOD = "keySet"; + private static final String PUT_METHOD = "put"; + private static final String PUTALL_METHOD = "putAll"; + private static final String REMOVE_METHOD = "remove"; + private static final String SIZE_METHOD = "size"; + private static final String VALUES_METHOD = "values"; + private static final String CAST_METHOD = "cast"; + private static final String CASTTOMAP_METHOD = "asMap"; + private static final String GETPROPERTY_METHOD = "getProperty"; + private static final String SETPROPERTY_METHOD = "setProperty"; + private static final String REMOVEPROPERTY_METHOD = "removeProperty"; + private static final String GETINNERJSONOBJECT_METHOD = "getInnerJSONObject"; + + private final Class graphObjectClass; + + public GraphObjectProxy(JSONObject state, Class graphObjectClass) { + super(state); + this.graphObjectClass = graphObjectClass; + } + + @Override + public String toString() { + return String.format("GraphObject{graphObjectClass=%s, state=%s}", graphObjectClass.getSimpleName(), state); + } + + @Override + public final Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + Class declaringClass = method.getDeclaringClass(); + + if (declaringClass == Object.class) { + return proxyObjectMethods(proxy, method, args); + } else if (declaringClass == Map.class) { + return proxyMapMethods(method, args); + } else if (declaringClass == GraphObject.class) { + return proxyGraphObjectMethods(proxy, method, args); + } else if (GraphObject.class.isAssignableFrom(declaringClass)) { + return proxyGraphObjectGettersAndSetters(method, args); + } + + return throwUnexpectedMethodSignature(method); + } + + private final Object proxyMapMethods(Method method, Object[] args) { + String methodName = method.getName(); + if (methodName.equals(CLEAR_METHOD)) { + JsonUtil.jsonObjectClear(this.state); + return null; + } else if (methodName.equals(CONTAINSKEY_METHOD)) { + return this.state.has((String) args[0]); + } else if (methodName.equals(CONTAINSVALUE_METHOD)) { + return JsonUtil.jsonObjectContainsValue(this.state, args[0]); + } else if (methodName.equals(ENTRYSET_METHOD)) { + return JsonUtil.jsonObjectEntrySet(this.state); + } else if (methodName.equals(GET_METHOD)) { + return this.state.opt((String) args[0]); + } else if (methodName.equals(ISEMPTY_METHOD)) { + return this.state.length() == 0; + } else if (methodName.equals(KEYSET_METHOD)) { + return JsonUtil.jsonObjectKeySet(this.state); + } else if (methodName.equals(PUT_METHOD)) { + return setJSONProperty(args); + } else if (methodName.equals(PUTALL_METHOD)) { + Map map = null; + if (args[0] instanceof Map) { + @SuppressWarnings("unchecked") + Map castMap = (Map) args[0]; + map = castMap; + } else if (args[0] instanceof GraphObject) { + map = ((GraphObject) args[0]).asMap(); + } + JsonUtil.jsonObjectPutAll(this.state, map); + return null; + } else if (methodName.equals(REMOVE_METHOD)) { + this.state.remove((String) args[0]); + return null; + } else if (methodName.equals(SIZE_METHOD)) { + return this.state.length(); + } else if (methodName.equals(VALUES_METHOD)) { + return JsonUtil.jsonObjectValues(this.state); + } + + return throwUnexpectedMethodSignature(method); + } + + private final Object proxyGraphObjectMethods(Object proxy, Method method, Object[] args) { + String methodName = method.getName(); + if (methodName.equals(CAST_METHOD)) { + @SuppressWarnings("unchecked") + Class graphObjectClass = (Class) args[0]; + + if (graphObjectClass != null && + graphObjectClass.isAssignableFrom(this.graphObjectClass)) { + return proxy; + } + return Factory.createGraphObjectProxy(graphObjectClass, this.state); + } else if (methodName.equals(GETINNERJSONOBJECT_METHOD)) { + InvocationHandler handler = Proxy.getInvocationHandler(proxy); + GraphObjectProxy otherProxy = (GraphObjectProxy) handler; + return otherProxy.state; + } else if (methodName.equals(CASTTOMAP_METHOD)) { + return Factory.createGraphObjectProxyForMap(this.state); + } else if (methodName.equals(GETPROPERTY_METHOD)) { + return state.opt((String) args[0]); + } else if (methodName.equals(SETPROPERTY_METHOD)) { + return setJSONProperty(args); + } else if (methodName.equals(REMOVEPROPERTY_METHOD)) { + this.state.remove((String) args[0]); + return null; + } + + return throwUnexpectedMethodSignature(method); + } + + private final Object proxyGraphObjectGettersAndSetters(Method method, Object[] args) throws JSONException { + String methodName = method.getName(); + int parameterCount = method.getParameterTypes().length; + PropertyName propertyNameOverride = method.getAnnotation(PropertyName.class); + + String key = propertyNameOverride != null ? propertyNameOverride.value() : + convertCamelCaseToLowercaseWithUnderscores(methodName.substring(3)); + + // If it's a get or a set on a GraphObject-derived class, we can handle it. + if (parameterCount == 0) { + // Has to be a getter. ASSUMPTION: The GraphObject-derived class has been verified + Object value = this.state.opt(key); + + Class expectedType = method.getReturnType(); + + Type genericReturnType = method.getGenericReturnType(); + ParameterizedType parameterizedReturnType = null; + if (genericReturnType instanceof ParameterizedType) { + parameterizedReturnType = (ParameterizedType) genericReturnType; + } + + value = coerceValueToExpectedType(value, expectedType, parameterizedReturnType); + + return value; + } else if (parameterCount == 1) { + // Has to be a setter. ASSUMPTION: The GraphObject-derived class has been verified + Object value = args[0]; + // If this is a wrapped object, store the underlying JSONObject instead, in order to serialize + // correctly. + if (GraphObject.class.isAssignableFrom(value.getClass())) { + value = ((GraphObject) value).getInnerJSONObject(); + } else if (GraphObjectList.class.isAssignableFrom(value.getClass())) { + value = ((GraphObjectList) value).getInnerJSONArray(); + } else if (Iterable.class.isAssignableFrom(value.getClass())) { + JSONArray jsonArray = new JSONArray(); + Iterable iterable = (Iterable) value; + for (Object o : iterable ) { + if (GraphObject.class.isAssignableFrom(o.getClass())) { + jsonArray.put(((GraphObject)o).getInnerJSONObject()); + } else { + jsonArray.put(o); + } + } + value = jsonArray; + } + this.state.putOpt(key, value); + return null; + } + + return throwUnexpectedMethodSignature(method); + } + + private Object setJSONProperty(Object[] args) { + String name = (String) args[0]; + Object property = args[1]; + Object value = getUnderlyingJSONObject(property); + try { + state.putOpt(name, value); + } catch (JSONException e) { + throw new IllegalArgumentException(e); + } + return null; + } + } + + private final static class GraphObjectListImpl extends AbstractList implements GraphObjectList { + private final JSONArray state; + private final Class itemType; + + public GraphObjectListImpl(JSONArray state, Class itemType) { + Validate.notNull(state, "state"); + Validate.notNull(itemType, "itemType"); + + this.state = state; + this.itemType = itemType; + } + + @Override + public String toString() { + return String.format("GraphObjectList{itemType=%s, state=%s}", itemType.getSimpleName(), state); + } + + @Override + public void add(int location, T object) { + // We only support adding at the end of the list, due to JSONArray restrictions. + if (location < 0) { + throw new IndexOutOfBoundsException(); + } else if (location < size()) { + throw new UnsupportedOperationException("Only adding items at the end of the list is supported."); + } + + put(location, object); + } + + @Override + public T set(int location, T object) { + checkIndex(location); + + T result = get(location); + put(location, object); + return result; + } + + @Override + public int hashCode() { + return state.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (getClass() != obj.getClass()) { + return false; + } + @SuppressWarnings("unchecked") + GraphObjectListImpl other = (GraphObjectListImpl) obj; + return state.equals(other.state); + } + + @SuppressWarnings("unchecked") + @Override + public T get(int location) { + checkIndex(location); + + Object value = state.opt(location); + + // Class expectedType = method.getReturnType(); + // Type genericType = method.getGenericReturnType(); + T result = (T) coerceValueToExpectedType(value, itemType, null); + + return result; + } + + @Override + public int size() { + return state.length(); + } + + @Override + public final GraphObjectList castToListOf(Class graphObjectClass) { + if (GraphObject.class.isAssignableFrom(itemType)) { + if (graphObjectClass.isAssignableFrom(itemType)) { + @SuppressWarnings("unchecked") + GraphObjectList result = (GraphObjectList)this; + return result; + } + + return createList(state, graphObjectClass); + } else { + throw new FacebookGraphObjectException("Can't cast GraphObjectCollection of non-GraphObject type " + + itemType); + } + } + + @Override + public final JSONArray getInnerJSONArray() { + return state; + } + + @Override + public void clear() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean remove(Object o) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean removeAll(Collection c) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean retainAll(Collection c) { + throw new UnsupportedOperationException(); + } + + private void checkIndex(int index) { + if (index < 0 || index >= state.length()) { + throw new IndexOutOfBoundsException(); + } + } + + private void put(int index, T obj) { + Object underlyingObject = getUnderlyingJSONObject(obj); + try { + state.put(index, underlyingObject); + } catch (JSONException e) { + throw new IllegalArgumentException(e); + } + } + } + } } diff --git a/facebook/src/com/facebook/model/GraphObjectList.java b/facebook/src/com/facebook/model/GraphObjectList.java index 5610f1e9d4..9e4b1e99df 100644 --- a/facebook/src/com/facebook/model/GraphObjectList.java +++ b/facebook/src/com/facebook/model/GraphObjectList.java @@ -22,7 +22,7 @@ /** * GraphObjectList is the primary representation of a collection of graph objects in the Facebook SDK for Android. - * It is not implemented by any concrete classes, but rather by a proxy (see the {@link GraphObjectWrapper GraphObjectWrapper} + * It is not implemented by any concrete classes, but rather by a proxy (see the {@link com.facebook.model.GraphObject.Factory Factory} * class). A GraphObjectList can actually contain elements of any type, not just graph objects, but its principal * use in the SDK is to contain types derived from GraphObject. *
diff --git a/facebook/src/com/facebook/model/GraphObjectWrapper.java b/facebook/src/com/facebook/model/GraphObjectWrapper.java deleted file mode 100644 index 6ac49702c0..0000000000 --- a/facebook/src/com/facebook/model/GraphObjectWrapper.java +++ /dev/null @@ -1,686 +0,0 @@ -/** - * Copyright 2010 Facebook, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.facebook.model; - -import com.facebook.FacebookGraphObjectException; -import com.facebook.internal.Utility; -import com.facebook.internal.Validate; -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - -import java.lang.reflect.*; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.*; - -/** - * Creates proxies that implement GraphObject, GraphObjectList, and their derived types. These proxies allow access - * to underlying collections and name/value property bags via strongly-typed property getters and setters. - *

- * This supports get/set properties that use primitive types, JSON types, Date, other GraphObject types, Iterable, - * Collection, List, and GraphObjectList. - */ -public final class GraphObjectWrapper { - private static final HashSet> verifiedGraphObjectClasses = new HashSet>(); - private static final SimpleDateFormat[] dateFormats = new SimpleDateFormat[] { - new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.US), - new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.US), new SimpleDateFormat("yyyy-MM-dd", Locale.US), }; - - // No objects of this type should exist. - private GraphObjectWrapper() { - } - - /** - * Creates a GraphObject proxy that provides typed access to the data in an underlying JSONObject. - * @param json the JSONObject containing the data to be exposed - * @return a GraphObject that represents the underlying data - * - * @throws com.facebook.FacebookException - * If the passed in Class is not a valid GraphObject interface - */ - public static GraphObject createGraphObject(JSONObject json) { - return createGraphObject(json, GraphObject.class); - } - - /** - * Creates a GraphObject-derived proxy that provides typed access to the data in an underlying JSONObject. - * @param json the JSONObject containing the data to be exposed - * @param graphObjectClass the GraphObject-derived type to return - * @return a graphObjectClass that represents the underlying data - * - * @throws com.facebook.FacebookException - * If the passed in Class is not a valid GraphObject interface - */ - public static T createGraphObject(JSONObject json, Class graphObjectClass) { - return createGraphObjectProxy(graphObjectClass, json); - } - - /** - * Creates a GraphObject proxy that initially contains no data. - * @return a GraphObject with no data - * - * @throws com.facebook.FacebookException - * If the passed in Class is not a valid GraphObject interface - */ - public static GraphObject createGraphObject() { - return createGraphObject(GraphObject.class); - } - - /** - * Creates a GraphObject-derived proxy that initially contains no data. - * @param graphObjectClass the GraphObject-derived type to return - * @return a graphObjectClass with no data - * - * @throws com.facebook.FacebookException - * If the passed in Class is not a valid GraphObject interface - */ - public static T createGraphObject(Class graphObjectClass) { - return createGraphObjectProxy(graphObjectClass, new JSONObject()); - } - - /** - * Determines if two GraphObjects represent the same underlying graph object, based on their IDs. - * @param a a graph object - * @param b another graph object - * @return true if both graph objects have an ID and it is the same ID, false otherwise - */ - public static boolean hasSameId(GraphObject a, GraphObject b) { - if (a == null || b == null || !a.asMap().containsKey("id") || !b.asMap().containsKey("id")) { - return false; - } - if (a.equals(b)) { - return true; - } - Object idA = a.getProperty("id"); - Object idB = b.getProperty("id"); - if (idA == null || idB == null || !(idA instanceof String) || !(idB instanceof String)) { - return false; - } - return idA.equals(idB); - } - - /** - * Creates a GraphObjectList-derived proxy that provides typed access to the data in an underlying JSONArray. - * @param array the JSONArray containing the data to be exposed - * @param graphObjectClass the GraphObject-derived type to return - * @return a graphObjectClass that represents the underlying data - * - * @throws com.facebook.FacebookException - * If the passed in Class is not a valid GraphObject interface - */ - public static GraphObjectList createGraphObjectList(JSONArray array, Class graphObjectClass) { - return new GraphObjectListImpl(array, graphObjectClass); - } - - /** - * Creates a GraphObjectList-derived proxy that initially contains no data. - * @param graphObjectClass the GraphObject-derived type to return - * @return a GraphObjectList with no data - * - * @throws com.facebook.FacebookException - * If the passed in Class is not a valid GraphObject interface - */ - public static GraphObjectList createGraphObjectList(Class graphObjectClass) { - return createGraphObjectList(new JSONArray(), graphObjectClass); - } - - private static T createGraphObjectProxy(Class graphObjectClass, JSONObject state) { - verifyCanProxyClass(graphObjectClass); - - Class[] interfaces = new Class[] { graphObjectClass }; - GraphObjectProxy graphObjectProxy = new GraphObjectProxy(state, graphObjectClass); - - @SuppressWarnings("unchecked") - T graphObject = (T) Proxy.newProxyInstance(GraphObject.class.getClassLoader(), interfaces, graphObjectProxy); - - return graphObject; - } - - private static Map createGraphObjectProxyForMap(JSONObject state) { - Class[] interfaces = new Class[]{Map.class}; - GraphObjectProxy graphObjectProxy = new GraphObjectProxy(state, Map.class); - - @SuppressWarnings("unchecked") - Map graphObject = (Map) Proxy - .newProxyInstance(GraphObject.class.getClassLoader(), interfaces, graphObjectProxy); - - return graphObject; - } - - private static synchronized boolean hasClassBeenVerified(Class graphObjectClass) { - return verifiedGraphObjectClasses.contains(graphObjectClass); - } - - private static synchronized void recordClassHasBeenVerified(Class graphObjectClass) { - verifiedGraphObjectClasses.add(graphObjectClass); - } - - private static void verifyCanProxyClass(Class graphObjectClass) { - if (hasClassBeenVerified(graphObjectClass)) { - return; - } - - if (!graphObjectClass.isInterface()) { - throw new FacebookGraphObjectException("GraphObjectWrapper can only wrap interfaces, not class: " - + graphObjectClass.getName()); - } - - Method[] methods = graphObjectClass.getMethods(); - for (Method method : methods) { - String methodName = method.getName(); - int parameterCount = method.getParameterTypes().length; - Class returnType = method.getReturnType(); - boolean hasPropertyNameOverride = method.isAnnotationPresent(PropertyName.class); - - if (method.getDeclaringClass().isAssignableFrom(GraphObject.class)) { - // Don't worry about any methods from GraphObject or one of its base classes. - continue; - } else if (parameterCount == 1 && returnType == Void.TYPE) { - if (hasPropertyNameOverride) { - // If a property override is present, it MUST be valid. We don't fallback - // to using the method name - if (!Utility.isNullOrEmpty(method.getAnnotation(PropertyName.class).value())) { - continue; - } - } else if (methodName.startsWith("set") && methodName.length() > 3) { - // Looks like a valid setter - continue; - } - } else if (parameterCount == 0 && returnType != Void.TYPE) { - if (hasPropertyNameOverride) { - // If a property override is present, it MUST be valid. We don't fallback - // to using the method name - if (!Utility.isNullOrEmpty(method.getAnnotation(PropertyName.class).value())) { - continue; - } - } else if (methodName.startsWith("get") && methodName.length() > 3) { - // Looks like a valid getter - continue; - } - } - - throw new FacebookGraphObjectException("GraphObjectWrapper can't proxy method: " + method.toString()); - } - - recordClassHasBeenVerified(graphObjectClass); - } - - // If expectedType is a generic type, expectedTypeAsParameterizedType must be provided in order to determine - // generic parameter types. - static U coerceValueToExpectedType(Object value, Class expectedType, - ParameterizedType expectedTypeAsParameterizedType) { - if (value == null) { - return null; - } - - Class valueType = value.getClass(); - if (expectedType.isAssignableFrom(valueType)) { - @SuppressWarnings("unchecked") - U result = (U) value; - return result; - } - - if (expectedType.isPrimitive()) { - // If the result is a primitive, let the runtime succeed or fail at unboxing it. - @SuppressWarnings("unchecked") - U result = (U) value; - return result; - } - - if (GraphObject.class.isAssignableFrom(expectedType)) { - @SuppressWarnings("unchecked") - Class graphObjectClass = (Class) expectedType; - - // We need a GraphObject, but we don't have one. - if (JSONObject.class.isAssignableFrom(valueType)) { - // We can wrap a JSONObject as a GraphObject. - @SuppressWarnings("unchecked") - U result = (U) createGraphObjectProxy(graphObjectClass, (JSONObject) value); - return result; - } else if (GraphObject.class.isAssignableFrom(valueType)) { - // We can cast a GraphObject-derived class to another GraphObject-derived class. - @SuppressWarnings("unchecked") - U result = (U) ((GraphObject) value).cast(graphObjectClass); - return result; - } else { - throw new FacebookGraphObjectException("Can't create GraphObject from " + valueType.getName()); - } - } else if (Iterable.class.equals(expectedType) || Collection.class.equals(expectedType) - || List.class.equals(expectedType) || GraphObjectList.class.equals(expectedType)) { - if (expectedTypeAsParameterizedType == null) { - throw new FacebookGraphObjectException("can't infer generic type of: " + expectedType.toString()); - } - - Type[] actualTypeArguments = expectedTypeAsParameterizedType.getActualTypeArguments(); - - if (actualTypeArguments == null || actualTypeArguments.length != 1 - || !(actualTypeArguments[0] instanceof Class)) { - throw new FacebookGraphObjectException( - "Expect collection properties to be of a type with exactly one generic parameter."); - } - Class collectionGenericArgument = (Class) actualTypeArguments[0]; - - if (JSONArray.class.isAssignableFrom(valueType)) { - JSONArray jsonArray = (JSONArray) value; - @SuppressWarnings("unchecked") - U result = (U) createGraphObjectList(jsonArray, collectionGenericArgument); - return result; - } else { - throw new FacebookGraphObjectException("Can't create Collection from " + valueType.getName()); - } - } else if (String.class.equals(expectedType)) { - if (Number.class.isAssignableFrom(valueType)) { - @SuppressWarnings("unchecked") - U result = (U) String.format("%d", value); - return result; - } - } else if (Date.class.equals(expectedType)) { - if (String.class.isAssignableFrom(valueType)) { - for (SimpleDateFormat format : dateFormats) { - try { - Date date = format.parse((String) value); - if (date != null) { - @SuppressWarnings("unchecked") - U result = (U) date; - return result; - } - } catch (ParseException e) { - // Keep going. - } - } - } - } - throw new FacebookGraphObjectException("Can't convert type" + valueType.getName() + " to " - + expectedType.getName()); - } - - static String convertCamelCaseToLowercaseWithUnderscores(String string) { - string = string.replaceAll("([a-z])([A-Z])", "$1_$2"); - return string.toLowerCase(); - } - - private static Object getUnderlyingJSONObject(Object obj) { - Class objClass = obj.getClass(); - if (GraphObject.class.isAssignableFrom(objClass)) { - GraphObject graphObject = (GraphObject) obj; - return graphObject.getInnerJSONObject(); - } else if (GraphObjectList.class.isAssignableFrom(objClass)) { - GraphObjectList graphObjectList = (GraphObjectList) obj; - return graphObjectList.getInnerJSONArray(); - } - return obj; - } - - private abstract static class ProxyBase implements InvocationHandler { - // Pre-loaded Method objects for the methods in java.lang.Object - private static final String EQUALS_METHOD = "equals"; - private static final String TOSTRING_METHOD = "toString"; - - protected final STATE state; - - protected ProxyBase(STATE state) { - this.state = state; - } - - // Declared to return Object just to simplify implementation of proxy helpers. - protected final Object throwUnexpectedMethodSignature(Method method) { - throw new FacebookGraphObjectException(getClass().getName() + " got an unexpected method signature: " - + method.toString()); - } - - protected final Object proxyObjectMethods(Object proxy, Method method, Object[] args) throws Throwable { - String methodName = method.getName(); - if (methodName.equals(EQUALS_METHOD)) { - Object other = args[0]; - - if (other == null) { - return false; - } - - InvocationHandler handler = Proxy.getInvocationHandler(other); - if (!(handler instanceof GraphObjectProxy)) { - return false; - } - GraphObjectProxy otherProxy = (GraphObjectProxy) handler; - return this.state.equals(otherProxy.state); - } else if (methodName.equals(TOSTRING_METHOD)) { - return toString(); - } - - // For others, just defer to the implementation object. - return method.invoke(this.state, args); - } - - } - - private final static class GraphObjectProxy extends ProxyBase { - private static final String CLEAR_METHOD = "clear"; - private static final String CONTAINSKEY_METHOD = "containsKey"; - private static final String CONTAINSVALUE_METHOD = "containsValue"; - private static final String ENTRYSET_METHOD = "entrySet"; - private static final String GET_METHOD = "get"; - private static final String ISEMPTY_METHOD = "isEmpty"; - private static final String KEYSET_METHOD = "keySet"; - private static final String PUT_METHOD = "put"; - private static final String PUTALL_METHOD = "putAll"; - private static final String REMOVE_METHOD = "remove"; - private static final String SIZE_METHOD = "size"; - private static final String VALUES_METHOD = "values"; - private static final String CAST_METHOD = "cast"; - private static final String CASTTOMAP_METHOD = "asMap"; - private static final String GETPROPERTY_METHOD = "getProperty"; - private static final String SETPROPERTY_METHOD = "setProperty"; - private static final String REMOVEPROPERTY_METHOD = "removeProperty"; - private static final String GETINNERJSONOBJECT_METHOD = "getInnerJSONObject"; - - private final Class graphObjectClass; - - public GraphObjectProxy(JSONObject state, Class graphObjectClass) { - super(state); - this.graphObjectClass = graphObjectClass; - } - - @Override - public String toString() { - return String.format("GraphObject{graphObjectClass=%s, state=%s}", graphObjectClass.getSimpleName(), state); - } - - @Override - public final Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - Class declaringClass = method.getDeclaringClass(); - - if (declaringClass == Object.class) { - return proxyObjectMethods(proxy, method, args); - } else if (declaringClass == Map.class) { - return proxyMapMethods(method, args); - } else if (declaringClass == GraphObject.class) { - return proxyGraphObjectMethods(proxy, method, args); - } else if (GraphObject.class.isAssignableFrom(declaringClass)) { - return proxyGraphObjectGettersAndSetters(method, args); - } - - return throwUnexpectedMethodSignature(method); - } - - private final Object proxyMapMethods(Method method, Object[] args) { - String methodName = method.getName(); - if (methodName.equals(CLEAR_METHOD)) { - JsonUtil.jsonObjectClear(this.state); - return null; - } else if (methodName.equals(CONTAINSKEY_METHOD)) { - return this.state.has((String) args[0]); - } else if (methodName.equals(CONTAINSVALUE_METHOD)) { - return JsonUtil.jsonObjectContainsValue(this.state, args[0]); - } else if (methodName.equals(ENTRYSET_METHOD)) { - return JsonUtil.jsonObjectEntrySet(this.state); - } else if (methodName.equals(GET_METHOD)) { - return this.state.opt((String) args[0]); - } else if (methodName.equals(ISEMPTY_METHOD)) { - return this.state.length() == 0; - } else if (methodName.equals(KEYSET_METHOD)) { - return JsonUtil.jsonObjectKeySet(this.state); - } else if (methodName.equals(PUT_METHOD)) { - return setJSONProperty(args); - } else if (methodName.equals(PUTALL_METHOD)) { - Map map = null; - if (args[0] instanceof Map) { - @SuppressWarnings("unchecked") - Map castMap = (Map) args[0]; - map = castMap; - } else if (args[0] instanceof GraphObject) { - map = ((GraphObject) args[0]).asMap(); - } - JsonUtil.jsonObjectPutAll(this.state, map); - return null; - } else if (methodName.equals(REMOVE_METHOD)) { - this.state.remove((String) args[0]); - return null; - } else if (methodName.equals(SIZE_METHOD)) { - return this.state.length(); - } else if (methodName.equals(VALUES_METHOD)) { - return JsonUtil.jsonObjectValues(this.state); - } - - return throwUnexpectedMethodSignature(method); - } - - private final Object proxyGraphObjectMethods(Object proxy, Method method, Object[] args) { - String methodName = method.getName(); - if (methodName.equals(CAST_METHOD)) { - @SuppressWarnings("unchecked") - Class graphObjectClass = (Class) args[0]; - - if (graphObjectClass != null && - graphObjectClass.isAssignableFrom(this.graphObjectClass)) { - return proxy; - } - return GraphObjectWrapper.createGraphObjectProxy(graphObjectClass, this.state); - } else if (methodName.equals(GETINNERJSONOBJECT_METHOD)) { - InvocationHandler handler = Proxy.getInvocationHandler(proxy); - GraphObjectProxy otherProxy = (GraphObjectProxy) handler; - return otherProxy.state; - } else if (methodName.equals(CASTTOMAP_METHOD)) { - return GraphObjectWrapper.createGraphObjectProxyForMap(this.state); - } else if (methodName.equals(GETPROPERTY_METHOD)) { - return state.opt((String) args[0]); - } else if (methodName.equals(SETPROPERTY_METHOD)) { - return setJSONProperty(args); - } else if (methodName.equals(REMOVEPROPERTY_METHOD)) { - this.state.remove((String) args[0]); - return null; - } - - return throwUnexpectedMethodSignature(method); - } - - private final Object proxyGraphObjectGettersAndSetters(Method method, Object[] args) throws JSONException { - String methodName = method.getName(); - int parameterCount = method.getParameterTypes().length; - PropertyName propertyNameOverride = method.getAnnotation(PropertyName.class); - - String key = propertyNameOverride != null ? propertyNameOverride.value() : - convertCamelCaseToLowercaseWithUnderscores(methodName.substring(3)); - - // If it's a get or a set on a GraphObject-derived class, we can handle it. - if (parameterCount == 0) { - // Has to be a getter. ASSUMPTION: The GraphObject-derived class has been verified - Object value = this.state.opt(key); - - Class expectedType = method.getReturnType(); - - Type genericReturnType = method.getGenericReturnType(); - ParameterizedType parameterizedReturnType = null; - if (genericReturnType instanceof ParameterizedType) { - parameterizedReturnType = (ParameterizedType) genericReturnType; - } - - value = coerceValueToExpectedType(value, expectedType, parameterizedReturnType); - - return value; - } else if (parameterCount == 1) { - // Has to be a setter. ASSUMPTION: The GraphObject-derived class has been verified - Object value = args[0]; - // If this is a wrapped object, store the underlying JSONObject instead, in order to serialize - // correctly. - if (GraphObject.class.isAssignableFrom(value.getClass())) { - value = ((GraphObject) value).getInnerJSONObject(); - } else if (GraphObjectList.class.isAssignableFrom(value.getClass())) { - value = ((GraphObjectList) value).getInnerJSONArray(); - } else if (Iterable.class.isAssignableFrom(value.getClass())) { - JSONArray jsonArray = new JSONArray(); - Iterable iterable = (Iterable) value; - for (Object o : iterable ) { - if (GraphObject.class.isAssignableFrom(o.getClass())) { - jsonArray.put(((GraphObject)o).getInnerJSONObject()); - } else { - jsonArray.put(o); - } - } - value = jsonArray; - } - this.state.putOpt(key, value); - return null; - } - - return throwUnexpectedMethodSignature(method); - } - - private Object setJSONProperty(Object[] args) { - String name = (String) args[0]; - Object property = args[1]; - Object value = getUnderlyingJSONObject(property); - try { - state.putOpt(name, value); - } catch (JSONException e) { - throw new IllegalArgumentException(e); - } - return null; - } - } - - private final static class GraphObjectListImpl extends AbstractList implements GraphObjectList { - private final JSONArray state; - private final Class itemType; - - public GraphObjectListImpl(JSONArray state, Class itemType) { - Validate.notNull(state, "state"); - Validate.notNull(itemType, "itemType"); - - this.state = state; - this.itemType = itemType; - } - - @Override - public String toString() { - return String.format("GraphObjectList{itemType=%s, state=%s}", itemType.getSimpleName(), state); - } - - @Override - public void add(int location, T object) { - // We only support adding at the end of the list, due to JSONArray restrictions. - if (location < 0) { - throw new IndexOutOfBoundsException(); - } else if (location < size()) { - throw new UnsupportedOperationException("Only adding items at the end of the list is supported."); - } - - put(location, object); - } - - @Override - public T set(int location, T object) { - checkIndex(location); - - T result = get(location); - put(location, object); - return result; - } - - @Override - public int hashCode() { - return state.hashCode(); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (getClass() != obj.getClass()) { - return false; - } - @SuppressWarnings("unchecked") - GraphObjectListImpl other = (GraphObjectListImpl) obj; - return state.equals(other.state); - } - - @SuppressWarnings("unchecked") - @Override - public T get(int location) { - checkIndex(location); - - Object value = state.opt(location); - - // Class expectedType = method.getReturnType(); - // Type genericType = method.getGenericReturnType(); - T result = (T) coerceValueToExpectedType(value, itemType, null); - - return result; - } - - @Override - public int size() { - return state.length(); - } - - @Override - public final GraphObjectList castToListOf(Class graphObjectClass) { - if (GraphObject.class.isAssignableFrom(itemType)) { - if (graphObjectClass.isAssignableFrom(itemType)) { - @SuppressWarnings("unchecked") - GraphObjectList result = (GraphObjectList)this; - return result; - } - - return createGraphObjectList(state, graphObjectClass); - } else { - throw new FacebookGraphObjectException("Can't cast GraphObjectCollection of non-GraphObject type " - + itemType); - } - } - - @Override - public final JSONArray getInnerJSONArray() { - return state; - } - - @Override - public void clear() { - throw new UnsupportedOperationException(); - } - - @Override - public boolean remove(Object o) { - throw new UnsupportedOperationException(); - } - - @Override - public boolean removeAll(Collection c) { - throw new UnsupportedOperationException(); - } - - @Override - public boolean retainAll(Collection c) { - throw new UnsupportedOperationException(); - } - - private void checkIndex(int index) { - if (index < 0 || index >= state.length()) { - throw new IndexOutOfBoundsException(); - } - } - - private void put(int index, T obj) { - Object underlyingObject = getUnderlyingJSONObject(obj); - try { - state.put(index, underlyingObject); - } catch (JSONException e) { - throw new IllegalArgumentException(e); - } - } - } -} diff --git a/facebook/src/com/facebook/model/GraphPlace.java b/facebook/src/com/facebook/model/GraphPlace.java index ebe278e932..a3ee128078 100644 --- a/facebook/src/com/facebook/model/GraphPlace.java +++ b/facebook/src/com/facebook/model/GraphPlace.java @@ -19,7 +19,7 @@ /** * Provides a strongly-typed representation of a Place as defined by the Graph API. * - * Note that this interface is intended to be used with GraphObjectWrapper + * Note that this interface is intended to be used with GraphObject.Factory * and not implemented directly. */ public interface GraphPlace extends GraphObject { diff --git a/facebook/src/com/facebook/model/GraphUser.java b/facebook/src/com/facebook/model/GraphUser.java index a6d2f2dde7..082baed857 100644 --- a/facebook/src/com/facebook/model/GraphUser.java +++ b/facebook/src/com/facebook/model/GraphUser.java @@ -19,7 +19,7 @@ /** * Provides a strongly-typed representation of a User as defined by the Graph API. * - * Note that this interface is intended to be used with GraphObjectWrapper + * Note that this interface is intended to be used with GraphObject.Factory * and not implemented directly. */ public interface GraphUser extends GraphObject { diff --git a/facebook/src/com/facebook/model/OpenGraphAction.java b/facebook/src/com/facebook/model/OpenGraphAction.java index f7f2767b32..0d31f86c5f 100644 --- a/facebook/src/com/facebook/model/OpenGraphAction.java +++ b/facebook/src/com/facebook/model/OpenGraphAction.java @@ -25,7 +25,7 @@ * Provides a strongly-typed representation of an Open Graph Action. * For more documentation of OG Actions, see: https://developers.facebook.com/docs/opengraph/actions/ * - * Note that this interface is intended to be used with GraphObjectWrapper + * Note that this interface is intended to be used with GraphObject.Factory * and not implemented directly. */ public interface OpenGraphAction extends GraphObject { diff --git a/facebook/src/com/facebook/widget/GraphObjectAdapter.java b/facebook/src/com/facebook/widget/GraphObjectAdapter.java index e2c4906aea..a1fa9c13f0 100644 --- a/facebook/src/com/facebook/widget/GraphObjectAdapter.java +++ b/facebook/src/com/facebook/widget/GraphObjectAdapter.java @@ -26,7 +26,6 @@ import com.facebook.*; import com.facebook.android.R; import com.facebook.model.GraphObject; -import com.facebook.model.GraphObjectWrapper; import org.json.JSONObject; import java.net.MalformedURLException; @@ -251,7 +250,7 @@ protected URL getPictureUrlOfGraphObject(T graphObject) { if (o instanceof String) { url = (String) o; } else if (o instanceof JSONObject) { - ItemPicture itemPicture = GraphObjectWrapper.createGraphObject((JSONObject) o).cast(ItemPicture.class); + ItemPicture itemPicture = GraphObject.Factory.create((JSONObject) o).cast(ItemPicture.class); ItemPictureData data = itemPicture.getData(); if (data != null) { url = data.getUrl(); @@ -555,7 +554,7 @@ int getPosition(String sectionKey, T graphObject) { // Now find index of this item within that section. for (T t : graphObjectsBySection.get(sectionKey)) { - if (GraphObjectWrapper.hasSameId(t, graphObject)) { + if (GraphObject.Factory.hasSameId(t, graphObject)) { return position; } position++; diff --git a/facebook/src/com/facebook/widget/WebDialog.java b/facebook/src/com/facebook/widget/WebDialog.java index a291839e37..1b9763629d 100644 --- a/facebook/src/com/facebook/widget/WebDialog.java +++ b/facebook/src/com/facebook/widget/WebDialog.java @@ -354,7 +354,7 @@ public void onPageFinished(WebView view, String url) { } } - private static class BuilderBase { + private static class BuilderBase> { private static final String APP_ID_PARAM = "app_id"; public static final String ACCESS_TOKEN = "access_token"; diff --git a/facebook/tests/src/com/facebook/FacebookActivityTestCase.java b/facebook/tests/src/com/facebook/FacebookActivityTestCase.java index 6aa0518b49..ebd34c5d8b 100644 --- a/facebook/tests/src/com/facebook/FacebookActivityTestCase.java +++ b/facebook/tests/src/com/facebook/FacebookActivityTestCase.java @@ -26,7 +26,6 @@ import android.test.ActivityInstrumentationTestCase2; import android.util.Log; import com.facebook.model.GraphObject; -import com.facebook.model.GraphObjectWrapper; import com.facebook.internal.Utility; import junit.framework.AssertionFailedError; import org.json.JSONException; @@ -315,7 +314,7 @@ protected U batchPostAndGet(Request post, Request get, C } protected GraphObject createStatusUpdate() { - GraphObject statusUpdate = GraphObjectWrapper.createGraphObject(); + GraphObject statusUpdate = GraphObject.Factory.create(); String message = String.format( "Check out my awesome new status update posted at: %s. Some chars for you: +\"[]:,", new Date()); statusUpdate.setProperty("message", message); diff --git a/facebook/tests/src/com/facebook/GraphRequestTests.java b/facebook/tests/src/com/facebook/GraphRequestTests.java index 75b5f86eb8..34456442f3 100644 --- a/facebook/tests/src/com/facebook/GraphRequestTests.java +++ b/facebook/tests/src/com/facebook/GraphRequestTests.java @@ -17,7 +17,6 @@ import android.test.suitebuilder.annotation.LargeTest; import com.facebook.model.GraphObject; -import com.facebook.model.GraphObjectWrapper; import java.util.Date; @@ -33,7 +32,7 @@ public void testCommentRoundTrip() { GraphObject createdStatus = batchCreateAndGet(session, "me/feed", status, null, GraphObject.class); String statusID = (String) createdStatus.getProperty("id"); - GraphObject comment = GraphObjectWrapper.createGraphObject(); + GraphObject comment = GraphObject.Factory.create(); final String commentMessage = "It truly is a wonderful status update."; comment.setProperty("message", commentMessage); @@ -65,7 +64,7 @@ public void testCommentRoundTrip() { public void testEventRoundTrip() { TestSession session = openTestSessionWithSharedUserAndPermissions(null, "create_event"); - GraphObject event = GraphObjectWrapper.createGraphObject(); + GraphObject event = GraphObject.Factory.create(); // Android emulators tend to not have the right date/time. To avoid issues with posting events in the past // or too far in the future, we use a constant year. This test will break in 2030, angering our robot overlords. Date startTime = new Date(130, 2, 17, 12, 34, 56); diff --git a/facebook/tests/src/com/facebook/RequestTests.java b/facebook/tests/src/com/facebook/RequestTests.java index aec330037d..b78b47cf24 100644 --- a/facebook/tests/src/com/facebook/RequestTests.java +++ b/facebook/tests/src/com/facebook/RequestTests.java @@ -48,7 +48,7 @@ public void testCreateRequest() { @MediumTest @LargeTest public void testCreatePostRequest() { - GraphObject graphObject = GraphObjectWrapper.createGraphObject(); + GraphObject graphObject = GraphObject.Factory.create(); Request request = Request.newPostRequest(null, "me/statuses", graphObject, null); assertTrue(request != null); assertEquals(HttpMethod.POST, request.getHttpMethod()); diff --git a/facebook/tests/src/com/facebook/model/GraphObjectWrapperTests.java b/facebook/tests/src/com/facebook/model/GraphObjectWrapperTests.java index fe8e1827dd..13e1d89db9 100644 --- a/facebook/tests/src/com/facebook/model/GraphObjectWrapperTests.java +++ b/facebook/tests/src/com/facebook/model/GraphObjectWrapperTests.java @@ -35,7 +35,7 @@ public final class GraphObjectWrapperTests extends AndroidTestCase { @MediumTest @LargeTest public void testCreateEmptyGraphObject() { - GraphObject graphObject = GraphObjectWrapper.createGraphObject(); + GraphObject graphObject = GraphObject.Factory.create(); assertTrue(graphObject != null); } @@ -43,7 +43,7 @@ public void testCreateEmptyGraphObject() { @MediumTest @LargeTest public void testCanTreatAsMap() { - GraphObject graphObject = GraphObjectWrapper.createGraphObject(); + GraphObject graphObject = GraphObject.Factory.create(); graphObject.setProperty("hello", "world"); assertEquals("world", (String) graphObject.asMap().get("hello")); @@ -53,7 +53,7 @@ public void testCanTreatAsMap() { @MediumTest @LargeTest public void testCanTreatAsGraphPlace() { - GraphPlace graphPlace = GraphObjectWrapper.createGraphObject(GraphPlace.class); + GraphPlace graphPlace = GraphObject.Factory.create(GraphPlace.class); graphPlace.setName("hello"); assertEquals("hello", graphPlace.getName()); @@ -63,7 +63,7 @@ public void testCanTreatAsGraphPlace() { @MediumTest @LargeTest public void testCanTreatAsGraphUser() { - GraphUser graphUser = GraphObjectWrapper.createGraphObject(GraphUser.class); + GraphUser graphUser = GraphObject.Factory.create(GraphUser.class); graphUser.setFirstName("Michael"); assertEquals("Michael", graphUser.getFirstName()); @@ -80,7 +80,7 @@ public void testCanTreatAsGraphUser() { @MediumTest @LargeTest public void testCanCastBetweenGraphObjectTypes() { - GraphObject graphObject = GraphObjectWrapper.createGraphObject(); + GraphObject graphObject = GraphObject.Factory.create(); graphObject.setProperty("first_name", "Mickey"); @@ -104,7 +104,7 @@ interface Derived extends Base { @MediumTest @LargeTest public void testCastingToSameTypeGivesSameObject() { - Base base = GraphObjectWrapper.createGraphObject(Base.class); + Base base = GraphObject.Factory.create(Base.class); Base cast = base.cast(Base.class); @@ -115,7 +115,7 @@ public void testCastingToSameTypeGivesSameObject() { @MediumTest @LargeTest public void testCastingToBaseTypeGivesSameObject() { - Derived derived = GraphObjectWrapper.createGraphObject(Derived.class); + Derived derived = GraphObject.Factory.create(Derived.class); Base cast = derived.cast(Base.class); assertTrue(derived == cast); @@ -128,10 +128,10 @@ public void testCastingToBaseTypeGivesSameObject() { @MediumTest @LargeTest public void testCanSetComplexTypes() { - GraphLocation graphLocation = GraphObjectWrapper.createGraphObject(GraphLocation.class); + GraphLocation graphLocation = GraphObject.Factory.create(GraphLocation.class); graphLocation.setCity("Seattle"); - GraphPlace graphPlace = GraphObjectWrapper.createGraphObject(GraphPlace.class); + GraphPlace graphPlace = GraphObject.Factory.create(GraphPlace.class); graphPlace.setLocation(graphLocation); assertEquals(graphLocation, graphPlace.getLocation()); @@ -150,7 +150,7 @@ public void testCanConvertFromJSON() throws JSONException { jsonPlace.put("location", jsonLocation); jsonPlace.put("name", "Eiffel Tower"); - GraphPlace graphPlace = GraphObjectWrapper.createGraphObject(jsonPlace, GraphPlace.class); + GraphPlace graphPlace = GraphObject.Factory.create(jsonPlace, GraphPlace.class); GraphLocation graphLocation = graphPlace.getLocation(); assertEquals("Paris", graphLocation.getCity()); } @@ -159,7 +159,7 @@ public void testCanConvertFromJSON() throws JSONException { @MediumTest @LargeTest public void testCanConvertFromGraphObject() throws JSONException { - GraphObject graphObject = GraphObjectWrapper.createGraphObject(); + GraphObject graphObject = GraphObject.Factory.create(); graphObject.setProperty("city", "Paris"); graphObject.setProperty("country", "France"); @@ -167,7 +167,7 @@ public void testCanConvertFromGraphObject() throws JSONException { jsonPlace.put("location", graphObject); jsonPlace.put("name", "Eiffel Tower"); - GraphPlace graphPlace = GraphObjectWrapper.createGraphObject(jsonPlace, GraphPlace.class); + GraphPlace graphPlace = GraphObject.Factory.create(jsonPlace, GraphPlace.class); GraphLocation graphLocation = graphPlace.getLocation(); assertEquals("Paris", graphLocation.getCity()); } @@ -180,7 +180,7 @@ private abstract class GraphObjectClass implements GraphObject { @LargeTest public void testCantWrapNonInterface() { try { - GraphObjectWrapper.createGraphObject(GraphObjectClass.class); + GraphObject.Factory.create(GraphObjectClass.class); fail("Expected exception"); } catch (FacebookGraphObjectException exception) { } @@ -195,7 +195,7 @@ private interface BadNoParameterMethodNameGraphObject extends GraphObject { @LargeTest public void testCantWrapBadZeroParameterMethodName() { try { - GraphObjectWrapper.createGraphObject(BadNoParameterMethodNameGraphObject.class); + GraphObject.Factory.create(BadNoParameterMethodNameGraphObject.class); fail("Expected exception"); } catch (FacebookGraphObjectException exception) { } @@ -210,7 +210,7 @@ private interface BadSingleParameterMethodNameGraphObject extends GraphObject { @LargeTest public void testCantWrapBadSingleParameterMethodName() { try { - GraphObjectWrapper.createGraphObject(BadSingleParameterMethodNameGraphObject.class); + GraphObject.Factory.create(BadSingleParameterMethodNameGraphObject.class); fail("Expected exception"); } catch (FacebookGraphObjectException exception) { } @@ -225,7 +225,7 @@ private interface BadGetterNameGraphObject extends GraphObject { @LargeTest public void testCantWrapBadGetterName() { try { - GraphObjectWrapper.createGraphObject(BadGetterNameGraphObject.class); + GraphObject.Factory.create(BadGetterNameGraphObject.class); fail("Expected exception"); } catch (FacebookGraphObjectException exception) { } @@ -240,7 +240,7 @@ private interface BadGetterParamsGraphObject extends GraphObject { @LargeTest public void testCantWrapBadGetterParams() { try { - GraphObjectWrapper.createGraphObject(BadGetterParamsGraphObject.class); + GraphObject.Factory.create(BadGetterParamsGraphObject.class); fail("Expected exception"); } catch (FacebookGraphObjectException exception) { } @@ -255,7 +255,7 @@ private interface BadGetterReturnTypeGraphObject extends GraphObject { @LargeTest public void testCantWrapBadGetterReturnType() { try { - GraphObjectWrapper.createGraphObject(BadGetterReturnTypeGraphObject.class); + GraphObject.Factory.create(BadGetterReturnTypeGraphObject.class); fail("Expected exception"); } catch (FacebookGraphObjectException exception) { } @@ -270,7 +270,7 @@ private interface BadSetterNameGraphObject extends GraphObject { @LargeTest public void testCantWrapBadSetterName() { try { - GraphObjectWrapper.createGraphObject(BadSetterNameGraphObject.class); + GraphObject.Factory.create(BadSetterNameGraphObject.class); fail("Expected exception"); } catch (FacebookGraphObjectException exception) { } @@ -285,7 +285,7 @@ private interface BadSetterParamsGraphObject extends GraphObject { @LargeTest public void testCantWrapBadSetterParams() { try { - GraphObjectWrapper.createGraphObject(BadSetterParamsGraphObject.class); + GraphObject.Factory.create(BadSetterParamsGraphObject.class); fail("Expected exception"); } catch (FacebookGraphObjectException exception) { } @@ -300,7 +300,7 @@ private interface BadSetterReturnTypeGraphObject extends GraphObject { @LargeTest public void testCantWrapBadSetterReturnType() { try { - GraphObjectWrapper.createGraphObject(BadSetterReturnTypeGraphObject.class); + GraphObject.Factory.create(BadSetterReturnTypeGraphObject.class); fail("Expected exception"); } catch (FacebookGraphObjectException exception) { } @@ -317,7 +317,7 @@ private interface BadBaseInterfaceGraphObject extends BadSetterReturnTypeGraphOb @LargeTest public void testCantWrapBadBaseInterface() { try { - GraphObjectWrapper.createGraphObject(BadBaseInterfaceGraphObject.class); + GraphObject.Factory.create(BadBaseInterfaceGraphObject.class); fail("Expected exception"); } catch (FacebookGraphObjectException exception) { } @@ -347,7 +347,7 @@ private interface GoodPropertyOverrideInterfaceGraphObject extends GraphObject { @LargeTest public void testCanOverrideGraphPropertyNames() { GoodPropertyOverrideInterfaceGraphObject graphObject = - GraphObjectWrapper.createGraphObject(GoodPropertyOverrideInterfaceGraphObject.class); + GraphObject.Factory.create(GoodPropertyOverrideInterfaceGraphObject.class); String testValue = "flu-blah"; graphObject.setDefaultName(testValue); @@ -372,7 +372,7 @@ private interface BadPropertyOverrideInterfaceGraphObject extends GraphObject { @LargeTest public void testCantWrapBadPropertyNameOverrides() { try { - GraphObjectWrapper.createGraphObject(BadPropertyOverrideInterfaceGraphObject.class); + GraphObject.Factory.create(BadPropertyOverrideInterfaceGraphObject.class); fail("Expected exception"); } catch (FacebookGraphObjectException exception) { } @@ -382,7 +382,7 @@ public void testCantWrapBadPropertyNameOverrides() { @MediumTest @LargeTest public void testObjectEquals() { - GraphObject graphObject = GraphObjectWrapper.createGraphObject(); + GraphObject graphObject = GraphObject.Factory.create(); graphObject.setProperty("aKey", "aValue"); assertTrue(graphObject.equals(graphObject)); @@ -391,7 +391,7 @@ public void testObjectEquals() { assertTrue(graphObject.equals(graphPlace)); assertTrue(graphPlace.equals(graphObject)); - GraphObject aDifferentGraphObject = GraphObjectWrapper.createGraphObject(); + GraphObject aDifferentGraphObject = GraphObject.Factory.create(); aDifferentGraphObject.setProperty("aKey", "aDifferentValue"); assertFalse(graphObject.equals(aDifferentGraphObject)); } @@ -404,7 +404,7 @@ public void testGetProperty() throws JSONException { jsonObject.put("hello", "world"); jsonObject.put("hocus", "pocus"); - GraphObject graphObject = GraphObjectWrapper.createGraphObject(jsonObject); + GraphObject graphObject = GraphObject.Factory.create(jsonObject); assertEquals("world", graphObject.getProperty("hello")); assertTrue(graphObject.getProperty("fred") == null); } @@ -414,7 +414,7 @@ public void testGetProperty() throws JSONException { @LargeTest public void testSetProperty() throws JSONException { JSONObject jsonObject = new JSONObject(); - GraphObject graphObject = GraphObjectWrapper.createGraphObject(jsonObject); + GraphObject graphObject = GraphObject.Factory.create(jsonObject); graphObject.setProperty("hello", "world"); graphObject.setProperty("don't imagine", "purple elephants"); @@ -429,7 +429,7 @@ public void testSetProperty() throws JSONException { public void testRemoveProperty() throws JSONException { JSONObject jsonObject = new JSONObject(); jsonObject.put("whirled", "peas"); - GraphObject graphObject = GraphObjectWrapper.createGraphObject(jsonObject); + GraphObject graphObject = GraphObject.Factory.create(jsonObject); graphObject.setProperty("hello", "world"); graphObject.setProperty("don't imagine", "purple elephants"); @@ -445,7 +445,7 @@ public void testMapClear() throws JSONException { JSONObject jsonObject = new JSONObject(); jsonObject.put("hello", "world"); - GraphObject graphObject = GraphObjectWrapper.createGraphObject(jsonObject); + GraphObject graphObject = GraphObject.Factory.create(jsonObject); assertEquals(1, jsonObject.length()); @@ -461,7 +461,7 @@ public void testMapContainsKey() throws JSONException { JSONObject jsonObject = new JSONObject(); jsonObject.put("hello", "world"); - GraphObject graphObject = GraphObjectWrapper.createGraphObject(jsonObject); + GraphObject graphObject = GraphObject.Factory.create(jsonObject); assertTrue(graphObject.asMap().containsKey("hello")); assertFalse(graphObject.asMap().containsKey("hocus")); @@ -474,7 +474,7 @@ public void testMapContainsValue() throws JSONException { JSONObject jsonObject = new JSONObject(); jsonObject.put("hello", "world"); - GraphObject graphObject = GraphObjectWrapper.createGraphObject(jsonObject); + GraphObject graphObject = GraphObject.Factory.create(jsonObject); assertTrue(graphObject.asMap().containsValue("world")); assertFalse(graphObject.asMap().containsValue("pocus")); @@ -488,7 +488,7 @@ public void testMapEntrySet() throws JSONException { jsonObject.put("hello", "world"); jsonObject.put("hocus", "pocus"); - GraphObject graphObject = GraphObjectWrapper.createGraphObject(jsonObject); + GraphObject graphObject = GraphObject.Factory.create(jsonObject); Set> entrySet = graphObject.asMap().entrySet(); assertEquals(2, entrySet.size()); @@ -502,7 +502,7 @@ public void testMapGet() throws JSONException { jsonObject.put("hello", "world"); jsonObject.put("hocus", "pocus"); - GraphObject graphObject = GraphObjectWrapper.createGraphObject(jsonObject); + GraphObject graphObject = GraphObject.Factory.create(jsonObject); assertEquals("world", graphObject.asMap().get("hello")); assertTrue(graphObject.getProperty("fred") == null); } @@ -511,7 +511,7 @@ public void testMapGet() throws JSONException { @MediumTest @LargeTest public void testMapGetReturnsNullForMissingProperty() throws JSONException { - GraphUser graphUser = GraphObjectWrapper.createGraphObject(GraphUser.class); + GraphUser graphUser = GraphObject.Factory.create(GraphUser.class); assertNull(graphUser.getBirthday()); } @@ -521,7 +521,7 @@ public void testMapGetReturnsNullForMissingProperty() throws JSONException { public void testMapIsEmpty() throws JSONException { JSONObject jsonObject = new JSONObject(); - GraphObject graphObject = GraphObjectWrapper.createGraphObject(jsonObject); + GraphObject graphObject = GraphObject.Factory.create(jsonObject); assertTrue(graphObject.asMap().isEmpty()); jsonObject.put("hello", "world"); @@ -537,7 +537,7 @@ public void testMapKeySet() throws JSONException { jsonObject.put("hello", "world"); jsonObject.put("hocus", "pocus"); - GraphObject graphObject = GraphObjectWrapper.createGraphObject(jsonObject); + GraphObject graphObject = GraphObject.Factory.create(jsonObject); Set keySet = graphObject.asMap().keySet(); assertEquals(2, keySet.size()); @@ -552,7 +552,7 @@ public void testMapKeySet() throws JSONException { public void testMapPut() throws JSONException { JSONObject jsonObject = new JSONObject(); - GraphObject graphObject = GraphObjectWrapper.createGraphObject(jsonObject); + GraphObject graphObject = GraphObject.Factory.create(jsonObject); graphObject.setProperty("hello", "world"); graphObject.setProperty("hocus", "pocus"); @@ -566,11 +566,11 @@ public void testMapPut() throws JSONException { public void testMapPutOfWrapperPutsJSONObject() throws JSONException { JSONObject jsonObject = new JSONObject(); - GraphObject graphObject = GraphObjectWrapper.createGraphObject(jsonObject); + GraphObject graphObject = GraphObject.Factory.create(jsonObject); graphObject.setProperty("hello", "world"); graphObject.setProperty("hocus", "pocus"); - GraphObject parentObject = GraphObjectWrapper.createGraphObject(); + GraphObject parentObject = GraphObject.Factory.create(); parentObject.setProperty("key", graphObject); JSONObject jsonParent = parentObject.getInnerJSONObject(); @@ -586,11 +586,12 @@ public void testMapPutOfWrapperPutsJSONObject() throws JSONException { public void testMapPutOfWrapperPutsJSONArray() throws JSONException { JSONArray jsonArray = new JSONArray(); - GraphObjectList graphObjectList = GraphObjectWrapper.createGraphObjectList(jsonArray, String.class); + GraphObjectList graphObjectList = GraphObject.Factory + .createList(jsonArray, String.class); graphObjectList.add("hello"); graphObjectList.add("world"); - GraphObject parentObject = GraphObjectWrapper.createGraphObject(); + GraphObject parentObject = GraphObject.Factory.create(); parentObject.setProperty("key", graphObjectList); JSONObject jsonParent = parentObject.getInnerJSONObject(); @@ -609,7 +610,7 @@ public void testMapPutAll() throws JSONException { map.put("hocus", "pocus"); JSONObject jsonObject = new JSONObject(); - GraphObject graphObject = GraphObjectWrapper.createGraphObject(jsonObject); + GraphObject graphObject = GraphObject.Factory.create(jsonObject); graphObject.asMap().putAll(map); assertEquals("pocus", jsonObject.get("hocus")); @@ -624,7 +625,7 @@ public void testMapRemove() throws JSONException { jsonObject.put("hello", "world"); jsonObject.put("hocus", "pocus"); - GraphObject graphObject = GraphObjectWrapper.createGraphObject(jsonObject); + GraphObject graphObject = GraphObject.Factory.create(jsonObject); graphObject.removeProperty("hello"); assertEquals(1, jsonObject.length()); @@ -638,7 +639,7 @@ public void testMapSize() throws JSONException { jsonObject.put("hello", "world"); jsonObject.put("hocus", "pocus"); - GraphObject graphObject = GraphObjectWrapper.createGraphObject(jsonObject); + GraphObject graphObject = GraphObject.Factory.create(jsonObject); assertEquals(2, graphObject.asMap().size()); } @@ -651,7 +652,7 @@ public void testMapValues() throws JSONException { jsonObject.put("hello", "world"); jsonObject.put("hocus", "pocus"); - GraphObject graphObject = GraphObjectWrapper.createGraphObject(jsonObject); + GraphObject graphObject = GraphObject.Factory.create(jsonObject); Collection values = graphObject.asMap().values(); @@ -667,7 +668,7 @@ public void testGetInnerJSONObject() throws JSONException { jsonObject.put("hello", "world"); jsonObject.put("hocus", "pocus"); - GraphObject graphObject = GraphObjectWrapper.createGraphObject(jsonObject); + GraphObject graphObject = GraphObject.Factory.create(jsonObject); assertEquals(jsonObject, graphObject.getInnerJSONObject()); } @@ -676,8 +677,8 @@ public void testGetInnerJSONObject() throws JSONException { @MediumTest @LargeTest public void testSettingGraphObjectProxyStoresJSONObject() throws JSONException { - GraphPlace graphPlace = GraphObjectWrapper.createGraphObject(GraphPlace.class); - GraphLocation graphLocation = GraphObjectWrapper.createGraphObject(GraphLocation.class); + GraphPlace graphPlace = GraphObject.Factory.create(GraphPlace.class); + GraphLocation graphLocation = GraphObject.Factory.create(GraphLocation.class); graphPlace.setLocation(graphLocation); @@ -700,7 +701,7 @@ private interface DateGraphObject extends GraphObject { @MediumTest @LargeTest public void testGetStringsAsDates() { - DateGraphObject dates = GraphObjectWrapper.createGraphObject(DateGraphObject.class); + DateGraphObject dates = GraphObject.Factory.create(DateGraphObject.class); dates.setProperty("date1", "2012-07-04"); dates.setProperty("date2", "2012-07-04T19:30:50"); dates.setProperty("date3", "2012-07-04T19:20:40-0400"); @@ -741,7 +742,7 @@ public void testGetStringsAsDates() { public void testCollectionAdd() throws JSONException { JSONArray array = new JSONArray(); - Collection collection = GraphObjectWrapper.createGraphObjectList(array, Integer.class); + Collection collection = GraphObject.Factory.createList(array, Integer.class); collection.add(5); assertTrue(array.length() == 1); @@ -756,7 +757,7 @@ public void testCollectionAddAll() throws JSONException { Collection collectionToAdd = Arrays.asList(5, -1); - Collection collection = GraphObjectWrapper.createGraphObjectList(array, Integer.class); + Collection collection = GraphObject.Factory.createList(array, Integer.class); collection.addAll(collectionToAdd); assertTrue(array.length() == 2); @@ -771,7 +772,7 @@ public void testCollectionContains() throws JSONException { JSONArray array = new JSONArray(); array.put(5); - Collection collection = GraphObjectWrapper.createGraphObjectList(array, Integer.class); + Collection collection = GraphObject.Factory.createList(array, Integer.class); assertTrue(collection.contains(5)); assertFalse(collection.contains(6)); } @@ -784,7 +785,7 @@ public void testCollectionContainsAll() throws JSONException { array.put(5); array.put(-1); - Collection collection = GraphObjectWrapper.createGraphObjectList(array, Integer.class); + Collection collection = GraphObject.Factory.createList(array, Integer.class); assertTrue(collection.containsAll(Arrays.asList(5))); assertTrue(collection.containsAll(Arrays.asList(5, -1))); assertFalse(collection.containsAll(Arrays.asList(5, -1, 2))); @@ -796,7 +797,7 @@ public void testCollectionContainsAll() throws JSONException { public void testCollectionIsEmpty() throws JSONException { JSONArray array = new JSONArray(); - Collection collection = GraphObjectWrapper.createGraphObjectList(array, Integer.class); + Collection collection = GraphObject.Factory.createList(array, Integer.class); assertTrue(collection.isEmpty()); array.put(5); @@ -811,7 +812,7 @@ public void testCollectionIterator() throws JSONException { array.put(5); array.put(-1); - Collection collection = GraphObjectWrapper.createGraphObjectList(array, Integer.class); + Collection collection = GraphObject.Factory.createList(array, Integer.class); Iterator iter = collection.iterator(); assertTrue(iter.hasNext()); assertTrue(iter.next() == 5); @@ -828,12 +829,12 @@ public void testCollectionIterator() throws JSONException { @MediumTest @LargeTest public void testCollectionIteratorOfGraphObject() throws JSONException { - Collection collection = GraphObjectWrapper.createGraphObjectList(GraphLocation.class); + Collection collection = GraphObject.Factory.createList(GraphLocation.class); - GraphLocation seattle = GraphObjectWrapper.createGraphObject(GraphLocation.class); + GraphLocation seattle = GraphObject.Factory.create(GraphLocation.class); seattle.setCity("Seattle"); collection.add(seattle); - GraphLocation paris = GraphObjectWrapper.createGraphObject(GraphLocation.class); + GraphLocation paris = GraphObject.Factory.create(GraphLocation.class); paris.setCity("Paris"); collection.add(paris); @@ -855,7 +856,7 @@ public void testCollectionIteratorOfGraphObject() throws JSONException { public void testCollectionSize() throws JSONException { JSONArray array = new JSONArray(); - Collection collection = GraphObjectWrapper.createGraphObjectList(array, Integer.class); + Collection collection = GraphObject.Factory.createList(array, Integer.class); assertEquals(0, collection.size()); array.put(5); @@ -867,7 +868,7 @@ public void testCollectionSize() throws JSONException { @LargeTest public void testCollectionClearThrows() throws JSONException { try { - Collection collection = GraphObjectWrapper.createGraphObjectList(Integer.class); + Collection collection = GraphObject.Factory.createList(Integer.class); collection.clear(); fail("Expected exception"); } catch (UnsupportedOperationException exception) { @@ -879,7 +880,7 @@ public void testCollectionClearThrows() throws JSONException { @LargeTest public void testCollectionRemoveThrows() throws JSONException { try { - Collection collection = GraphObjectWrapper.createGraphObjectList(Integer.class); + Collection collection = GraphObject.Factory.createList(Integer.class); collection.remove(5); fail("Expected exception"); } catch (UnsupportedOperationException exception) { @@ -891,7 +892,7 @@ public void testCollectionRemoveThrows() throws JSONException { @LargeTest public void testCollectionRemoveAllThrows() throws JSONException { try { - Collection collection = GraphObjectWrapper.createGraphObjectList(Integer.class); + Collection collection = GraphObject.Factory.createList(Integer.class); collection.removeAll(Arrays.asList()); fail("Expected exception"); } catch (UnsupportedOperationException exception) { @@ -903,7 +904,7 @@ public void testCollectionRemoveAllThrows() throws JSONException { @LargeTest public void testCollectionRetainAllThrows() throws JSONException { try { - Collection collection = GraphObjectWrapper.createGraphObjectList(Integer.class); + Collection collection = GraphObject.Factory.createList(Integer.class); collection.retainAll(Arrays.asList()); fail("Expected exception"); } catch (UnsupportedOperationException exception) { @@ -927,7 +928,7 @@ public void testObjectWrapsJSONCollection() throws JSONException { JSONObject jsonLocations = new JSONObject(); jsonLocations.put("locations", jsonArray); - Locations locations = GraphObjectWrapper.createGraphObject(jsonLocations, Locations.class); + Locations locations = GraphObject.Factory.create(jsonLocations, Locations.class); Collection locationsGraphObjectCollection = locations.getLocations(); assertTrue(locationsGraphObjectCollection != null); @@ -940,14 +941,14 @@ public void testObjectWrapsJSONCollection() throws JSONException { @MediumTest @LargeTest public void testObjectWrapsIterable() throws JSONException { - GraphUser user = GraphObjectWrapper.createGraphObject(GraphUser.class); + GraphUser user = GraphObject.Factory.create(GraphUser.class); user.setFirstName("Foo"); user.setLastName("Bar"); List users = new ArrayList(); users.add(user); - OpenGraphAction action = GraphObjectWrapper.createGraphObject(OpenGraphAction.class); + OpenGraphAction action = GraphObject.Factory.create(OpenGraphAction.class); action.setTags(users); String json = action.getInnerJSONObject().toString(); @@ -975,8 +976,9 @@ public void testCollectionWrapsJSONObject() throws JSONException { JSONArray jsonArray = new JSONArray(); jsonArray.put(jsonLocation); - Collection locationsGraphObjectCollection = GraphObjectWrapper.createGraphObjectList(jsonArray, - GraphLocation.class); + Collection locationsGraphObjectCollection = GraphObject.Factory + .createList(jsonArray, + GraphLocation.class); assertTrue(locationsGraphObjectCollection != null); GraphLocation graphLocation = locationsGraphObjectCollection.iterator().next(); @@ -989,7 +991,7 @@ public void testCollectionWrapsJSONObject() throws JSONException { @LargeTest public void testCannotCastCollectionOfNonGraphObjects() throws JSONException { try { - GraphObjectList collection = GraphObjectWrapper.createGraphObjectList(Integer.class); + GraphObjectList collection = GraphObject.Factory.createList(Integer.class); collection.castToListOf(GraphLocation.class); fail("Expected exception"); } catch (FacebookGraphObjectException exception) { @@ -1006,7 +1008,8 @@ public void testCanCastCollectionOfGraphObjects() throws JSONException { JSONArray jsonArray = new JSONArray(); jsonArray.put(jsonSeattle); - GraphObjectList collection = GraphObjectWrapper.createGraphObjectList(jsonArray, GraphObject.class); + GraphObjectList collection = GraphObject.Factory + .createList(jsonArray, GraphObject.class); GraphObjectList locationCollection = collection.castToListOf(GraphLocation.class); assertTrue(locationCollection != null); @@ -1020,7 +1023,7 @@ public void testCanCastCollectionOfGraphObjects() throws JSONException { @MediumTest @LargeTest public void testCastingCollectionToSameTypeGivesSameObject() { - GraphObjectList base = GraphObjectWrapper.createGraphObjectList(Base.class); + GraphObjectList base = GraphObject.Factory.createList(Base.class); GraphObjectList cast = base.castToListOf(Base.class); @@ -1031,7 +1034,7 @@ public void testCastingCollectionToSameTypeGivesSameObject() { @MediumTest @LargeTest public void testCastingCollectionToBaseTypeGivesSameObject() { - GraphObjectList derived = GraphObjectWrapper.createGraphObjectList(Derived.class); + GraphObjectList derived = GraphObject.Factory.createList(Derived.class); GraphObjectList cast = derived.castToListOf(Base.class); @@ -1044,7 +1047,8 @@ public void testCastingCollectionToBaseTypeGivesSameObject() { public void testCanGetInnerJSONArray() throws JSONException { JSONArray jsonArray = new JSONArray(); - GraphObjectList collection = GraphObjectWrapper.createGraphObjectList(jsonArray, GraphObject.class); + GraphObjectList collection = GraphObject.Factory + .createList(jsonArray, GraphObject.class); assertEquals(jsonArray, collection.getInnerJSONArray()); } @@ -1057,7 +1061,8 @@ public void testCanGetRandomAccess() throws JSONException { jsonArray.put("Seattle"); jsonArray.put("Menlo Park"); - GraphObjectList collection = GraphObjectWrapper.createGraphObjectList(jsonArray, String.class); + GraphObjectList collection = GraphObject.Factory + .createList(jsonArray, String.class); assertEquals("Menlo Park", collection.get(1)); } @@ -1068,7 +1073,8 @@ public void testCanGetRandomAccess() throws JSONException { public void testCanSetRandomAccess() throws JSONException { JSONArray jsonArray = new JSONArray(); - GraphObjectList collection = GraphObjectWrapper.createGraphObjectList(jsonArray, String.class); + GraphObjectList collection = GraphObject.Factory + .createList(jsonArray, String.class); collection.add("Seattle"); collection.add("Menlo Park"); @@ -1083,11 +1089,12 @@ public void testCanSetRandomAccess() throws JSONException { public void testCollectionPutOfWrapperPutsJSONObject() throws JSONException { JSONObject jsonObject = new JSONObject(); - GraphObject graphObject = GraphObjectWrapper.createGraphObject(jsonObject); + GraphObject graphObject = GraphObject.Factory.create(jsonObject); graphObject.setProperty("hello", "world"); graphObject.setProperty("hocus", "pocus"); - GraphObjectList parentList = GraphObjectWrapper.createGraphObjectList(GraphObject.class); + GraphObjectList parentList = GraphObject.Factory + .createList(GraphObject.class); parentList.add(graphObject); JSONArray jsonArray = parentList.getInnerJSONArray(); @@ -1109,8 +1116,10 @@ public void testCollectionPutOfWrapperPutsJSONObject() throws JSONException { @MediumTest @LargeTest public void testCamelCaseToLowercase() { - assertEquals("hello_world", GraphObjectWrapper.convertCamelCaseToLowercaseWithUnderscores("HelloWorld")); - assertEquals("hello_world", GraphObjectWrapper.convertCamelCaseToLowercaseWithUnderscores("helloWorld")); + assertEquals("hello_world", GraphObject.Factory + .convertCamelCaseToLowercaseWithUnderscores("HelloWorld")); + assertEquals("hello_world", GraphObject.Factory + .convertCamelCaseToLowercaseWithUnderscores("helloWorld")); } diff --git a/samples/BooleanOGSample/src/com/facebook/samples/booleanog/LogicActivity.java b/samples/BooleanOGSample/src/com/facebook/samples/booleanog/LogicActivity.java index 31d8dda108..05ba8eecd0 100644 --- a/samples/BooleanOGSample/src/com/facebook/samples/booleanog/LogicActivity.java +++ b/samples/BooleanOGSample/src/com/facebook/samples/booleanog/LogicActivity.java @@ -447,7 +447,7 @@ private void sendPendingPost() { boolean rightOperand = pendingPost.getBoolean(PENDING_POST_RIGHT); boolean result = pendingPost.getBoolean(PENDING_POST_RESULT); - LogicAction action = GraphObjectWrapper.createGraphObject(LogicAction.class); + LogicAction action = GraphObject.Factory.create(LogicAction.class); action.setResult(result); action.setTruthvalue(getTruthValueObject(leftOperand)); action.setAnothertruthvalue(getTruthValueObject(rightOperand)); @@ -480,14 +480,16 @@ private void onPostActionResponse(Response response) { private TruthValueGraphObject getTruthValueObject(boolean value) { if (value) { if (TRUE_GRAPH_OBJECT == null) { - TruthValueGraphObject object = GraphObjectWrapper.createGraphObject(TruthValueGraphObject.class); + TruthValueGraphObject object = GraphObject.Factory + .create(TruthValueGraphObject.class); object.setUrl(TRUE_GRAPH_OBJECT_URL); TRUE_GRAPH_OBJECT = object; } return TRUE_GRAPH_OBJECT; } else { if (FALSE_GRAPH_OBJECT == null) { - TruthValueGraphObject object = GraphObjectWrapper.createGraphObject(TruthValueGraphObject.class); + TruthValueGraphObject object = GraphObject.Factory + .create(TruthValueGraphObject.class); object.setUrl(FALSE_GRAPH_OBJECT_URL); FALSE_GRAPH_OBJECT = object; } diff --git a/samples/Scrumptious/src/com/facebook/scrumptious/SelectionFragment.java b/samples/Scrumptious/src/com/facebook/scrumptious/SelectionFragment.java index b11c6ca06c..1a47b340e6 100644 --- a/samples/Scrumptious/src/com/facebook/scrumptious/SelectionFragment.java +++ b/samples/Scrumptious/src/com/facebook/scrumptious/SelectionFragment.java @@ -176,7 +176,7 @@ private void handleAnnounce() { @Override protected Response doInBackground(Void... voids) { - EatAction eatAction = GraphObjectWrapper.createGraphObject(EatAction.class); + EatAction eatAction = GraphObject.Factory.create(EatAction.class); for (BaseListElement element : listElements) { element.populateOGAction(eatAction); } @@ -306,7 +306,7 @@ public void onClick(View view) { protected void populateOGAction(OpenGraphAction action) { if (foodChoiceUrl != null) { EatAction eatAction = action.cast(EatAction.class); - MealGraphObject meal = GraphObjectWrapper.createGraphObject(MealGraphObject.class); + MealGraphObject meal = GraphObject.Factory.create(MealGraphObject.class); meal.setUrl(foodChoiceUrl); eatAction.setMeal(meal); } @@ -462,7 +462,8 @@ private List restoreByteArray(byte[] bytes) { if (usersAsString != null) { List users = new ArrayList(usersAsString.size()); for (String user : usersAsString) { - GraphUser graphUser = GraphObjectWrapper.createGraphObject(new JSONObject(user), GraphUser.class); + GraphUser graphUser = GraphObject.Factory + .create(new JSONObject(user), GraphUser.class); users.add(graphUser); } return users; @@ -527,7 +528,8 @@ protected boolean restoreState(Bundle savedState) { String place = savedState.getString(PLACE_KEY); if (place != null) { try { - selectedPlace = GraphObjectWrapper.createGraphObject(new JSONObject(place), GraphPlace.class); + selectedPlace = GraphObject.Factory + .create(new JSONObject(place), GraphPlace.class); setPlaceText(); return true; } catch (JSONException e) {