public <T> T toJavaObject(String json, Class<T> type) {
if (isBlank(json))
if (jsonMappingErrorHandler.handleMappingError(json, type, null))
return null;
else
throw new FacebookJsonMappingException("JSON is an empty string - can't map it.");
if (json.startsWith("["))
if (jsonMappingErrorHandler.handleMappingError(json, type, null))
return null;
else
throw new FacebookJsonMappingException("JSON is an array but is being mapped as an object "
+ "- you should map it as a List instead. Offending JSON is '" + json + "'.");
try {
// Are we asked to map to JsonObject? If so, short-circuit right away.
if (type.equals(JsonObject.class))
return (T) new JsonObject(json);
List<FieldWithAnnotation<Facebook>> fieldsWithAnnotation = findFieldsWithAnnotation(type, Facebook.class);
Set<String> facebookFieldNamesWithMultipleMappings = facebookFieldNamesWithMultipleMappings(fieldsWithAnnotation);
// If there are no annotated fields, assume we're mapping to a built-in
// type. If this is actually the empty object, just return a new instance
// of the corresponding Java type.
if (fieldsWithAnnotation.size() == 0)
if (isEmptyObject(json))
return createInstance(type);
else
return toPrimitiveJavaType(json, type);
// Facebook will sometimes return the string "null".
// Check for that and bail early if we find it.
if ("null".equals(json))
return null;
// Facebook will sometimes return the string "false" to mean null.
// Check for that and bail early if we find it.
if ("false".equals(json)) {
if (logger.isLoggable(FINE))
logger.fine("Encountered 'false' from Facebook when trying to map to " + type.getSimpleName()
+ " - mapping null instead.");
return null;
}
JsonObject jsonObject = new JsonObject(json);
T instance = createInstance(type);
if (instance instanceof JsonObject)
return (T) jsonObject;
// For each Facebook-annotated field on the current Java object, pull data
// out of the JSON object and put it in the Java object
for (FieldWithAnnotation<Facebook> fieldWithAnnotation : fieldsWithAnnotation) {
String facebookFieldName = getFacebookFieldName(fieldWithAnnotation);
if (!jsonObject.has(facebookFieldName)) {
if (logger.isLoggable(FINER))
logger.finer("No JSON value present for '" + facebookFieldName + "', skipping. JSON is '" + json + "'.");
continue;
}
fieldWithAnnotation.getField().setAccessible(true);
// Set the Java field's value.
//
// If we notice that this Facebook field name is mapped more than once,
// go into a special mode where we swallow any exceptions that occur
// when mapping to the Java field. This is because Facebook will
// sometimes return data in different formats for the same field name.
// See issues 56 and 90 for examples of this behavior and discussion.
if (facebookFieldNamesWithMultipleMappings.contains(facebookFieldName)) {
try {
fieldWithAnnotation.getField()
.set(instance, toJavaType(fieldWithAnnotation, jsonObject, facebookFieldName));
} catch (FacebookJsonMappingException e) {
logMultipleMappingFailedForField(facebookFieldName, fieldWithAnnotation, json);
} catch (JsonException e) {
logMultipleMappingFailedForField(facebookFieldName, fieldWithAnnotation, json);
}
} else {
try {
fieldWithAnnotation.getField()
.set(instance, toJavaType(fieldWithAnnotation, jsonObject, facebookFieldName));
} catch (Exception e) {
if (!jsonMappingErrorHandler.handleMappingError(json, type, e))
throw e;
}
}
}
return instance;
} catch (FacebookJsonMappingException e) {
throw e;
} catch (Exception e) {
if (jsonMappingErrorHandler.handleMappingError(json, type, e))
return null;
else
throw new FacebookJsonMappingException("Unable to map JSON to Java. Offending JSON is '" + json + "'.", e);
}
}