Skip to content

Commit 8233145

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 6899567 commit 8233145

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
@@ -38,6 +38,7 @@
3838
import org.slf4j.Logger;
3939
import org.slf4j.LoggerFactory;
4040
import org.springframework.beans.BeansException;
41+
import org.springframework.beans.factory.BeanClassLoaderAware;
4142
import org.springframework.context.ApplicationContext;
4243
import org.springframework.context.ApplicationContextAware;
4344
import org.springframework.core.CollectionFactory;
@@ -123,6 +124,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
123124
protected @Nullable String mapKeyDotReplacement = null;
124125
protected @Nullable CodecRegistryProvider codecRegistryProvider;
125126

127+
private MongoTypeMapper defaultTypeMapper;
126128
private SpELContext spELContext;
127129
private @Nullable EntityCallbacks entityCallbacks;
128130
private final DocumentPointerFactory documentPointerFactory;
@@ -144,7 +146,7 @@ public MappingMongoConverter(DbRefResolver dbRefResolver,
144146
this.dbRefResolver = dbRefResolver;
145147

146148
this.mappingContext = mappingContext;
147-
this.typeMapper = new DefaultMongoTypeMapper(DefaultMongoTypeMapper.DEFAULT_TYPE_KEY, mappingContext,
149+
this.defaultTypeMapper = new DefaultMongoTypeMapper(DefaultMongoTypeMapper.DEFAULT_TYPE_KEY, mappingContext,
148150
this::getWriteTarget);
149151
this.idMapper = new QueryMapper(this);
150152

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

205205
/*
@@ -208,7 +208,7 @@ public void setTypeMapper(@Nullable MongoTypeMapper typeMapper) {
208208
*/
209209
@Override
210210
public MongoTypeMapper getTypeMapper() {
211-
return this.typeMapper;
211+
return this.typeMapper == null ? this.defaultTypeMapper : this.typeMapper;
212212
}
213213

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

262267
/**
@@ -301,7 +306,7 @@ protected <S extends Object> S readDocument(ConversionContext context, Bson bson
301306
TypeInformation<? extends S> typeHint) {
302307

303308
Document document = bson instanceof BasicDBObject ? new Document((BasicDBObject) bson) : (Document) bson;
304-
TypeInformation<? extends S> typeToRead = typeMapper.readType(document, typeHint);
309+
TypeInformation<? extends S> typeToRead = getTypeMapper().readType(document, typeHint);
305310
Class<? extends S> rawType = typeToRead.getType();
306311

307312
if (conversions.hasCustomReadTarget(bson.getClass(), rawType)) {
@@ -657,7 +662,7 @@ public void write(Object obj, Bson bson) {
657662
BsonUtils.removeNullId(bson);
658663

659664
if (requiresTypeHint(entityType)) {
660-
typeMapper.writeType(type, bson);
665+
getTypeMapper().writeType(type, bson);
661666
}
662667
}
663668

@@ -1099,7 +1104,7 @@ protected void addCustomTypeKeyIfNecessary(@Nullable TypeInformation<?> type, Ob
10991104

11001105
boolean notTheSameClass = !valueType.equals(reference);
11011106
if (notTheSameClass) {
1102-
typeMapper.writeType(valueType, bson);
1107+
getTypeMapper().writeType(valueType, bson);
11031108
}
11041109
}
11051110

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

1310-
Class<?> mapType = typeMapper.readType(bson, targetType).getType();
1315+
Class<?> mapType = getTypeMapper().readType(bson, targetType).getType();
13111316

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

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

1329-
if (typeMapper.isTypeKey(k)) {
1334+
if (getTypeMapper().isTypeKey(k)) {
13301335
return;
13311336
}
13321337

@@ -1489,7 +1494,7 @@ private Object removeTypeInfo(Object object, boolean recursively) {
14891494
}
14901495
}
14911496

1492-
if (typeMapper.isTypeKey(key)) {
1497+
if (getTypeMapper().isTypeKey(key)) {
14931498

14941499
keyToRemove = key;
14951500

@@ -1660,6 +1665,7 @@ public MappingMongoConverter with(MongoDatabaseFactory dbFactory) {
16601665
target.conversions = conversions;
16611666
target.spELContext = spELContext;
16621667
target.setInstantiators(instantiators);
1668+
target.defaultTypeMapper = defaultTypeMapper;
16631669
target.typeMapper = typeMapper;
16641670
target.setCodecRegistryProvider(dbFactory);
16651671
target.afterPropertiesSet();

0 commit comments

Comments
 (0)