Java
Spring Boot
REST API
List Interface
Constructor Error

No primary or default constructor found for interface java.util.List Rest API Spring boot

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

The error No primary or default constructor found for interface java.util.List is a Jackson deserialization problem, not a Spring Boot startup problem. It usually appears when request payload mapping points at an interface or abstract type without enough type information. Once you understand where Spring delegates conversion, the fix is straightforward and repeatable.

Core Topic Sections

Why this error appears

Spring MVC uses HttpMessageConverter implementations to transform JSON into Java objects. In most Boot applications, Jackson does this conversion. Jackson can instantiate concrete classes such as ArrayList, but it cannot instantiate an interface directly unless a concrete target type is implied by the controller method signature or by annotations.

If your endpoint expects an object but receives a JSON array, or if generics are erased by a raw type, Jackson may attempt to create List itself and fail with the constructor error.

Reproduce the failure quickly

The failure can be reproduced with an intentionally incorrect contract where the controller expects a wrapper object while the client sends an array.

java
1@RestController
2@RequestMapping("/users")
3public class UserController {
4
5    @PostMapping("/bulk")
6    public ResponseEntity<String> bulkCreate(@RequestBody UserBatchRequest request) {
7        return ResponseEntity.ok("received " + request.users().size());
8    }
9}
10
11record UserBatchRequest(List<UserDto> users) {}
12record UserDto(String email, String role) {}

If the client sends this payload instead of the wrapper object, binding fails:

json
1[
2  {"email": "[email protected]", "role": "admin"},
3  {"email": "[email protected]", "role": "viewer"}
4]

Fix pattern 1: align payload and controller type

If the API should accept a bare array, declare List<UserDto> directly in the endpoint.

java
1@PostMapping("/bulk")
2public ResponseEntity<String> bulkCreate(@RequestBody List<UserDto> users) {
3    return ResponseEntity.ok("received " + users.size());
4}

If the API should accept a wrapper object, keep UserBatchRequest and require this JSON shape:

json
1{
2  "users": [
3    {"email": "[email protected]", "role": "admin"},
4    {"email": "[email protected]", "role": "viewer"}
5  ]
6}

Consistency between method signature and request body shape resolves most cases.

Fix pattern 2: avoid raw collections and ambiguous DTO fields

Raw types remove generic element information and make conversion fragile. Prefer explicit generic types in DTOs and method parameters.

java
1// avoid
2private List items;
3
4// prefer
5private List<UserDto> items;

Also avoid interface fields in request DTOs when you do not need polymorphism. A concrete ArrayList<UserDto> field is acceptable if your contract is simple and you want strict mapping behavior.

Validation and error handling

Add validation to fail with useful messages instead of a generic deserialization stack trace. @Valid and bean validation annotations improve API diagnostics.

java
1record UserDto(
2    @jakarta.validation.constraints.Email String email,
3    @jakarta.validation.constraints.NotBlank String role
4) {}
5
6@PostMapping("/bulk")
7public ResponseEntity<String> bulkCreate(@RequestBody @jakarta.validation.Valid List<UserDto> users) {
8    return ResponseEntity.ok("received " + users.size());
9}

A global exception handler can return a stable error format for clients.

java
1@RestControllerAdvice
2public class ApiErrorHandler {
3
4    @ExceptionHandler(org.springframework.http.converter.HttpMessageNotReadableException.class)
5    public ResponseEntity<String> notReadable(Exception ex) {
6        return ResponseEntity.badRequest().body("Invalid JSON payload for endpoint contract");
7    }
8}

Contract tests that prevent regression

Create integration tests for both valid and invalid payload shapes. This keeps request contracts explicit during refactors.

java
1@SpringBootTest
2@AutoConfigureMockMvc
3class BulkCreateContractTest {
4
5    @Autowired MockMvc mvc;
6
7    @Test
8    void acceptsArrayPayload() throws Exception {
9        String json = "[{"email":"a@example.com","role":"admin"}]";
10        mvc.perform(post("/users/bulk").contentType("application/json").content(json))
11            .andExpect(status().isOk());
12    }
13}

When these tests run in CI, payload drift gets caught before deployment.

Common Pitfalls

  • Sending a JSON array while the endpoint expects a wrapper object with a users property.
  • Declaring raw List types and losing element type information needed by Jackson.
  • Mixing interface fields and polymorphic payloads without explicit type metadata.
  • Ignoring validation, which hides contract mistakes behind generic deserialization errors.
  • Relying on manual testing only, instead of adding contract tests for payload shape.

Summary

  • The constructor error usually indicates JSON shape mismatch or missing concrete type information.
  • Align endpoint signatures and payload structure first, then add validation.
  • Use explicit generics in request DTOs to keep mapping deterministic.
  • Return clear error responses with a controller advice for malformed JSON.
  • Add integration tests for request contracts to avoid regressions.

Course illustration
Course illustration

All Rights Reserved.