无法解析 RestTemplate 收到的 JSON 响应

Cannot Parse a JSON response that is received by RestTemplate

我需要解析从 Web 服务收到的 JSON 响应,但我收到以下错误消息,我对此感到困惑。我在没有 Results class 的情况下尝试过也无济于事。任何帮助将不胜感激。

The request sent by the client was syntactically incorrect.

代码

RestTemplate restTemplate = new RestTemplate();
restTemplate.getMessageConverters().add(new 
                                        MappingJackson2HttpMessageConverter());
        ResponseEntity<Results> responseEntity = restTemplate
                .getForEntity(
                        "http://primesport.sieenasoftware.com/QryApi
                         /GetEvents?
                         username=username&
                         password=password&
                         userid=23",
                         Results.class);
        System.err.println(">>" + responseEntity.getBody().getEvents().size());

结果

public class Results {
    private List<Events> events;
    getter and setter
}

事件

   public class Event {
       private long eventId;
       private String name;
       private String subTitle;
       private String description;
       private String localDate;
       private String localDateFrom;
       private String imageUrl;
       private int venueId;
       private String venue;
       private int availableTickets;
       private long performerId;
       private String performer;
       private String performerType;
       private int subcategoryId;
       private String urlCategoryName;
       private String metaTitle;
       private String metaDescription;
       private String primeSportUrl;
       private String sectionWiseView;
       private String venueCity;
       private String venueState;
       private String snippetDate;
       private int eiProductionId;
       private boolean requireBillingAsShipping;
    public long getEventId() {
        return eventId;
    }
    public void setEventId(long eventId) {
        this.eventId = eventId;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getSubTitle() {
        return subTitle;
    }
    public void setSubTitle(String subTitle) {
        this.subTitle = subTitle;
    }
    public String getDescription() {
        return description;
    }
    public void setDescription(String description) {
        this.description = description;
    }
    public String getLocalDate() {
        return localDate;
    }
    public void setLocalDate(String localDate) {
        this.localDate = localDate;
    }
    public String getLocalDateFrom() {
        return localDateFrom;
    }
    public void setLocalDateFrom(String localDateFrom) {
        this.localDateFrom = localDateFrom;
    }
    public String getImageUrl() {
        return imageUrl;
    }
    public void setImageUrl(String imageUrl) {
        this.imageUrl = imageUrl;
    }
    public int getVenueId() {
        return venueId;
    }
    public void setVenueId(int venueId) {
        this.venueId = venueId;
    }
    public String getVenue() {
        return venue;
    }
    public void setVenue(String venue) {
        this.venue = venue;
    }
    public int getAvailableTickets() {
        return availableTickets;
    }
    public void setAvailableTickets(int availableTickets) {
        this.availableTickets = availableTickets;
    }
    public long getPerformerId() {
        return performerId;
    }
    public void setPerformerId(long performerId) {
        this.performerId = performerId;
    }
    public String getPerformer() {
        return performer;
    }
    public void setPerformer(String performer) {
        this.performer = performer;
    }
    public String getPerformerType() {
        return performerType;
    }
    public void setPerformerType(String performerType) {
        this.performerType = performerType;
    }
    public int getSubcategoryId() {
        return subcategoryId;
    }
    public void setSubcategoryId(int subcategoryId) {
        this.subcategoryId = subcategoryId;
    }
    public String getUrlCategoryName() {
        return urlCategoryName;
    }
    public void setUrlCategoryName(String urlCategoryName) {
        this.urlCategoryName = urlCategoryName;
    }
    public String getMetaTitle() {
        return metaTitle;
    }
    public void setMetaTitle(String metaTitle) {
        this.metaTitle = metaTitle;
    }
    public String getMetaDescription() {
        return metaDescription;
    }
    public void setMetaDescription(String metaDescription) {
        this.metaDescription = metaDescription;
    }
    public String getPrimeSportUrl() {
        return primeSportUrl;
    }
    public void setPrimeSportUrl(String primeSportUrl) {
        this.primeSportUrl = primeSportUrl;
    }
    public String getSectionWiseView() {
        return sectionWiseView;
    }
    public void setSectionWiseView(String sectionWiseView) {
        this.sectionWiseView = sectionWiseView;
    }
    public String getVenueCity() {
        return venueCity;
    }
    public void setVenueCity(String venueCity) {
        this.venueCity = venueCity;
    }
    public String getVenueState() {
        return venueState;
    }
    public void setVenueState(String venueState) {
        this.venueState = venueState;
    }
    public String getSnippetDate() {
        return snippetDate;
    }
    public void setSnippetDate(String snippetDate) {
        this.snippetDate = snippetDate;
    }
    public int getEiProductionId() {
        return eiProductionId;
    }
    public void setEiProductionId(int eiProductionId) {
        this.eiProductionId = eiProductionId;
    }
    public boolean isRequireBillingAsShipping() {
        return requireBillingAsShipping;
    }
    public void setRequireBillingAsShipping(boolean requireBillingAsShipping) {
        this.requireBillingAsShipping = requireBillingAsShipping;
    }

}

部分响应

[{
"EventId":1000250537,
"Name":"US Open Golf",
"SubTitle":null,
"Description":"US Open Golf Tickets",
"Date":"\/Date(1434873560000)\/",
"LocalDate":"6/20/2015 11:59 PM",
"LocalDateFrom":null,
"ImageUrl":null,
"VenueId":146566,
"Venue":"Chambers Bay Golf Course",
"AvailableTickets":33,
"PerformerId":151551,
"Performer":"US Open Golf",
"PerformerType":"Golf",
"SubcategoryId":55,
"UrlCategoryName":"Sports",
"MetaTitle":null,
"MetaDescription":null,
"PrimeSportUrl":"http://primesport.sieenasoftware.com/e/sports/us-open-golf/chambers-bay-golf-course/",
"SectionWiseView":null,
"VenueCity":"UNIVERSITY PLACE",
"VenueState":"WA",
"SnippetDate":null,
"EIProductionId":99985,
"RequireBillingAsShipping":false},
{
"EventId":1000253479,
"Name":"Womens College World Series",
"SubTitle":null,
"Description": .....

更新

我知道 JAXB 可用于 JSON 和 XML,我正在尝试使用它看看是否有助于解决问题。

更新

代码返回以下异常:

    org.springframework.http.converter.HttpMessageNotReadableException: Could not read JSON: Can not deserialize instance of com.myproject.myevent.Results out of START_ARRAY token
 at [Source: java.io.PushbackInputStream@dedcd10; line: 1, column: 1]; nested exception is com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of com.myproject.myevent.Results out of START_ARRAY token
 at [Source: java.io.PushbackInputStream@dedcd10; line: 1, column: 1]
    at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:208)
    at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.read(AbstractJackson2HttpMessageConverter.java:200)
    at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:97)
    at org.springframework.web.client.RestTemplate$ResponseEntityResponseExtractor.extractData(RestTemplate.java:809)
    at org.springframework.web.client.RestTemplate$ResponseEntityResponseExtractor.extractData(RestTemplate.java:793)
    at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:576)
    at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:529)
    at org.springframework.web.client.RestTemplate.getForEntity(RestTemplate.java:261)
    at com.myproject.service.TicketSeviceImpl.primeSport(TicketSeviceImpl.java:217)
    at com.myproject.service.TicketSeviceImpl.findTicket(TicketSeviceImpl.java:45)
    at com.myproject.web.TicketController.findTicket(TicketController.java:29)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)

