caching optmizations and performance tests
git-svn-id: https://src.springframework.org/svn/spring-framework/trunk@3268 50f2f4bb-b051-0410-bef5-90022cba6387
This commit is contained in:
parent
d8b65390ae
commit
28a652ea77
|
|
@ -73,6 +73,12 @@ public class TypeDescriptor {
|
|||
|
||||
private Object value;
|
||||
|
||||
private TypeDescriptor elementType;
|
||||
|
||||
private TypeDescriptor mapKeyType;
|
||||
|
||||
private TypeDescriptor mapValueType;
|
||||
|
||||
/**
|
||||
* Create a new type descriptor from a method or constructor parameter.
|
||||
* <p>Use this constructor when a target conversion point originates from a method parameter,
|
||||
|
|
@ -233,22 +239,19 @@ public class TypeDescriptor {
|
|||
* Returns <code>null</code> if the type is neither an array or collection.
|
||||
*/
|
||||
public Class<?> getElementType() {
|
||||
if (isArray()) {
|
||||
return getArrayComponentType();
|
||||
}
|
||||
else if (isCollection()) {
|
||||
return getCollectionElementType();
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
return getElementTypeDescriptor().getType();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the element type as a type descriptor.
|
||||
*/
|
||||
public TypeDescriptor getElementTypeDescriptor() {
|
||||
return forElementType(getElementType());
|
||||
if (elementType != null) {
|
||||
return elementType;
|
||||
} else {
|
||||
elementType = forElementType(resolveElementType());
|
||||
return elementType;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -257,7 +260,8 @@ public class TypeDescriptor {
|
|||
* @return the element type descriptor
|
||||
*/
|
||||
public TypeDescriptor getElementTypeDescriptor(Object element) {
|
||||
return getElementType() != null ? getElementTypeDescriptor() : TypeDescriptor.forObject(element);
|
||||
TypeDescriptor elementType = getElementTypeDescriptor();
|
||||
return elementType != TypeDescriptor.NULL ? elementType : TypeDescriptor.forObject(element);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -278,63 +282,20 @@ public class TypeDescriptor {
|
|||
* Determine the generic key type of the wrapped Map parameter/field, if any.
|
||||
* @return the generic type, or <code>null</code> if none
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public Class<?> getMapKeyType() {
|
||||
if (isMap()) {
|
||||
if (this.field != null) {
|
||||
return GenericCollectionTypeResolver.getMapKeyFieldType(this.field);
|
||||
}
|
||||
else if (this.methodParameter != null) {
|
||||
return GenericCollectionTypeResolver.getMapKeyParameterType(this.methodParameter);
|
||||
}
|
||||
else if (this.value instanceof Map) {
|
||||
Map map = (Map) this.value;
|
||||
if (!map.isEmpty()) {
|
||||
Object key = map.keySet().iterator().next();
|
||||
if (key != null) {
|
||||
return key.getClass();
|
||||
}
|
||||
}
|
||||
}
|
||||
return GenericCollectionTypeResolver.getMapKeyType((Class<? extends Map>) this.type);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the generic value type of the wrapped Map parameter/field, if any.
|
||||
* @return the generic type, or <code>null</code> if none
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public Class<?> getMapValueType() {
|
||||
if (isMap()) {
|
||||
if (this.field != null) {
|
||||
return GenericCollectionTypeResolver.getMapValueFieldType(this.field);
|
||||
}
|
||||
else if (this.methodParameter != null) {
|
||||
return GenericCollectionTypeResolver.getMapValueParameterType(this.methodParameter);
|
||||
}
|
||||
else if (this.value instanceof Map) {
|
||||
Map map = (Map) this.value;
|
||||
if (!map.isEmpty()) {
|
||||
Object val = map.values().iterator().next();
|
||||
if (val != null) {
|
||||
return val.getClass();
|
||||
}
|
||||
}
|
||||
}
|
||||
return GenericCollectionTypeResolver.getMapValueType((Class<? extends Map>) this.type);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
return getMapKeyTypeDescriptor().getType();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns map key type as a type descriptor.
|
||||
*/
|
||||
public TypeDescriptor getMapKeyTypeDescriptor() {
|
||||
return forElementType(getMapKeyType());
|
||||
if (mapKeyType != null) {
|
||||
return mapKeyType;
|
||||
} else {
|
||||
mapKeyType = isMap() ? forElementType(resolveMapKeyType()) : null;
|
||||
return mapKeyType;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -343,14 +304,28 @@ public class TypeDescriptor {
|
|||
* @return the map key type descriptor
|
||||
*/
|
||||
public TypeDescriptor getMapKeyTypeDescriptor(Object key) {
|
||||
return getMapKeyType() != null ? getMapKeyTypeDescriptor() : TypeDescriptor.forObject(key);
|
||||
TypeDescriptor keyType = getMapKeyTypeDescriptor();
|
||||
return keyType != TypeDescriptor.NULL ? keyType : TypeDescriptor.forObject(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the generic value type of the wrapped Map parameter/field, if any.
|
||||
* @return the generic type, or <code>null</code> if none
|
||||
*/
|
||||
public Class<?> getMapValueType() {
|
||||
return getMapValueTypeDescriptor().getType();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns map value type as a type descriptor.
|
||||
*/
|
||||
public TypeDescriptor getMapValueTypeDescriptor() {
|
||||
return forElementType(getMapValueType());
|
||||
if (mapValueType != null) {
|
||||
return mapValueType;
|
||||
} else {
|
||||
mapValueType = isMap() ? forElementType(resolveMapValueType()) : null;
|
||||
return mapValueType;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -359,7 +334,8 @@ public class TypeDescriptor {
|
|||
* @return the map value type descriptor
|
||||
*/
|
||||
public TypeDescriptor getMapValueTypeDescriptor(Object value) {
|
||||
return getMapValueType() != null ? getMapValueTypeDescriptor() : TypeDescriptor.forObject(value);
|
||||
TypeDescriptor valueType = getMapValueTypeDescriptor();
|
||||
return valueType != TypeDescriptor.NULL ? valueType : TypeDescriptor.forObject(value);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -367,10 +343,12 @@ public class TypeDescriptor {
|
|||
*/
|
||||
public Annotation[] getAnnotations() {
|
||||
if (this.field != null) {
|
||||
// not caching
|
||||
return this.field.getAnnotations();
|
||||
}
|
||||
else if (this.methodParameter != null) {
|
||||
if (this.methodParameter.getParameterIndex() < 0) {
|
||||
// not caching
|
||||
return this.methodParameter.getMethodAnnotations();
|
||||
}
|
||||
else {
|
||||
|
|
@ -494,12 +472,20 @@ public class TypeDescriptor {
|
|||
|
||||
// internal helpers
|
||||
|
||||
private Class<?> getArrayComponentType() {
|
||||
return getType().getComponentType();
|
||||
private Class<?> resolveElementType() {
|
||||
if (isArray()) {
|
||||
return getType().getComponentType();
|
||||
}
|
||||
else if (isCollection()) {
|
||||
return resolveCollectionElementType();
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Class<?> getCollectionElementType() {
|
||||
private Class<?> resolveCollectionElementType() {
|
||||
if (this.field != null) {
|
||||
return GenericCollectionTypeResolver.getCollectionFieldType(this.field);
|
||||
}
|
||||
|
|
@ -515,12 +501,47 @@ public class TypeDescriptor {
|
|||
}
|
||||
}
|
||||
}
|
||||
if (this.type != null) {
|
||||
return GenericCollectionTypeResolver.getCollectionType((Class<? extends Collection>) this.type);
|
||||
return type != null ? GenericCollectionTypeResolver.getCollectionType((Class<? extends Collection>) this.type) : null;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Class<?> resolveMapKeyType() {
|
||||
if (this.field != null) {
|
||||
return GenericCollectionTypeResolver.getMapKeyFieldType(this.field);
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
else if (this.methodParameter != null) {
|
||||
return GenericCollectionTypeResolver.getMapKeyParameterType(this.methodParameter);
|
||||
}
|
||||
else if (this.value instanceof Map<?, ?>) {
|
||||
Map<?, ?> map = (Map<?, ?>) this.value;
|
||||
if (!map.isEmpty()) {
|
||||
Object key = map.keySet().iterator().next();
|
||||
if (key != null) {
|
||||
return key.getClass();
|
||||
}
|
||||
}
|
||||
}
|
||||
return type != null ? GenericCollectionTypeResolver.getMapKeyType((Class<? extends Map>) this.type) : null;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Class<?> resolveMapValueType() {
|
||||
if (this.field != null) {
|
||||
return GenericCollectionTypeResolver.getMapValueFieldType(this.field);
|
||||
}
|
||||
else if (this.methodParameter != null) {
|
||||
return GenericCollectionTypeResolver.getMapValueParameterType(this.methodParameter);
|
||||
}
|
||||
else if (this.value instanceof Map<?, ?>) {
|
||||
Map<?, ?> map = (Map<?, ?>) this.value;
|
||||
if (!map.isEmpty()) {
|
||||
Object val = map.values().iterator().next();
|
||||
if (val != null) {
|
||||
return val.getClass();
|
||||
}
|
||||
}
|
||||
}
|
||||
return type != null ? GenericCollectionTypeResolver.getMapValueType((Class<? extends Map>) this.type) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -16,19 +16,27 @@
|
|||
|
||||
package org.springframework.core.convert.support;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.core.convert.ConversionFailedException;
|
||||
import org.springframework.core.convert.ConverterNotFoundException;
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.util.StopWatch;
|
||||
|
||||
/**
|
||||
* @author Keith Donald
|
||||
|
|
@ -193,6 +201,58 @@ public class GenericConversionServiceTests {
|
|||
assertEquals(input, converted);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void testPerformance1() {
|
||||
GenericConversionService conversionService = ConversionServiceFactory.createDefaultConversionService();
|
||||
StopWatch watch = new StopWatch("conversionPerformance");
|
||||
watch.start("convert 4,000,000");
|
||||
for (int i = 0; i < 4000000; i++) {
|
||||
conversionService.convert(3, String.class);
|
||||
}
|
||||
watch.stop();
|
||||
System.out.println(watch.prettyPrint());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void testPerformance2() throws Exception {
|
||||
GenericConversionService conversionService = ConversionServiceFactory.createDefaultConversionService();
|
||||
StopWatch watch = new StopWatch("conversionPerformance");
|
||||
watch.start("convert 4,000,000");
|
||||
List<String> source = new LinkedList<String>();
|
||||
source.add("1");
|
||||
source.add("2");
|
||||
source.add("3");
|
||||
TypeDescriptor td = new TypeDescriptor(getClass().getField("list"));
|
||||
for (int i = 0; i < 1000000; i++) {
|
||||
conversionService.convert(source, TypeDescriptor.forObject(source), td);
|
||||
}
|
||||
watch.stop();
|
||||
System.out.println(watch.prettyPrint());
|
||||
}
|
||||
|
||||
public static List<Integer> list;
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void testPerformance3() throws Exception {
|
||||
GenericConversionService conversionService = ConversionServiceFactory.createDefaultConversionService();
|
||||
StopWatch watch = new StopWatch("conversionPerformance");
|
||||
watch.start("convert 4,000,000");
|
||||
Map<String, String> source = new HashMap<String, String>();
|
||||
source.put("1", "1");
|
||||
source.put("2", "2");
|
||||
source.put("3", "3");
|
||||
TypeDescriptor td = new TypeDescriptor(getClass().getField("map"));
|
||||
for (int i = 0; i < 1000000; i++) {
|
||||
conversionService.convert(source, TypeDescriptor.forObject(source), td);
|
||||
}
|
||||
watch.stop();
|
||||
System.out.println(watch.prettyPrint());
|
||||
}
|
||||
|
||||
public static Map<String, Integer> map;
|
||||
|
||||
private interface MyBaseInterface {
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue