Browse Source

caching optmizations and performance tests

pull/23217/head
Keith Donald 15 years ago
parent
commit
e60389283d
  1. 165
      org.springframework.core/src/main/java/org/springframework/core/convert/TypeDescriptor.java
  2. 64
      org.springframework.core/src/test/java/org/springframework/core/convert/support/GenericConversionServiceTests.java

165
org.springframework.core/src/main/java/org/springframework/core/convert/TypeDescriptor.java

@ -73,6 +73,12 @@ public class TypeDescriptor { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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;
}
/**

64
org.springframework.core/src/test/java/org/springframework/core/convert/support/GenericConversionServiceTests.java

@ -16,19 +16,27 @@ @@ -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 { @@ -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…
Cancel
Save