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
This commit is contained in:
@@ -39,6 +39,7 @@ import org.bson.json.JsonReader;
|
||||
import org.bson.types.ObjectId;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.core.CollectionFactory;
|
||||
@@ -124,6 +125,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
protected @Nullable String mapKeyDotReplacement = null;
|
||||
protected @Nullable CodecRegistryProvider codecRegistryProvider;
|
||||
|
||||
private MongoTypeMapper defaultTypeMapper;
|
||||
private SpELContext spELContext;
|
||||
private @Nullable EntityCallbacks entityCallbacks;
|
||||
private final DocumentPointerFactory documentPointerFactory;
|
||||
@@ -145,7 +147,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
this.dbRefResolver = dbRefResolver;
|
||||
|
||||
this.mappingContext = mappingContext;
|
||||
this.typeMapper = new DefaultMongoTypeMapper(DefaultMongoTypeMapper.DEFAULT_TYPE_KEY, mappingContext,
|
||||
this.defaultTypeMapper = new DefaultMongoTypeMapper(DefaultMongoTypeMapper.DEFAULT_TYPE_KEY, mappingContext,
|
||||
this::getWriteTarget);
|
||||
this.idMapper = new QueryMapper(this);
|
||||
|
||||
@@ -198,9 +200,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
* @param typeMapper the typeMapper to set. Can be {@literal null}.
|
||||
*/
|
||||
public void setTypeMapper(@Nullable MongoTypeMapper typeMapper) {
|
||||
this.typeMapper = typeMapper == null
|
||||
? new DefaultMongoTypeMapper(DefaultMongoTypeMapper.DEFAULT_TYPE_KEY, mappingContext)
|
||||
: typeMapper;
|
||||
this.typeMapper = typeMapper;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -209,7 +209,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
*/
|
||||
@Override
|
||||
public MongoTypeMapper getTypeMapper() {
|
||||
return this.typeMapper;
|
||||
return this.typeMapper == null ? this.defaultTypeMapper : this.typeMapper;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -258,6 +258,11 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
if (entityCallbacks == null) {
|
||||
setEntityCallbacks(EntityCallbacks.create(applicationContext));
|
||||
}
|
||||
|
||||
ClassLoader classLoader = applicationContext.getClassLoader();
|
||||
if (this.defaultTypeMapper instanceof BeanClassLoaderAware && classLoader != null) {
|
||||
((BeanClassLoaderAware) this.defaultTypeMapper).setBeanClassLoader(classLoader);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -302,7 +307,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
TypeInformation<? extends S> typeHint) {
|
||||
|
||||
Document document = bson instanceof BasicDBObject ? new Document((BasicDBObject) bson) : (Document) bson;
|
||||
TypeInformation<? extends S> typeToRead = typeMapper.readType(document, typeHint);
|
||||
TypeInformation<? extends S> typeToRead = getTypeMapper().readType(document, typeHint);
|
||||
Class<? extends S> rawType = typeToRead.getType();
|
||||
|
||||
if (conversions.hasCustomReadTarget(bson.getClass(), rawType)) {
|
||||
@@ -658,7 +663,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
BsonUtils.removeNullId(bson);
|
||||
|
||||
if (requiresTypeHint(entityType)) {
|
||||
typeMapper.writeType(type, bson);
|
||||
getTypeMapper().writeType(type, bson);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1100,7 +1105,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
|
||||
boolean notTheSameClass = !valueType.equals(reference);
|
||||
if (notTheSameClass) {
|
||||
typeMapper.writeType(valueType, bson);
|
||||
getTypeMapper().writeType(valueType, bson);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1308,7 +1313,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
Assert.notNull(bson, "Document must not be null!");
|
||||
Assert.notNull(targetType, "TypeInformation must not be null!");
|
||||
|
||||
Class<?> mapType = typeMapper.readType(bson, targetType).getType();
|
||||
Class<?> mapType = getTypeMapper().readType(bson, targetType).getType();
|
||||
|
||||
TypeInformation<?> keyType = targetType.getComponentType();
|
||||
TypeInformation<?> valueType = targetType.getMapValueType() == null ? ClassTypeInformation.OBJECT
|
||||
@@ -1327,7 +1332,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
|
||||
sourceMap.forEach((k, v) -> {
|
||||
|
||||
if (typeMapper.isTypeKey(k)) {
|
||||
if (getTypeMapper().isTypeKey(k)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1490,7 +1495,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
}
|
||||
}
|
||||
|
||||
if (typeMapper.isTypeKey(key)) {
|
||||
if (getTypeMapper().isTypeKey(key)) {
|
||||
|
||||
keyToRemove = key;
|
||||
|
||||
@@ -1661,6 +1666,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
target.conversions = conversions;
|
||||
target.spELContext = spELContext;
|
||||
target.setInstantiators(instantiators);
|
||||
target.defaultTypeMapper = defaultTypeMapper;
|
||||
target.typeMapper = typeMapper;
|
||||
target.setCodecRegistryProvider(dbFactory);
|
||||
target.afterPropertiesSet();
|
||||
|
||||
Reference in New Issue
Block a user