动态JSON结构到Java结构

我正在开发一个项目,使用JSON作为创建Java对象的配置框架。 这也是我第一个来自CF / PHP / JS等多年经验的专业Java项目……

我可以在将JSON转换为Java时找到的每个资源都基于这样的想法,即您必须首先在Java中手动构建对象,POJO,然后使用JSON填充它。

作为一名网络语言老手,我对这个想法感到窒息。 我认为编译语言的播放方式不同,但我认为这是从命令行到机器语言共享的一个原则:“如果你必须做两次以上,那就自动完成它。”

……然而,看起来主流的Java智慧似乎是:每次都是手工制作繁琐的结构,然后使用GSON / Jackson /无论如何填充刚性结构。 如果你的JSON发生了变化(它会因为JSON而改变)。

是否与Web代码思维方式平行?
1)加载JSON
2)基于JSON结构构建本机语言结构。
3)用结构中的数据填充新对象。
4)根据需要使用物体。

(正如@Thomas指出的那样,为什么这是必要的最准确的场景是返回JSON的API响应,它可能会定期不同,虽然对于高级语言来说鸭子打字通常不舒服,甚至将一切转换为字符串保存与每次重建框架相比的努力和时间{或者有一个工具可以将你的JSON从无数来源转换为可供任何其他工具使用}。同样,从牛仔语言的角度来看,这似乎是显而易见的,但对于高级别来说却是如此陌生语言人们不理解这个问题。)

我仔细阅读了上面的评论,我认为有一个非常常见的情况是,即使在编译时已知API结构, 临时 Java对象也非常有用。

让我们假设您处理的API返回一个复杂的JSON对象,您只对非常具体的属性值感兴趣。

以下面的谷歌地图API调用为例,获取地理位置详细信息:

https://maps.googleapis.com/maps/api/geocode/json?address=sunnyvale,CA

您可以查看和查看,响应结构非常复杂。 假设您只想获取latlng属性值,应该有一种更简单的方法,而不是预定义完整的相应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类代码取自jello-framework ,它可以让你做到这一点。

 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) 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) value).get(index); } else { return null; } } } else { return null; } } return value; } }