javaspring-bootspring-data-redis

unable to cast body as String from ResponseEntity


In my Spring Boot environment I was testing some API. From Service I am returning ResponseEntity.

However when I try to collect its body in controller class, I am getting exception.

Service class method:

@Service
public class RedisDemo {
    private final RedisTemplate<String, String> redisTemplate;
    @Autowired
    public RedisDemo(RedisTemplate<String, String> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }
    public Object executeCommand(String command, byte[]... parts) {
        return redisTemplate.execute(connection ->
             connection.execute(command, parts),
             true
        );
    }
    public ResponseEntity<?> test(){
            Object object = executeCommand(
                       "HMGET", 
                       "students".getBytes(), 
                       "andrew".getBytes()
                    );
            ArrayList list = (ArrayList) object;
            return new ResponseEntity<>(list.get(0),HttpStatus.OK);
    
        }

Controller class method:

@GetMapping("/test")
public ResponseEntity<?> test(){
     ResponseEntity<?> test = redisDemo.test();
    //String body = (String)test.getBody();
    //System.out.println(body);      
    return new ResponseEntity<>(test.getBody(),HttpStatus.OK);
}

I am able to get response in postman as

andrew;wilson;abcSchool;900

enter image description here

However, in order to get response body, if I uncomment the String body line in controller. I am getting below exception :

java.lang.ClassCastException: class [B cannot be cast to class java.lang.String ([B and java.lang.String are in module java.base of loader 'bootstrap')
    at com.self.student.controller.MainController.test(MainController.java:113) ~[classes/:na]

enter image description here

How can I get String response inline as responseEntity.getBody() so that I can do some logic. I am getting HMGET response from redis server

Do I have to use Jackson library internally, or using ObjectMapper. How to use any of them if there can be a solution using them.


Solution

  • I think you're wondering,

    public ResponseEntity<?> test() {
        ResponseEntity<?> test = redisDemo.test();
        return new ResponseEntity<>(test.getBody(), HttpStatus.OK);
    }
    

    Why does this code work and return correct response? -> Well, it's because of this line:

    return new ResponseEntity<>(test.getBody(), HttpStatus.OK);
    

    Actually, this code doesn’t throw any errors when running standalone because it just forwards test.getBody() (which is a byte[]) without any type casting. Spring takes care of it like this:


    About Your Error:

    java.lang.ClassCastException: class [B cannot be cast to class java.lang.String
    

    This happens because the data returned from Redis (via redisTemplate.execute) is actually a byte[] ([B in Java), not a String.

    Why Does This Happen?

    list.get(0) is a byte[], not a String.

    When you try to cast test.getBody() to String in your controller, Java throws an error because you can't directly cast byte[] to String.

    Solution: Convert byte[] to String Before Returning It

    public ResponseEntity<?> test() {
        ...
        
        // Convert byte[] to String
        String result = new String((byte[]) list.get(0), StandardCharsets.UTF_8);
        
        return new ResponseEntity<>(result, HttpStatus.OK);
    }
    

    Final Output

    Now, when you call the API using Postman, you'll still get: "andrew;wilson;abcSchool;900"

    But this time, your controller is handling it as a proper String