更新

以下代码 returns

代码

try {
            System.err.println(">>> primeSport");
            RestTemplate restTemplate = new RestTemplate();
            restTemplate.getMessageConverters().add(
                    new MappingJackson2HttpMessageConverter());
            ResponseEntity<Event[]> responseEntity = restTemplate
                    .getForEntity(
                            "http://primesport.sieenasoftware.com/QryApi/GetEvents?username=username&password=password&userid=23",
                            Event[].class);
            System.err.println(">>" + responseEntity.getBody().length);
            System.err.println(">>" + responseEntity.getBody()[0].getEventId());
            System.err.println(">>" + responseEntity.getBody()[1].getEventId());
        } catch (Exception e) {
            e.printStackTrace();
        }

输出

>1532
>0
>0

如果您使用的是 Maven,您可以尝试导入 Jackson Jar 或在 pom.xml 中添加依赖项。

ObjectMapper mapper = new ObjectMapper();
      try
      {
         mapper.writeValue(new File("c://temp/employee.json"), Results);
      }

您能否尝试以下方法,看看是否有帮助:

ResponseEntity<Events[]> responseEntity = restTemplate
            .getForEntity(
                    "http://primesport.sieenasoftware.com/QryApi
                     /GetEvents?
                     username=username&
                     password=password&
                     userid=23",
                     Events[].class);
System.err.println(">>" + responseEntity.getBody().length);

要将字段映射到 JSON 成员,您可以使用 Jackson 注释 JSONProperty("EventId") 可用于 eventId 字段。其他人也一样。

@JsonProperty("EventId")
private long eventId;
@JsonProperty("Name")
private String name;

根据 json 格式,您只需使用事件 class 而不是结果 class。 或者将 JSON 结果更改为:

["events": {
"EventId":1000250537,
"Name":"US Open Golf",
"SubTitle":null,
"Description":"US Open Golf Tickets",
"Date":"\/Date(1434873560000)\/",
"LocalDate":"6/20/2015 11:59 PM",
"LocalDateFrom":null,
"ImageUrl":null,
"VenueId":146566,
"Venue":"Chambers Bay Golf Course",
"AvailableTickets":33,
"PerformerId":151551,
"Performer":"US Open Golf",
"PerformerType":"Golf",
"SubcategoryId":55,
"UrlCategoryName":"Sports",
"MetaTitle":null,
"MetaDescription":null,
"PrimeSportUrl":"http://primesport.sieenasoftware.com/e/sports/us-open-golf/chambers-bay-golf-course/",
"SectionWiseView":null,
"VenueCity":"UNIVERSITY PLACE",
"VenueState":"WA",
"SnippetDate":null,
"EIProductionId":99985,
"RequireBillingAsShipping":false},
{
"EventId":1000253479,
"Name":"Womens College World Series",
"SubTitle":null,
"Description": .....

您是否尝试查看生成的确切请求?假设在 fiddler/charles?

这样的代理软件中

有时我遇到过,在请求真正到达线路(或到达服务器端点)之前,框架会添加额外的结构(编码等)。

试试这个,创建请求。甚至 RestTemplate 的文档也建议避免对 URL 进行双重编码。在 IDE.

中查看时可能不是很明显
String url = "http://primesport.sieenasoftware.com/QryApi/GetEvents?";
MultiValueMap<String, String> params = new LinkedMultiValueMap<String, String>();
params.add("username", "username");
params.add("password", "password");
params.add("userid", "23");

UriComponents uriComponents = UriComponentsBuilder.fromHttpUrl(url).queryParams(params).build();
System.out.println(uriComponents.toUri());

请告诉我结果如何。

此外,如果您找不到设置 fiddler 代理的步骤,请告诉我们。在编写服务客户端代码时,它是一个非常方便的工具。