Skip to content

Commit

Permalink
Optimize cache usage in DefaultConversionService and fix race condition
Browse files Browse the repository at this point in the history
  • Loading branch information
PakhomovAlexander committed Nov 21, 2023
1 parent 9e20f4f commit bbafea4
Showing 1 changed file with 16 additions and 55 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -125,69 +125,42 @@ public <T> Optional<T> convert(Object object, Class<T> targetType, ConversionCon
ConvertiblePair pair = new ConvertiblePair(sourceType, targetType, formattingAnnotation);
TypeConverter typeConverter = converterCache.get(pair);
if (typeConverter == null) {
typeConverter = findTypeConverter(sourceType, targetType, formattingAnnotation);
if (typeConverter == null) {
return Optional.empty();
} else {
converterCache.put(pair, typeConverter);
if (typeConverter == UNCONVERTIBLE) {
return Optional.empty();
} else {
return typeConverter.convert(object, targetType, context);
}
}
} else if (typeConverter != UNCONVERTIBLE) {
return typeConverter.convert(object, targetType, context);
typeConverter = findTypeConverter(pair.source, pair.target, pair.formattingAnnotation);
converterCache.put(pair, typeConverter);
}
return typeConverter.convert(object, targetType, context);
} else {
ConvertiblePair pair = new ConvertiblePair(sourceType, targetType, null);
TypeConverter typeConverter = converterCache.get(pair);
if (typeConverter == null) {
typeConverter = findTypeConverter(sourceType, targetType, null);
if (typeConverter == null) {
converterCache.put(pair, UNCONVERTIBLE);
return Optional.empty();
} else {
converterCache.put(pair, typeConverter);
if (typeConverter == UNCONVERTIBLE) {
return Optional.empty();
} else {
return typeConverter.convert(object, targetType, context);
}
}
} else if (typeConverter != UNCONVERTIBLE) {
return typeConverter.convert(object, targetType, context);
typeConverter = findTypeConverter(pair.source, pair.target, pair.formattingAnnotation);
converterCache.put(pair, typeConverter);
}
return typeConverter.convert(object, targetType, context);
}

return Optional.empty();
}

@Override
public <S, T> boolean canConvert(Class<S> sourceType, Class<T> targetType) {
ConvertiblePair pair = new ConvertiblePair(sourceType, targetType, null);
TypeConverter typeConverter = converterCache.get(pair);
if (typeConverter == null) {
typeConverter = findTypeConverter(sourceType, targetType, null);
if (typeConverter != null) {
converterCache.put(pair, typeConverter);
return typeConverter != UNCONVERTIBLE;
}
return false;
typeConverter = findTypeConverter(pair.source, pair.target, pair.formattingAnnotation);
converterCache.put(pair, typeConverter);
}
return typeConverter != UNCONVERTIBLE;
}

@Override
public <S, T> DefaultConversionService addConverter(Class<S> sourceType, Class<T> targetType, TypeConverter<S, T> typeConverter) {
public <S, T> DefaultConversionService addConverter(Class<S> sourceType, Class<T> targetType, TypeConverter<S, T> typeConverter) {
ConvertiblePair pair = newPair(sourceType, targetType, typeConverter);
typeConverters.put(pair, typeConverter);
converterCache.put(pair, typeConverter);
return this;
}

@Override
public <S, T> DefaultConversionService addConverter(Class<S> sourceType, Class<T> targetType, Function<S, T> function) {
public <S, T> DefaultConversionService addConverter(Class<S> sourceType, Class<T> targetType, Function<S, T> function) {
ConvertiblePair pair = new ConvertiblePair(sourceType, targetType);
TypeConverter<S, T> typeConverter = TypeConverter.of(sourceType, targetType, function);
typeConverters.put(pair, typeConverter);
Expand All @@ -202,7 +175,7 @@ public <S, T> DefaultConversionService addConverter(Class<S> sourceType, Class<T
* @since 3.5.3
*/
@Internal
public void reset() {
public synchronized void reset() {
typeConverters.clear();
converterCache.clear();
registerDefaultConverters();
Expand All @@ -212,7 +185,7 @@ public void reset() {
* Default Converters.
*/
@SuppressWarnings({"OptionalIsPresent", "unchecked"})
protected void registerDefaultConverters() {
protected synchronized void registerDefaultConverters() {
// primitive array to wrapper array
@SuppressWarnings("rawtypes")
Function primitiveArrayToWrapperArray = ArrayUtils::toWrapperArray;
Expand Down Expand Up @@ -974,8 +947,8 @@ protected void registerDefaultConverters() {
* @param <T> Generic type
* @return type converter
*/
protected <T> TypeConverter findTypeConverter(Class<?> sourceType, Class<T> targetType, String formattingAnnotation) {
TypeConverter typeConverter = UNCONVERTIBLE;
protected synchronized <T> TypeConverter findTypeConverter(Class<?> sourceType, Class<T> targetType, String formattingAnnotation) {
TypeConverter typeConverter = null;
List<Class> sourceHierarchy = ClassUtils.resolveHierarchy(sourceType);
List<Class> targetHierarchy = ClassUtils.resolveHierarchy(targetType);
for (Class sourceSuperType : sourceHierarchy) {
Expand All @@ -988,20 +961,8 @@ protected <T> TypeConverter findTypeConverter(Class<?> sourceType, Class<T> targ
}
}
}
boolean hasFormatting = formattingAnnotation != null;
if (hasFormatting) {
for (Class sourceSuperType : sourceHierarchy) {
for (Class targetSuperType : targetHierarchy) {
ConvertiblePair pair = new ConvertiblePair(sourceSuperType, targetSuperType);
typeConverter = typeConverters.get(pair);
if (typeConverter != null) {
converterCache.put(pair, typeConverter);
return typeConverter;
}
}
}
}
return typeConverter;

return UNCONVERTIBLE;
}

private SimpleDateFormat resolveFormat(ConversionContext context) {
Expand Down

0 comments on commit bbafea4

Please sign in to comment.