REST客户端RestTemplate无法获取对象集合。

31

我使用Spring RestTemplate。我创建了一个REST服务和客户端,作为单独的应用程序进行单元测试。我有一个返回用户列表的方法和一个用于创建用户的方法:

@GET
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON,
        MediaType.TEXT_XML })
@Path("/all")
public Response getAllUsers() {
    List<User> list = dao.getAll();
    GenericEntity<List<User>> result = new GenericEntity<List<User>>(list) {
    };
    return Response.status(Status.OK).entity(result).build();
}

如果我请求在浏览器中显示所有用户,它会向我显示XML格式。这没问题。但是当我尝试使用以下代码时:

@Test
public void testGetAll() {
    List list = new RestTemplate().getForObject(URL + "all", List.class);
    System.out.println(list);
}

我得到了

WARNING: GET request for "http://localhost:8080/REST/all" resulted in 500 (Internal Server Error); invoking error handler

我试图调试这个程序。方法在运行时没有抛出异常。浏览器显示用户xml信息。 可能出了什么问题?

另外,我想知道如何从模板对象中获取状态码或消息(用于测试)?

感谢您的回答。

编辑:

我修改了我的测试方法:

@Test
public void testGetAll() {
    RestTemplate template = new RestTemplate();

    List<HttpMessageConverter<?>> messageConverters = new    ArrayList<HttpMessageConverter<?>>();
    Jaxb2RootElementHttpMessageConverter jaxbMessageConverter = new Jaxb2RootElementHttpMessageConverter();
    List<MediaType> mediaTypes = new ArrayList<MediaType>();
    mediaTypes.add(MediaType.APPLICATION_XML);
    jaxbMessageConverter.setSupportedMediaTypes(mediaTypes);
    messageConverters.add(jaxbMessageConverter);

    template.setMessageConverters(messageConverters);
    List list = template.getForObject(URL + "all",
            ArrayList.class);
    System.out.println(list);
}

我遇到了一个异常错误:

org.springframework.web.client.RestClientException: Could not extract response: no suitable HttpMessageConverter found for response type [class java.util.ArrayList] and content type [application/xml]
at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:107)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:496)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:452)
at org.springframework.web.client.RestTemplate.getForObject(RestTemplate.java:222)
at com.nixsolutions.web.service.rest.UserRESTServiceTest.testGetAll(UserRESTServiceTest.java:61)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

也许您需要指定要接收的内容类型?由于该方法生成3种不同的内容类型,哪一种将用于处理您的请求? - Admit
@Admit,我尝试做这个,但是出现了异常。我刚刚更新了我的问题并解释了一下。 - Oleksandr H
如果将 ArrayList 替换为 List,是否会有与以前相同的行为?另外一件事——也许您需要对集合进行根元素包装。例如:某些类将集合作为字段,并使用 JaxB 注解正确映射该类。 - Admit
是的,行为相同。唯一不同的是在堆栈跟踪中不是[class java.util.ArrayList],而只是List。 - Oleksandr H
4个回答

46

也许这样会更好...

RestTemplate template = new RestTemplate(true);


ResponseEntity<TblGps[]> responseEntity = restTemplate.getForEntity(urlGETList, TblGps[].class);

TblGps[]=responseEntity.getBody();

3
优秀的解决方案。在 List.class 不合适时也能使用。做得好。 - Blamkin86
你能解释一下为什么这个不起作用吗?ResponseEntity<List<Game>> gameSettings = REST_TEMPLATE.getForEntity(sourceUrl,List.class , variables); - Adelin
请查看我为此主题提供的另一个答案 - 它更详细。 - kamokaze
1
另请参阅http://forum.spring.io/forum/spring-projects/android/125835-how-to-get-a-list-myobject-via-resttemplate。 - Benny Bottema
这个解决方案的问题在于它也将所有内部列表转换为数组。 - krmanish007

7
您需要使用一个具体的List实现,例如您可以使用ArrayList,请参考以下示例:
ResponseEntity<? extends ArrayList<User>> responseEntity = restTemplate.getForEntity(restEndPointUrl, (Class<? extends ArrayList<User>>)ArrayList.class, userId);

它甚至适用于完全通用的设置:

ResponseEntity<? extends ArrayList<HashMap<String,Object>>> responseEntity = restTemplate.getForEntity(restEndPointUrl, (Class<? extends ArrayList<HashMap<String,Object>>>)ArrayList.class, parameterId);

我收到了 java.lang.ClassCastException:java.util.LinkedHashMap 无法转换为 User - Abdull
这是一种获取通用列表的方法,不需要转换为特定类。 - chrismarx

5

当您设置Jaxb2RootElementHttpMessageConverter时,您将覆盖随RestTemplate提供的默认转换器。其中一个默认转换器(我认为是字符串转换器)可以处理text/xml类型。删除整个Jaxb2RootElementHttpMessageConverter,但在预期使用ArrayList.class而不是List.class的情况下保留该部分,这将起作用:

@Test
public void testGetAll() {
    RestTemplate template = new RestTemplate();
    List list = template.getForObject(URL + "all",
        ArrayList.class);
    System.out.println(list);
}

您可能还需要添加一个accept头来选择使用text/xml而不是其他生成的类型之一:

HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.setAccept(Arrays.asList(new MediaType[] {MediaType.TEXT_XML}));

使用RestTemplateexchange(而不是getForObject):

List list = template.exchange(URL + "all", new HttpEntity<String>(requestHeaders()), ArrayList.class);

我需要在哪里定义requestHeaders,并如何将其与模板连接起来? - Oleksandr H
@OleksandrHubachov - 抱歉,我添加了另一行代码来完成那个任务。 - Avi
哦...我不知道问题出在哪里...我做了这个:HttpHeaders requestHeaders = new HttpHeaders(); requestHeaders.setAccept(Arrays .asList(new MediaType[] { MediaType.APPLICATION_XML })); ResponseEntity<ArrayList> list = template.exchange(URL
  • "all", HttpMethod.GET, new HttpEntity<MediaType>( requestHeaders), ArrayList.class); 但我仍然得到相同的异常...
- Oleksandr H
你移除了转换器的定义吗? - Avi
@Avi 我也有一个关于RestTemplate的类似问题,在这里。如果可能的话,你能帮我解决一下吗? - john

0
你可以使用 restTemplate.getForEntity()。它将返回包含所有响应信息(包括状态)的 ResponseEntity

好的。这将解决一个小问题。但我仍然无法提取用户列表。我尝试了这个:ResponseEntity<ArrayList> list = template.getForEntity(URL + "all", ArrayList.class); 但是无法提取响应:没有适合的HttpMessageConverter用于响应类型[class java.util.ArrayList]和内容类型[application/xml]。但我添加了application/xml作为媒体类型。 - Oleksandr H
看看我的回答,为什么你要使用ArrayList而不是对象数组... ResponseEntity<TblGps[]> responseEntity = restTemplate.getForEntity(urlGETList, TblGps[].class); 然后 TblGps[]=responseEntity.getBody(); - kamokaze

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接