2016-11-09 83 views
3

背景

我在弹簧引导(1.4.0.RELEASE),其不应该被连接到数据源,因此,需要已经简单REST API接受一个对象并用它以相同的方法返回另一个对象(接口类型)。这(种)不寻常的行为导致我使用RequestMethod.POST既能够有@RequestBody@ResponseBody弹簧引导 - REST方法返回接口

@RestController 
public class SomeController { 

    @RequestMapping(value = "/path", method = RequestMethod.POST) 
    public ResponseEntity<SomeInterface> someMethod(@RequestBody SomeClass obj) { 
     SomeInterface toReturn = createSomeInterface(...); 
     return new ResponseEntity<>(toReturn, HttpStatus.OK); 
    } 
} 

我也有一个Test方法:

@RunWith(SpringRunner.class) 
@SpringBootTest(classes = SomeApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) 
public class SomeControllerTests { 

    @Autowired 
    private TestRestTemplate restTemplate; 

    @Test 
    public void testSomeMethod() { 
     SomeClass toPost = createPostObj(); 
     ResponseEntity<SomeInterface> respons = this.restTemplate.postForEntity("/path", toPost, SomeInterface.class); 
     assertEquals(HttpStatus.OK, respons.getStatusCode()); 
     assertNotEquals(null, respons.getBody()); 
    } 
} 

然而,这抛出:

org.springframework.http.converter.HttpMessageNotReadableException: 
Could not read document: 
Can not construct instance of SomeInterface: 
abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information 

假设都SomeInterfaceSomeClass是财物等API的和不能改变的,这是可能做到?

注意

我已经尽力了SomeInterface包装成一个类没有成功:

public class Wrapper { 
    SomeInterface obj; 
    // getter and setter ... 
} 
+0

'SomeInterface toReturn = createSomeInterface(...);'你有SomeInterface的实现?因为你不能实例化一个java接口。 –

+0

@IssamELATIF存在一个实现'SomeInterfaceImpl',它是外部API yes的一部分。 –

回答

1

你的控制器是正确的,问题出在你的测试。

控制器方法返回一个SomeInterface实例对象,它由您正在使用的外部API中的某个未知类实现。这可能是一个POJO,或者可能包含Jackson注释,并且它会自动转换为JSON/XML而不会出现任何问题。

但是在测试中,您正在使用RestTemplate来调用您的控制器并将结果绑定到新对象。 RestTemplate需要一个类而不是接口,以便能够创建新实例并使用从JSON/XML格式的控制器接收的数据填充新实例。

如果您没有访问或知道实现该接口在您的测试中使用它的类,你可以改变它来检查包含到响应文本作为"Spring Boot documentation"解释或使用JSON assertion library如果你需要更先进的东西。

+0

'SomeInterface'有一个实现'SomeInterfaceImpl',它首先看起来有点像POJO对象(只有getter和setter)。然而,它是来自类和接口的很长一段继承,我不确定如何验证对象是否可以转换为JSON/XML格式(没有Jackson注释)。你能举出一个具体的例子来说明我怎样才能做到 - “改变它来检查文字......”_? –

0

不能构造SomeInterface的实例:抽象类型要么 需要映射到具体类型,具有自定义解串器,或 包含其他类型的信息

杰克逊抱怨传递SomeInterface.class作为参数传递给restTemplate.postForEntity方法,杰克逊不能实例化一个接口来传递实现。

你的测试应该像

@Test 
public void testSomeMethod() { 
    SomeClass toPost = createPostObj(); 
    ResponseEntity<SomeInterface> respons = this.restTemplate.postForEntity("/path", toPost, SomeInterfaceImpl.class); 
    assertEquals(HttpStatus.OK, respons.getStatusCode()); 
    assertNotEquals(null, respons.getBody()); 
} 
+0

不得不改变为'ResponseEntity respons = this.restTemplate.postForEntity(“/ path”,toPost,SomeInterfaceImpl.class);'否则我有编译错误。仍然不起作用,但新的堆栈跟踪:'org.springframework.web.client.RestClientException:无法提取响应:没有找到合适的HttpMessageConverter用于响应类型[class SomeInterfaceImpl]和内容类型[application/json; charset = UTF-8 ]'。 –

+0

你的类路径中是否有'com.fasterxml.jackson.core:jackson-databind'? –

+0

是的。我在我的pom.xml中包含'spring-starter-web',其中包含'com.fasterxml.jackson.core:jackson-databind:jar:2.8.1:compile'。 –