将 JSON 响应解析为对象

Posted

技术标签:

【中文标题】将 JSON 响应解析为对象【英文标题】:Parse a JSON response as an object 【发布时间】:2013-09-19 10:08:20 【问题描述】:

晚上好, 我是 Web 服务的新手,我只想编写一个简单的客户端,它只从 REST 调用中获取响应。 我下载了jersey-bundle-1.17.1.jar 并将其添加到我的构建路径中,我发现了一个工作代码,它对一个url 进行REST 调用并以String 的形式返回响应。

import javax.ws.rs.core.MediaType;

import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;

public class TestJerseyClient 
    public static void main(String[] args) 
        try 
            Client client = Client.create();
            WebResource webResource = client
                    .resource("http://path/to/service");

            ClientResponse response = webResource
                    .accept(MediaType.APPLICATION_JSON)
                    .get(ClientResponse.class);

            if (response.getStatus() != 200)
                throw new RuntimeException("Failed : HTTP error code : " + response.getStatus());

            String output = response.getEntity(String.class);

            System.out.println("Output from Server .... \n");
            System.out.println(output);
         catch (Exception e) 
            e.printStackTrace();
        
    

但我不想通过字符串操作来获取我感兴趣的响应部分。

我更喜欢结构化的方法,例如使用 Object 而不是字符串 (一个JSON 对象,一个Map<K,V> 对象等...)


尝试#1 - Map<K,V>
Sep 15, 2013 2:46:13 AM com.sun.jersey.api.client.ClientResponse getEntity
SEVERE: A message body reader for Java class java.util.Map, and Java type java.util.Map<java.lang.String, java.lang.Object>, and MIME media type application/json; charset=UTF-8 was not found
Sep 15, 2013 2:46:13 AM com.sun.jersey.api.client.ClientResponse getEntity
SEVERE: The registered message body readers compatible with the MIME media type are:
application/json; charset=UTF-8 ->
  com.sun.jersey.json.impl.provider.entity.JSONJAXBElementProvider$App
  com.sun.jersey.json.impl.provider.entity.JSONRootElementProvider$App
  com.sun.jersey.json.impl.provider.entity.JSONListElementProvider$App
*/* ->
  com.sun.jersey.core.impl.provider.entity.FormProvider
  com.sun.jersey.core.impl.provider.entity.StringProvider
  com.sun.jersey.core.impl.provider.entity.ByteArrayProvider
  com.sun.jersey.core.impl.provider.entity.FileProvider
  com.sun.jersey.core.impl.provider.entity.InputStreamProvider
  com.sun.jersey.core.impl.provider.entity.DataSourceProvider
  com.sun.jersey.core.impl.provider.entity.XMLJAXBElementProvider$General
  com.sun.jersey.core.impl.provider.entity.ReaderProvider
  com.sun.jersey.core.impl.provider.entity.DocumentProvider
  com.sun.jersey.core.impl.provider.entity.SourceProvider$StreamSourceReader
  com.sun.jersey.core.impl.provider.entity.SourceProvider$SAXSourceReader
  com.sun.jersey.core.impl.provider.entity.SourceProvider$DOMSourceReader
  com.sun.jersey.json.impl.provider.entity.JSONJAXBElementProvider$General
  com.sun.jersey.core.impl.provider.entity.XMLRootElementProvider$General
  com.sun.jersey.core.impl.provider.entity.XMLListElementProvider$General
  com.sun.jersey.core.impl.provider.entity.XMLRootObjectProvider$General
  com.sun.jersey.core.impl.provider.entity.EntityHolderReader
  com.sun.jersey.json.impl.provider.entity.JSONRootElementProvider$General
  com.sun.jersey.json.impl.provider.entity.JSONListElementProvider$General

com.sun.jersey.api.client.ClientHandlerException: A message body reader for Java class java.util.Map, and Java type java.util.Map<java.lang.String, java.lang.Object>, and MIME media type application/json; charset=UTF-8 was not found
    at com.sun.jersey.api.client.ClientResponse.getEntity(ClientResponse.java:561)
    at com.sun.jersey.api.client.ClientResponse.getEntity(ClientResponse.java:535)
    at com.sun.jersey.api.client.WebResource.handle(WebResource.java:696)
    at com.sun.jersey.api.client.WebResource.access$300(WebResource.java:74)
    at com.sun.jersey.api.client.WebResource$Builder.get(WebResource.java:512)
    at rest.TestJerseyClientAdvanced.main(TestJerseyClientAdvanced.java:36)

【问题讨论】:

到目前为止我已经尝试过这个例子 (plaincode.blogspot.gr/2011/07/…) 但它给了我一个错误 ^ 该评论应该是对问题的编辑。 【参考方案1】:

我建议您使用 Jackson 来(取消)编组 JSON 响应。这可以通过以下两个步骤来完成。

步骤 1。创建一个具有与预期响应匹配的成员/对象名称的 java bean。例如,MyResponse.class

步骤 2。从客户端响应中读取实体时使用 java bean。

private static ClientConfig clientConfig = new DefaultClientConfig();
clientConfig.getFeatures().put(JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE);

ClientResponse response =  Client.create(clientConfig).
            resource(uri).accept(MediaType.APPLICATION_JSON).
            header("content-type", MediaType.APPLICATION_JSON).
            get(MY_RESPONSE.class); 
MyResponse output = response.getEntity(MyResponse.class);

【讨论】:

我无法运行它,出现错误 HTTP 状态 500 - 请求处理失败;嵌套异常是 com.sun.jersey.api.client.ClientHandlerException:Java 类的消息体阅读器。您能否通过看到此异常来解释我错过了什么。 能够解决问题ClientResponse response = Client.create(clientConfig)。资源(uri).accept(MediaType.APPLICATION_JSON)。标头(“内容类型”,MediaType.APPLICATION_JSON)。得到(MY_RESPONSE.class);从引用类型 ClientResponse 更改为 MyResponse 效果很好。 MyResponse 响应 = Client.create(clientConfig)。资源(uri).accept(MediaType.APPLICATION_JSON)。标头(“内容类型”,MediaType.APPLICATION_JSON)。得到(MyResponse.class);其中 MyResponse 是您的 POJO 类 注意:如果使用 Jersey 1 和 Maven,您需要在 pom.xml 上添加 com.sun.jersey/jersey-json 才能使用 JSONConfiguration 类。 对于 Jersey 2,使用 response.readEntity(MyResponse.class) 投射您的输出【参考方案2】:

您可以使用Genson 库。

// register genson in jersey client
ClientConfig cfg = new DefaultClientConfig(GensonJsonConverter.class);
Client client = Client.create(cfg);
WebResource webResource = client.resource("http://path/to/service");

// you can map it to a pojo, no need to have a string or map
SomePojo pojo = webResource
                .accept(MediaType.APPLICATION_JSON)
                .get(SomePojo.class);

【讨论】:

【参考方案3】:

如果您只需要从大型 JSON 响应中获取少量属性,则可以使用 Jersey 客户端和 JsonArray 或 JsonObject 实体。

String url = "http://api.goeuro.com/api/v2/position/suggest/en/";
String city = "New York";

Client client = ClientBuilder.newClient();
WebTarget webTarget = client.register(JsonProcessingFeature.class).target(url);
JsonArray jsonArray = webTarget.path(city)
    .request(MediaType.APPLICATION_JSON_TYPE).get(JsonArray.class);

for (JsonObject jsonObject : jsonArray.getValuesAs(JsonObject.class)) 
    JsonObject geoPosition = jsonObject.getJsonObject("geo_position");
    System.out.println(Arrays.asList(
        jsonObject.getString("name"), jsonObject.getString("type"),
        geoPosition.get("latitude"), geoPosition.get("longitude")));

Maven 依赖项

<dependency>
    <groupId>org.glassfish.jersey.core</groupId>
    <artifactId>jersey-client</artifactId>
    <version>2.22.1</version>
</dependency>
<dependency>
    <groupId>org.glassfish.jersey.media</groupId>
    <artifactId>jersey-media-json-processing</artifactId>
    <version>2.22.1</version>
</dependency>

【讨论】:

【参考方案4】:

就这么简单:

    ObjectMapper mapper = new ObjectMapper();
    String json = "json value";
    MyClass obj = mapper.readValue(json , MyClass .class);

【讨论】:

【参考方案5】:

查看此示例 ...单击此link 了解更多信息

// The request also includes the userip parameter which provides the end
// user's IP address. Doing so will help distinguish this legitimate
// server-side traffic from traffic which doesn't come from an end-user.
URL url = new URL(
    "https://www.websitelink.com//folderresponsedata
    + "q=Paris%20Hilton&userip=USERS-IP-ADDRESS");
URLConnection connection = url.openConnection();
connection.addRequestProperty("Referer", /* Enter the URL of your site here */);

String line;
StringBuilder builder = new StringBuilder();
BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
while((line = reader.readLine()) != null) 
 builder.append(line);


JSONObject json = new JSONObject(builder.toString());
// now have some fun with the results...

【讨论】:

以上是关于将 JSON 响应解析为对象的主要内容,如果未能解决你的问题,请参考以下文章

保存 json 响应并将其解析为 swift 对象

Swift 4 将字符串解析为 json 对象

解析json数组响应/颤动

快速解析动态键的json响应问题

使用改造将不一致的 JSON 解析为 POJO

将 JSON 响应解析为结构