|
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