Skip to content

Commit b483cbc

Browse files
committed
DATACMNS-179 - Defer adding initial entity set to AbstractMappingContext.
So far the domain classes to be added to the mapping context initially were added in afterPropertiesSet() of InitializingBean. This had the drawback that although the MappingContext is already set up properly the actual listeners of the events fired (e.g. index creating ones) might not have been set up properly. We list to the ContextRefreshedEvent indicating the entire ApplicationContext being set up completely. Thus all infrastructure components are set up properly and the timing issues doesn't exist anymore.
1 parent f2bc789 commit b483cbc

File tree

4 files changed

+83
-10
lines changed

4 files changed

+83
-10
lines changed

spring-data-commons-core/src/main/java/org/springframework/data/mapping/context/AbstractMappingContext.java

Lines changed: 42 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2011 by the original author(s).
2+
* Copyright 2011-2012 by the original author(s).
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -34,9 +34,14 @@
3434
import java.util.concurrent.locks.Lock;
3535
import java.util.concurrent.locks.ReentrantReadWriteLock;
3636

37+
import org.springframework.beans.BeansException;
3738
import org.springframework.beans.factory.InitializingBean;
39+
import org.springframework.context.ApplicationContext;
40+
import org.springframework.context.ApplicationContextAware;
3841
import org.springframework.context.ApplicationEventPublisher;
3942
import org.springframework.context.ApplicationEventPublisherAware;
43+
import org.springframework.context.ApplicationListener;
44+
import org.springframework.context.event.ContextRefreshedEvent;
4045
import org.springframework.data.mapping.PersistentEntity;
4146
import org.springframework.data.mapping.PersistentProperty;
4247
import org.springframework.data.mapping.PropertyPath;
@@ -63,14 +68,16 @@
6368
* @author Oliver Gierke
6469
*/
6570
public abstract class AbstractMappingContext<E extends MutablePersistentEntity<?, P>, P extends PersistentProperty<P>>
66-
implements MappingContext<E, P>, InitializingBean, ApplicationEventPublisherAware {
71+
implements MappingContext<E, P>, InitializingBean, ApplicationEventPublisherAware, ApplicationContextAware,
72+
ApplicationListener<ContextRefreshedEvent> {
6773

6874
private static final Set<String> UNMAPPED_FIELDS = new HashSet<String>(Arrays.asList("class", "this$0"));
6975

7076
private final ConcurrentMap<TypeInformation<?>, E> persistentEntities = new ConcurrentHashMap<TypeInformation<?>, E>();
7177
private final ConcurrentMap<E, List<Validator>> validators = new ConcurrentHashMap<E, List<Validator>>();
7278

7379
private ApplicationEventPublisher applicationEventPublisher;
80+
private ApplicationContext applicationContext;
7481
private Set<? extends Class<?>> initialEntitySet = new HashSet<Class<?>>();
7582
private boolean strict = false;
7683
private SimpleTypeHolder simpleTypeHolder = new SimpleTypeHolder();
@@ -79,14 +86,25 @@ public abstract class AbstractMappingContext<E extends MutablePersistentEntity<?
7986
private final Lock read = lock.readLock();
8087
private final Lock write = lock.writeLock();
8188

82-
/*
83-
* (non-Javadoc)
89+
/**
90+
* Use {@link #setApplicationContext(ApplicationContext)} instead.
91+
*
92+
* @see #setApplicationContext(ApplicationContext)
8493
* @see org.springframework.context.ApplicationEventPublisherAware#setApplicationEventPublisher(org.springframework.context.ApplicationEventPublisher)
8594
*/
95+
@Deprecated
8696
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
8797
this.applicationEventPublisher = applicationEventPublisher;
8898
}
8999

100+
/*
101+
* (non-Javadoc)
102+
* @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)
103+
*/
104+
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
105+
this.applicationContext = applicationContext;
106+
}
107+
90108
/**
91109
* Sets the {@link Set} of types to populate the context initially.
92110
*
@@ -321,11 +339,29 @@ private TypeInformation<?> getComponentTypeRecursively(TypeInformation<?> typeIn
321339
protected abstract P createPersistentProperty(Field field, PropertyDescriptor descriptor, E owner,
322340
SimpleTypeHolder simpleTypeHolder);
323341

324-
/*
325-
* (non-Javadoc)
342+
/**
343+
* Initial entity population is now done on receiving the {@link ContextRefreshedEvent}. If implementations still need
344+
* the {@link InitializingBean} hook implement the interface yourself. Assume not entities being added at invocation
345+
* time yet.
346+
*
347+
* @see #onApplicationEvent(ContextRefreshedEvent)
326348
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
327349
*/
350+
@Deprecated
328351
public void afterPropertiesSet() {
352+
353+
}
354+
355+
/*
356+
* (non-Javadoc)
357+
* @see org.springframework.context.ApplicationListener#onApplicationEvent(org.springframework.context.ApplicationEvent)
358+
*/
359+
public void onApplicationEvent(ContextRefreshedEvent event) {
360+
361+
if (!event.getApplicationContext().equals(applicationContext)) {
362+
return;
363+
}
364+
329365
for (Class<?> initialEntity : initialEntitySet) {
330366
addPersistentEntity(initialEntity);
331367
}

spring-data-commons-core/src/test/java/org/springframework/data/convert/ConfigurableTypeInformationMapperUnitTests.java

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2011 the original author or authors.
2+
* Copyright 2011-2012 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -26,6 +26,11 @@
2626

2727
import org.junit.Before;
2828
import org.junit.Test;
29+
import org.junit.runner.RunWith;
30+
import org.mockito.Mock;
31+
import org.mockito.runners.MockitoJUnitRunner;
32+
import org.springframework.context.ApplicationContext;
33+
import org.springframework.context.event.ContextRefreshedEvent;
2934
import org.springframework.data.annotation.TypeAlias;
3035
import org.springframework.data.mapping.Association;
3136
import org.springframework.data.mapping.PersistentProperty;
@@ -42,9 +47,12 @@
4247
*
4348
* @author Oliver Gierke
4449
*/
50+
@RunWith(MockitoJUnitRunner.class)
4551
public class ConfigurableTypeInformationMapperUnitTests<T extends PersistentProperty<T>> {
4652

4753
ConfigurableTypeInformationMapper mapper;
54+
@Mock
55+
ApplicationContext context;
4856

4957
@Before
5058
public void setUp() {
@@ -93,8 +101,11 @@ protected Association<T> createAssociation() {
93101
}
94102
};
95103

104+
ContextRefreshedEvent event = new ContextRefreshedEvent(context);
105+
96106
mappingContext.setInitialEntitySet(Collections.singleton(Entity.class));
97-
mappingContext.afterPropertiesSet();
107+
mappingContext.setApplicationContext(context);
108+
mappingContext.onApplicationEvent(event);
98109

99110
mapper = new ConfigurableTypeInformationMapper(mappingContext);
100111

spring-data-commons-core/src/test/java/org/springframework/data/mapping/MappingMetadataTests.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ public void setup() {
4444
}
4545

4646
@Test
47+
@SuppressWarnings("deprecation")
4748
public void testPojoWithId() {
4849

4950
ctx.setInitialEntitySet(Collections.singleton(PersonWithId.class));
@@ -55,6 +56,7 @@ public void testPojoWithId() {
5556
}
5657

5758
@Test
59+
@SuppressWarnings("deprecation")
5860
public void testAssociations() {
5961

6062
ctx.setInitialEntitySet(Collections.singleton(PersonWithChildren.class));
@@ -101,4 +103,4 @@ protected Association<SampleProperty> createAssociation() {
101103
return new Association<MappingMetadataTests.SampleProperty>(this, null);
102104
}
103105
}
104-
}
106+
}

spring-data-commons-core/src/test/java/org/springframework/data/mapping/context/AbstractMappingContextUnitTests.java

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,19 @@
11
package org.springframework.data.mapping.context;
22

3-
import static org.hamcrest.CoreMatchers.*;
3+
import static org.hamcrest.Matchers.*;
44
import static org.junit.Assert.*;
5+
import static org.mockito.Mockito.*;
56

67
import java.beans.PropertyDescriptor;
78
import java.lang.reflect.Field;
9+
import java.util.Collections;
810

911
import org.junit.Before;
1012
import org.junit.Test;
13+
import org.mockito.Mockito;
14+
import org.springframework.context.ApplicationContext;
15+
import org.springframework.context.ApplicationEvent;
16+
import org.springframework.context.event.ContextRefreshedEvent;
1117
import org.springframework.data.mapping.Association;
1218
import org.springframework.data.mapping.PropertyPath;
1319
import org.springframework.data.mapping.model.AbstractPersistentProperty;
@@ -54,6 +60,24 @@ public void doesNotAddInvalidEntity() {
5460
context.getPersistentEntity(Unsupported.class);
5561
}
5662

63+
@Test
64+
@SuppressWarnings("deprecation")
65+
public void registersEntitiesOnContextRefreshedEvent() {
66+
67+
ApplicationContext context = mock(ApplicationContext.class);
68+
69+
DummyMappingContext mappingContext = new DummyMappingContext();
70+
mappingContext.setInitialEntitySet(Collections.singleton(Person.class));
71+
mappingContext.setApplicationContext(context);
72+
mappingContext.setApplicationEventPublisher(context);
73+
74+
mappingContext.afterPropertiesSet();
75+
verify(context, times(0)).publishEvent(Mockito.any(ApplicationEvent.class));
76+
77+
mappingContext.onApplicationEvent(new ContextRefreshedEvent(context));
78+
verify(context, times(1)).publishEvent(Mockito.any(ApplicationEvent.class));
79+
}
80+
5781
class Person {
5882
String name;
5983
}

0 commit comments

Comments
 (0)