|
19 | 19 | import static org.junit.Assume.*; |
20 | 20 | import static org.mockito.Mockito.*; |
21 | 21 |
|
| 22 | +import java.lang.annotation.Annotation; |
22 | 23 | import java.lang.annotation.Retention; |
23 | 24 | import java.lang.annotation.RetentionPolicy; |
24 | 25 | import java.util.Comparator; |
25 | 26 | import java.util.Iterator; |
26 | 27 | import java.util.List; |
| 28 | +import java.util.concurrent.CountDownLatch; |
| 29 | +import java.util.concurrent.atomic.AtomicBoolean; |
27 | 30 |
|
28 | 31 | import org.hamcrest.CoreMatchers; |
29 | 32 | import org.junit.Rule; |
|
34 | 37 | import org.mockito.Mockito; |
35 | 38 | import org.mockito.junit.MockitoJUnitRunner; |
36 | 39 | import org.springframework.core.annotation.AliasFor; |
| 40 | +import org.springframework.data.annotation.AccessType; |
| 41 | +import org.springframework.data.annotation.AccessType.Type; |
37 | 42 | import org.springframework.data.annotation.CreatedBy; |
38 | 43 | import org.springframework.data.annotation.CreatedDate; |
39 | 44 | import org.springframework.data.annotation.LastModifiedBy; |
| 45 | +import org.springframework.data.annotation.Persistent; |
40 | 46 | import org.springframework.data.annotation.TypeAlias; |
41 | 47 | import org.springframework.data.mapping.Alias; |
42 | 48 | import org.springframework.data.mapping.Document; |
|
49 | 55 | import org.springframework.data.mapping.context.SampleMappingContext; |
50 | 56 | import org.springframework.data.mapping.context.SamplePersistentProperty; |
51 | 57 | import org.springframework.data.util.ClassTypeInformation; |
| 58 | +import org.springframework.data.util.Version; |
52 | 59 | import org.springframework.test.util.ReflectionTestUtils; |
53 | 60 |
|
54 | 61 | /** |
@@ -276,6 +283,64 @@ public void getRequiredAnnotationThrowsException() { |
276 | 283 | assertThatThrownBy(() -> entity.getRequiredAnnotation(Document.class)).isInstanceOf(IllegalStateException.class); |
277 | 284 | } |
278 | 285 |
|
| 286 | +@Test // DATACMNS-1210 |
| 287 | +public void findAnnotationShouldBeThreadSafe() throws InterruptedException { |
| 288 | + |
| 289 | +assumeTrue("Requires Java 9", |
| 290 | +Version.parse(System.getProperty("java.version")).isGreaterThanOrEqualTo(Version.parse("9.0"))); |
| 291 | + |
| 292 | +CountDownLatch latch = new CountDownLatch(2); |
| 293 | +CountDownLatch syncLatch = new CountDownLatch(1); |
| 294 | + |
| 295 | +final AtomicBoolean failed = new AtomicBoolean(false); |
| 296 | + |
| 297 | +PersistentEntity<EntityWithAnnotation, T> entity = new BasicPersistentEntity( |
| 298 | +ClassTypeInformation.from(EntityWithAnnotation.class), null) { |
| 299 | + |
| 300 | +@Override |
| 301 | +public Annotation findAnnotation(Class annotationType) { |
| 302 | + |
| 303 | +try { |
| 304 | +syncLatch.await(); |
| 305 | +} catch (InterruptedException e) { |
| 306 | +e.printStackTrace(); |
| 307 | +} |
| 308 | + |
| 309 | +return super.findAnnotation(annotationType); |
| 310 | +} |
| 311 | +}; |
| 312 | + |
| 313 | +Runnable findAccessType = () -> { |
| 314 | + |
| 315 | +try { |
| 316 | +entity.findAnnotation(AccessType.class); |
| 317 | +} catch (Exception e) { |
| 318 | +failed.set(true); |
| 319 | +} finally { |
| 320 | +latch.countDown(); |
| 321 | +} |
| 322 | +}; |
| 323 | + |
| 324 | +Runnable findPersistent = () -> { |
| 325 | + |
| 326 | +try { |
| 327 | +entity.findAnnotation(Persistent.class); |
| 328 | +} catch (Exception e) { |
| 329 | +failed.set(true); |
| 330 | +} finally { |
| 331 | +latch.countDown(); |
| 332 | +} |
| 333 | +}; |
| 334 | + |
| 335 | +new Thread(findAccessType).start(); |
| 336 | +new Thread(findPersistent).start(); |
| 337 | + |
| 338 | +syncLatch.countDown(); |
| 339 | +latch.await(); |
| 340 | + |
| 341 | +assertThat(failed.get()).isFalse(); |
| 342 | +} |
| 343 | + |
279 | 344 | private <S> BasicPersistentEntity<S, T> createEntity(Class<S> type) { |
280 | 345 | return createEntity(type, null); |
281 | 346 | } |
@@ -315,4 +380,9 @@ public String getProperty() { |
315 | 380 | static class AliasEntityUsingComposedAnnotation {} |
316 | 381 |
|
317 | 382 | static class Subtype extends Entity {} |
| 383 | + |
| 384 | +@AccessType(Type.PROPERTY) |
| 385 | +static class EntityWithAnnotation { |
| 386 | + |
| 387 | +} |
318 | 388 | } |
0 commit comments