Skip to content

Commit 75999d9

Browse files
committed
Propagate Bean ClassLoader to MongoTypeMapper.
We now set the ClassLoader from the ApplicationContext to the type mapper to ensure the type mapper has access to entities. Previously, `SimpleTypeInformationMapper` used the contextual class loader and that failed in Fork/Join-Pool threads such as parallel streams as ForkJoinPool uses the system classloader. Running e.g. a packaged Boot application sets up an application ClassLoader that has access to packaged code while the system ClassLoader does not. Also, consistently access the MongoTypeMapper through its getter. Closes #3905
1 parent 7a64025 commit 75999d9

File tree

1 file changed

+17
-11
lines changed

1 file changed

+17
-11
lines changed

spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverter.java

+17-11
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
import org.bson.types.ObjectId;
4040

4141
import org.springframework.beans.BeansException;
42+
import org.springframework.beans.factory.BeanClassLoaderAware;
4243
import org.springframework.context.ApplicationContext;
4344
import org.springframework.context.ApplicationContextAware;
4445
import org.springframework.core.CollectionFactory;
@@ -124,6 +125,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
124125
protected @Nullable String mapKeyDotReplacement = null;
125126
protected @Nullable CodecRegistryProvider codecRegistryProvider;
126127

128+
private MongoTypeMapper defaultTypeMapper;
127129
private SpELContext spELContext;
128130
private @Nullable EntityCallbacks entityCallbacks;
129131
private final DocumentPointerFactory documentPointerFactory;
@@ -145,7 +147,7 @@ public MappingMongoConverter(DbRefResolver dbRefResolver,
145147
this.dbRefResolver = dbRefResolver;
146148

147149
this.mappingContext = mappingContext;
148-
this.typeMapper = new DefaultMongoTypeMapper(DefaultMongoTypeMapper.DEFAULT_TYPE_KEY, mappingContext,
150+
this.defaultTypeMapper = new DefaultMongoTypeMapper(DefaultMongoTypeMapper.DEFAULT_TYPE_KEY, mappingContext,
149151
this::getWriteTarget);
150152
this.idMapper = new QueryMapper(this);
151153

@@ -198,9 +200,7 @@ public MappingMongoConverter(MongoDatabaseFactory mongoDbFactory,
198200
* @param typeMapper the typeMapper to set. Can be {@literal null}.
199201
*/
200202
public void setTypeMapper(@Nullable MongoTypeMapper typeMapper) {
201-
this.typeMapper = typeMapper == null
202-
? new DefaultMongoTypeMapper(DefaultMongoTypeMapper.DEFAULT_TYPE_KEY, mappingContext)
203-
: typeMapper;
203+
this.typeMapper = typeMapper;
204204
}
205205

206206
/*
@@ -209,7 +209,7 @@ public void setTypeMapper(@Nullable MongoTypeMapper typeMapper) {
209209
*/
210210
@Override
211211
public MongoTypeMapper getTypeMapper() {
212-
return this.typeMapper;
212+
return this.typeMapper == null ? this.defaultTypeMapper : this.typeMapper;
213213
}
214214

215215
/**
@@ -258,6 +258,11 @@ public void setApplicationContext(ApplicationContext applicationContext) throws
258258
if (entityCallbacks == null) {
259259
setEntityCallbacks(EntityCallbacks.create(applicationContext));
260260
}
261+
262+
ClassLoader classLoader = applicationContext.getClassLoader();
263+
if (this.defaultTypeMapper instanceof BeanClassLoaderAware && classLoader != null) {
264+
((BeanClassLoaderAware) this.defaultTypeMapper).setBeanClassLoader(classLoader);
265+
}
261266
}
262267

263268
/**
@@ -302,7 +307,7 @@ protected <S extends Object> S readDocument(ConversionContext context, Bson bson
302307
TypeInformation<? extends S> typeHint) {
303308

304309
Document document = bson instanceof BasicDBObject ? new Document((BasicDBObject) bson) : (Document) bson;
305-
TypeInformation<? extends S> typeToRead = typeMapper.readType(document, typeHint);
310+
TypeInformation<? extends S> typeToRead = getTypeMapper().readType(document, typeHint);
306311
Class<? extends S> rawType = typeToRead.getType();
307312

308313
if (conversions.hasCustomReadTarget(bson.getClass(), rawType)) {
@@ -658,7 +663,7 @@ public void write(Object obj, Bson bson) {
658663
BsonUtils.removeNullId(bson);
659664

660665
if (requiresTypeHint(entityType)) {
661-
typeMapper.writeType(type, bson);
666+
getTypeMapper().writeType(type, bson);
662667
}
663668
}
664669

@@ -1100,7 +1105,7 @@ protected void addCustomTypeKeyIfNecessary(@Nullable TypeInformation<?> type, Ob
11001105

11011106
boolean notTheSameClass = !valueType.equals(reference);
11021107
if (notTheSameClass) {
1103-
typeMapper.writeType(valueType, bson);
1108+
getTypeMapper().writeType(valueType, bson);
11041109
}
11051110
}
11061111

@@ -1308,7 +1313,7 @@ protected Map<Object, Object> readMap(ConversionContext context, Bson bson, Type
13081313
Assert.notNull(bson, "Document must not be null!");
13091314
Assert.notNull(targetType, "TypeInformation must not be null!");
13101315

1311-
Class<?> mapType = typeMapper.readType(bson, targetType).getType();
1316+
Class<?> mapType = getTypeMapper().readType(bson, targetType).getType();
13121317

13131318
TypeInformation<?> keyType = targetType.getComponentType();
13141319
TypeInformation<?> valueType = targetType.getMapValueType() == null ? ClassTypeInformation.OBJECT
@@ -1327,7 +1332,7 @@ protected Map<Object, Object> readMap(ConversionContext context, Bson bson, Type
13271332

13281333
sourceMap.forEach((k, v) -> {
13291334

1330-
if (typeMapper.isTypeKey(k)) {
1335+
if (getTypeMapper().isTypeKey(k)) {
13311336
return;
13321337
}
13331338

@@ -1490,7 +1495,7 @@ private Object removeTypeInfo(Object object, boolean recursively) {
14901495
}
14911496
}
14921497

1493-
if (typeMapper.isTypeKey(key)) {
1498+
if (getTypeMapper().isTypeKey(key)) {
14941499

14951500
keyToRemove = key;
14961501

@@ -1661,6 +1666,7 @@ public MappingMongoConverter with(MongoDatabaseFactory dbFactory) {
16611666
target.conversions = conversions;
16621667
target.spELContext = spELContext;
16631668
target.setInstantiators(instantiators);
1669+
target.defaultTypeMapper = defaultTypeMapper;
16641670
target.typeMapper = typeMapper;
16651671
target.setCodecRegistryProvider(dbFactory);
16661672
target.afterPropertiesSet();

0 commit comments

Comments
 (0)