Skip to content

MappingMongoConverter problem: ConversionContext#convert does not try to use custom converters first #3660

Closed
@xjme

Description

@xjme

Hi, we upgraded from spring boot 2.4.3 to version 2.5.0. In the new version of SB, the spring data mongo db was updated from version 3.1.5 to 3.2.1.

We encountered a problem during the conversion of an object implementing java.util.Map, for which, however, we have implemented a custom converter.

The problem is that the custom converter is not called, the default mapConverter is used instead.

When I compare the previous code of MappingMongoConverter, more precisely code related to converting a property value, it was first checked whether a value with a certain type has a custom conversion defined. This is not the case in the new version of spring data mongodb, more precisely within ConversionContext#convert method.

For clarity, I present the differences between the individual versions of MappingMongoConvertor:

Spring Data MongoDb 3.2.1

MappingMongoConverter#getPropertyValue

@Nullable
@SuppressWarnings("unchecked")
public <T> T getPropertyValue(MongoPersistentProperty property) {

	String expression = property.getSpelExpression();
	Object value = expression != null ? evaluator.evaluate(expression) : accessor.get(property);

	if (value == null) {
		return null;
	}

	return (T) context.convert(value, property.getTypeInformation());
}

MappingMongoConverter.ConversionContext#convert

public <S extends Object> S convert(Object source, TypeInformation<? extends S> typeHint) {

	Assert.notNull(typeHint, "TypeInformation must not be null");

	if (source instanceof Collection) {

		Class<?> rawType = typeHint.getType();
		if (!Object.class.equals(rawType)) {
			if (!rawType.isArray() && !ClassUtils.isAssignable(Iterable.class, rawType)) {
				throw new MappingException(
						String.format(INCOMPATIBLE_TYPES, source, source.getClass(), rawType, getPath()));
			}
		}

		if (typeHint.isCollectionLike() || typeHint.getType().isAssignableFrom(Collection.class)) {
			return (S) collectionConverter.convert(this, (Collection<?>) source, typeHint);
		}
	}

	if (typeHint.isMap()) { // this causes a problem, it should be converted using custom map converter, not this.mapConverter
		return (S) mapConverter.convert(this, (Bson) source, typeHint);
	}

	if (source instanceof DBRef) {
		return (S) dbRefConverter.convert(this, (DBRef) source, typeHint);
	}

	if (source instanceof Collection) {
		throw new MappingException(
				String.format(INCOMPATIBLE_TYPES, source, BasicDBList.class, typeHint.getType(), getPath()));
	}

	if (source instanceof Bson) {
		return (S) documentConverter.convert(this, (Bson) source, typeHint);
	}

	return (S) elementConverter.convert(source, typeHint);
}

vs.

Spring Data MongoDb 3.1.5

MappingMongoConverter#getPropertyValue

@Nullable
public <T> T getPropertyValue(MongoPersistentProperty property) {

	String expression = property.getSpelExpression();
	Object value = expression != null ? evaluator.evaluate(expression) : accessor.get(property);

	if (value == null) {
		return null;
	}

	return readValue(value, property.getTypeInformation(), path);
}

MappingMongoConverter#readValue

@Nullable
@SuppressWarnings("unchecked")
<T> T readValue(Object value, TypeInformation<?> type, ObjectPath path) {

	Class<?> rawType = type.getType();

	if (conversions.hasCustomReadTarget(value.getClass(), rawType)) { // this check picks the custom converter
		return (T) conversionService.convert(value, rawType);
	} else if (value instanceof DBRef) {
		return potentiallyReadOrResolveDbRef((DBRef) value, type, path, rawType);
	} else if (value instanceof List) {
		return (T) readCollectionOrArray(type, (List<Object>) value, path);
	} else if (value instanceof Document) {
		return (T) read(type, (Document) value, path);
	} else if (value instanceof DBObject) {
		return (T) read(type, (BasicDBObject) value, path);
	} else {
		return (T) getPotentiallyConvertedSimpleRead(value, rawType);
	}
}

Metadata

Metadata

Labels

type: regressionA regression from a previous release

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions