我仔细阅读了上面的评论,我认为有一个非常常见的情况,ad hoc即使 API 结构在编译时已知,Java 对象也将非常有用。
假设您处理的 API 返回一个复杂的 JSON 对象,您只对其中非常具体的属性值感兴趣。
以以下 google 地图 API 调用为例,该调用可获取给定地址的地理详细信息:
https://maps.googleapis.com/maps/api/geocode/json?address=sunnyvale,CA
正如您所看到的,响应结构非常复杂。假设您只想获得lat
and lng
属性值,应该有一种更简单的方法,而不是预先定义完整的相应Java类。
所以,是的,如果您不想使用强类型的预定义 Java 类,您将需要使用原始对象类型和映射。更具体地说,是一个 StringMap。
现在我终于可以给出一个解决方案:
理想情况下,您希望使用与 JS 中相同的本机表示法来访问属性。像这样的事情:
String url = "https://maps.googleapis.com/maps/api/geocode/json?address=" + address;
String responseStr = fetch(url);
JsonHelper response = JsonHelper.forString(responseStr);
String status = (String) response.getValue("status");
if(status != null && status.equals("OK")) {
lat = (Double) response.getValue("results[0].geometry.location.lat");
lng = (Double) response.getValue("results[0].geometry.location.lng");
}
下列JsonHelper
类代码取自果冻框架它可以让你做到这一点。
package jello.common;
import java.util.List;
import com.google.gson.Gson;
import java.util.AbstractMap;
public class JsonHelper {
private Object json;
public JsonHelper(String jsonString) {
Gson g = new Gson();
json = g.fromJson(jsonString, Object.class);
}
public static JsonHelper forString(String jsonString) {
return new JsonHelper(jsonString);
}
@SuppressWarnings("unchecked")
public Object getValue(String path) {
Object value = json;
String [] elements = path.split("\\.");
for(String element : elements) {
String ename = element.split("\\[")[0];
if(AbstractMap.class.isAssignableFrom(value.getClass())) {
value = ( (AbstractMap<String, Object>) value).get(ename);
if(element.contains("[")) {
if(List.class.isAssignableFrom(value.getClass())) {
Integer index = Integer.valueOf(element.substring(element.indexOf("[")+1, element.indexOf("]")) );
value = ((List<Object>) value).get(index);
}
else {
return null;
}
}
}
else {
return null;
}
}
return value;
}
}