1

I'm using spring cache with redis implementation, I have following method

@Async
@Cacheable(key = "#id")
public Future<Student> getStudent(String id){
  Student stu  = ...;
  return new AsyncResult<>(stu);
}

When I visit the method first time, the data is cached into redis in json format.

but when I visit it the second time, it occurs some error like this:

java.util.concurrent.ExecutionException: org.springframework.data.redis.serializer.SerializationException: Could not read JSON: Cannot construct instance of org.springframework.scheduling.annotation.AsyncResult (no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator)

[EDIT]

I found a workaround : new a MyAsyncReslt.java which extends AsyncResult and add the NoArgsContructor.

rellocs wood
  • 1,381
  • 4
  • 21
  • 36

1 Answers1

2

Redis Serializer uses Jackson under the hood Class Jackson2JsonRedisSerializer, the error:

Cannot construct instance of org.springframework.scheduling.annotation.AsyncResult (no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator)

Seems to be outcoming from Jackson (can't deserialize without default constructor):

com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of Type (no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator)

Ensure you have your model class Student properly structured to be compliant with Jackson Jackson - Object Serialization as it is used in AsyncResult via generics.


Edit in accordance to OP question:

I found a workaround : new a MyAsyncReslt.java which extends AsyncResult and add the NoArgsContructor.

Spring's AsyncResult seems not to be properly implemented to be serialized with Jackson (check on Github spring-projects/spring-framework: AsyncResult).

public class AsyncResult<V> implements ListenableFuture<V> {
    // ...

    public AsyncResult(@Nullable V value) {
        this(value, null);
    }

    private AsyncResult(@Nullable V value, @Nullable Throwable ex) {
        this.value = value;
        this.executionException = ex;
    }

    // Missing empty constructor to comply with Jackson requirements:
    public AsyncResult() {}

// ...

Until the issue will be patched you can extend Spring's AsyncResult and provide the required empty constructor. Freely use your custom AsyncResult in code.

Xarvalus
  • 2,873
  • 1
  • 19
  • 29
  • The error say it cannot deserialize the AsyncResult ,which is provided by spring and not under my controller – rellocs wood May 12 '19 at 11:33
  • @rellocswood `AsyncResult<>` takes `Student` as generic, that's why I think the `Student` class might have Jackson's deserialization problems. Does the `Student` comply with all the needs of Jackson library? Does changing it makes any difference in outcoming error? – Xarvalus May 12 '19 at 11:40
  • when i cache the Student directly it works, when I add AsyncResult it fails – rellocs wood May 12 '19 at 12:13
  • @rellocswood I have updated the answer with your recent discoveries and some explanation. You might consider making PR into Spring to patch the lacking functionality – Xarvalus May 13 '19 at 09:33