Common Issues and Solutions for Returning JSON Objects in Spring Boot

Nov 07, 2025 · Programming · 11 views · 7.8

Keywords: Spring Boot | JSON Serialization | REST API | Jackson | @RestController

Abstract: This article provides an in-depth analysis of the 'No converter found' exception encountered when returning JSON objects in Spring Boot applications. By comparing different JSON library usage patterns, it explains the working mechanism of Jackson's automatic serialization and offers practical code examples using POJO, Map, and ResponseEntity solutions. The paper also explores the underlying mechanisms of @RestController annotation and best practices to help developers avoid common configuration errors.

Problem Background and Exception Analysis

During Spring Boot application development, developers frequently encounter JSON serialization-related configuration issues. A typical scenario occurs when using org.json.JSONObject as the return type of a REST controller, resulting in the system throwing java.lang.IllegalArgumentException: No converter found for return value of type: class org.json.JSONObject exception.

The root cause of this exception lies in Spring Boot's default use of the Jackson library for JSON serialization, which cannot directly handle objects of type org.json.JSONObject. Spring Boot's auto-configuration mechanism detects the @RestController annotation and attempts to use configured HTTP message converters to process return values.

JSON Processing Mechanism in Spring Boot

Spring Boot automatically includes the Jackson library through the spring-boot-starter-web dependency, which handles object serialization and deserialization. When a method returns an object, Spring follows this processing flow:

  1. Detect method return type
  2. Find appropriate HTTP message converters
  3. Use the found converter to transform the object into HTTP response body

The @RestController annotation is essentially a combination of @Controller and @ResponseBody. This means all methods in the controller automatically apply @ResponseBody semantics, where return values are written directly to the HTTP response body rather than being resolved as view names.

Solution 1: Using POJO Objects

The most recommended approach is using Plain Old Java Objects (POJO) as return values. Jackson can automatically serialize POJO objects with appropriate getter methods.

@RestController
@RequestMapping("/api")
public class HelloController {
    
    @GetMapping("/hello")
    public HelloResponse sayHello() {
        return new HelloResponse("bb");
    }
    
    public static class HelloResponse {
        private String aa;
        
        public HelloResponse(String aa) {
            this.aa = aa;
        }
        
        public String getAa() {
            return aa;
        }
        
        public void setAa(String aa) {
            this.aa = aa;
        }
    }
}

This approach offers benefits of type safety, easy testing, and maintainability. Jackson automatically serializes the object into JSON format: {"aa":"bb"}.

Solution 2: Using Map Structures

For scenarios requiring dynamic JSON structure construction, Map can be used as the return type.

@GetMapping("/hello")
public Map<String, Object> sayHello() {
    Map<String, Object> response = new HashMap<>();
    response.put("aa", "bb");
    response.put("timestamp", System.currentTimeMillis());
    return response;
}

This method provides high flexibility, suitable for returning data with non-fixed structures. Jackson can properly handle serialization of Map types.

Solution 3: Using Jackson's ObjectNode

For more complex JSON operations, Jackson's ObjectNode can be used directly.

@RestController
@RequestMapping("/api")
public class HelloController {
    
    @Autowired
    private ObjectMapper objectMapper;
    
    @GetMapping("/hello")
    public ObjectNode sayHello() {
        ObjectNode node = objectMapper.createObjectNode();
        node.put("aa", "bb");
        node.put("number", 42);
        node.put("active", true);
        return node;
    }
}

This approach offers the most comprehensive JSON operation capabilities, supporting complex structures like nested objects and arrays.

Solution 4: Using ResponseEntity

For scenarios requiring control over HTTP status codes and response headers, ResponseEntity can be used.

@GetMapping(path = "/hello", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Object> sayHello() {
    Map<String, String> response = new HashMap<>();
    response.put("aa", "bb");
    return new ResponseEntity<>(response, HttpStatus.OK);
}

This method allows precise control over various aspects of HTTP responses, including status codes, response headers, and content types.

Dependency Configuration Verification

Ensure the project's pom.xml file contains necessary dependencies:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

This dependency automatically includes Jackson-related libraries, including jackson-databind, jackson-core, and jackson-annotations.

Best Practice Recommendations

Based on practical development experience, we recommend the following best practices:

Conclusion

Spring Boot provides powerful JSON serialization support, but requires proper understanding of its working mechanisms. By using appropriate return types and following best practices, common configuration issues can be avoided, enabling the construction of stable and reliable REST APIs. Remember, Spring Boot's design philosophy favors convention over configuration, and understanding these conventions can significantly improve development efficiency.

Copyright Notice: All rights in this article are reserved by the operators of DevGex. Reasonable sharing and citation are welcome; any reproduction, excerpting, or re-publication without prior permission is prohibited.