Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring Boot - REST method returning interface

Background

I've a simple REST API in Spring Boot (1.4.0.RELEASE) which should not be connected to a datasource, and as such, needs to take in an object and use it to return another object (interface type) in the same method. This (kind of) unusual behaviour led me to using RequestMethod.POST to both be able to have @RequestBody and @ResponseBody:

@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);
    } 
}

I also have a Test method:

@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());
    }
}

However, this throws:

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

Question

Assuming both SomeInterface and SomeClass are belongings to other API's and can't be changed, is this possible to accomplish?

Note

I've tried to wrap the SomeInterface into a class without success:

public class Wrapper {
    SomeInterface obj;
    // getter and setter ...
}
like image 315
Joakim Avatar asked Dec 31 '25 01:12

Joakim


1 Answers

Your controller is correct, the problem lies in your test.

The controller method returns a SomeInterface instance object, which is implemented by some unknown class in the external API you are using. It's probably a POJO or maybe contains Jackson annotations, and it is automatically converted to JSON/XML without problems.

But in the test you are using RestTemplate to call your controller and bind the result to a new object. RestTemplate needs a class, not an interface, to be able to create the new instance and populate it with the data received from your controller in JSON/XML format.

If you don't have access or know the class that implements that interface to use it in your test, you can change it to check for text contained into the response as explained in the "Spring Boot documentation" or use a JSON assertion library if you need something more advanced.

like image 189
Cèsar Avatar answered Jan 01 '26 17:01

Cèsar