Uploaded image for project: 'Spring Data Commons'
  1. Spring Data Commons
  2. DATACMNS-1210

Thread-safetey issue in annotation detection in BasicPersistentEntity

    XMLWordPrintable

    Details

      Description

      I found the problem using spring-data-redis but it I think it could apply to all spring-data projects
      I was not able to file a bug in spring-data-mapping because there was no assignee.

      You can reproduce the issue easily:

      @Test
          void testThreadsafe(@Autowired MyPOJORepository repository){
              List<MyPOJO> all = new ArrayList<>();
              for(int i=0; i<10; i++){
                  MyPOJO pojo = new MyPOJO();
                  pojo.setMyProp("test"+i);
                  all.add(pojo);
              }
              all.parallelStream().forEach( p -> repository.save(p));
          }
      

      MyPOJO is a normal POJO annotated with Redis/Spring Data annotations:

      @RedisHash("myPojo")
      public class MyPOJO {
          @Id
          private String myProp;
      ... rest omitted
      

      the Repository is quite simple:

      public interface MyPOJORepository extends CrudRepository<MyPOJO, String> {}
      

      When firing up the test, I get:

      Caused by: java.util.ConcurrentModificationException
      	at java.base/java.util.HashMap.computeIfAbsent(HashMap.java:1139)
      	at org.springframework.data.mapping.model.BasicPersistentEntity.doFindAnnotation(BasicPersistentEntity.java:394)
      	at org.springframework.data.mapping.model.BasicPersistentEntity.findAnnotation(BasicPersistentEntity.java:379)
      	at org.springframework.data.redis.core.mapping.RedisMappingContext$ConfigAwareTimeToLiveAccessor.resolveDefaultTimeOut(RedisMappingContext.java:293)
      	at org.springframework.data.redis.core.mapping.RedisMappingContext$ConfigAwareTimeToLiveAccessor.getTimeToLive(RedisMappingContext.java:220)
      	at org.springframework.data.redis.core.convert.MappingRedisConverter.write(MappingRedisConverter.java:392)
      	at org.springframework.data.redis.core.convert.MappingRedisConverter.write(MappingRedisConverter.java:118)
      	at org.springframework.data.redis.core.RedisKeyValueAdapter.put(RedisKeyValueAdapter.java:206)
      	at org.springframework.data.keyvalue.core.KeyValueTemplate.lambda$update$1(KeyValueTemplate.java:204)
      	at org.springframework.data.keyvalue.core.KeyValueTemplate.execute(KeyValueTemplate.java:343)
      	... 30 more
      

      In Sourcecode you can see that in BasicPersistenceEntity:

      this.annotationCache = new HashMap<>();
      

      ... is just a simple map, no ConcurrentHashmap and no other means of making this part threadsafe.

      When I do the Test in single Thread mode there is no problem.

      Basically this means all the Spring Data Repositories are not threadsafe!

        Attachments

          Issue Links

            Activity

              People

              Assignee:
              cstrobl Christoph Strobl
              Reporter:
              proeben Philipp Röben
              Last updater:
              Mark Paluch
              Votes:
              0 Vote for this issue
              Watchers:
              1 Start watching this issue

                Dates

                Created:
                Updated:
                Resolved: