Skip to content

Improve performance for conversions using a method parameter based type descriptor with annotations [SPR-14926] #19493

Closed
@spring-projects-issues

Description

@spring-projects-issues

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:

Issue Links:

Metadata

Metadata

Assignees

Labels

in: coreIssues in core modules (aop, beans, core, context, expression)type: enhancementA general enhancement

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions