Closed
Description
Oliver Drotbohm opened SPR-14926 and commented
When a conversion is invoked using a TypeDescriptor
instance that was created for a MethodParameter
containing annotations, the lookup of the Converter
is significantly slowed down as the TypeDescriptor
instances undergo an ….equals(…)
check that's quite expensive due to the synthesized annotations.
I wonder whether TypeDescriptor
really needs to compare the annotations if the method and the parameter index are well defined as they by definition uniquely identify the parameter.
Here's a sample test case showing the issue:
package org.example.myapi;
import java.lang.reflect.Method;
import java.util.Date;
import org.junit.Test;
import org.springframework.core.MethodParameter;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.format.annotation.DateTimeFormat.ISO;
import org.springframework.format.support.DefaultFormattingConversionService;
import org.springframework.http.ResponseEntity;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.bind.annotation.RequestParam;
/**
* @author Oliver Gierke
*/
public class FooTests {
private static final int ITERATIONS = 1000000;
private static final ConversionService CONVERSION_SERVICE = new DefaultFormattingConversionService();
private static final TypeDescriptor STRING_TYPE = TypeDescriptor.valueOf(String.class);
@Test
public void methodParameterWithAnnotations() {
Date date = new Date();
Method method = ReflectionUtils.findMethod(SomeController.class, "someMethod", Date.class);
TypeDescriptor sourceDescriptor = TypeDescriptor.nested(new MethodParameter(method, 0), 0);
long startTime = System.currentTimeMillis();
for (int i = 0; i < ITERATIONS; i++) {
CONVERSION_SERVICE.convert(date, sourceDescriptor, STRING_TYPE);
}
long duration = (System.currentTimeMillis() - startTime);
System.out.println("With annotations " + duration);
}
@Test
public void methodParameterWithoutAnnotations() {
Method method = ReflectionUtils.findMethod(SomeController.class, "someMethod", String.class);
TypeDescriptor sourceDescriptor = TypeDescriptor.nested(new MethodParameter(method, 0), 0);
long startTime = System.currentTimeMillis();
for (int i = 0; i < ITERATIONS; i++) {
CONVERSION_SERVICE.convert("Foo", sourceDescriptor, STRING_TYPE);
}
long duration = (System.currentTimeMillis() - startTime);
System.out.println("Without annotations " + duration);
}
static class SomeController {
ResponseEntity<Object> someMethod(@RequestParam("foo") @DateTimeFormat(iso = ISO.DATE) Date date) {
return null;
}
ResponseEntity<Object> someMethod(String value) {
return null;
}
}
}
Affects: 4.3.4
Reference URL: spring-projects/spring-hateoas#511
Attachments:
- Bildschirmfoto 2016-11-21 um 11.20.48.PNG (154.80 kB)
- Bildschirmfoto 2016-11-26 um 13.16.01.PNG (89.78 kB)
- Bildschirmfoto 2016-11-26 um 13.56.30.PNG (110.74 kB)
Issue Links:
- Spring Performance Optimization, Comparing Classes [SPR-12926] #17519 Spring Performance Optimization, Comparing Classes
- AnnotationFormatterFactory should support @AliasFor [SPR-14844] #19410 AnnotationFormatterFactory should support
@AliasFor
- Differentiate between TypeDescriptors with same annotations but different attributes [SPR-13714] #18287 Differentiate between TypeDescriptors with same annotations but different attributes
- ConversionService performance regression [SPR-14929] #19496 ConversionService performance regression
- Annotated method argument matching performance issue [SPR-15060] #19626 Annotated method argument matching performance issue
- @DateTimeFormat(iso = ISO.DATE_TIME) should use optimized formatter for LocalDateTime [SPR-14958] #19525
@DateTimeFormat
(iso = ISO.DATE_TIME) should use optimized formatter for LocalDateTime