fixed HTTP invoker to support resolution of multi-level primitive array classes again

This commit is contained in:
Juergen Hoeller 2009-02-17 17:50:14 +00:00
parent 57874a6050
commit 35c36dda4b
4 changed files with 103 additions and 18 deletions

View File

@ -39,9 +39,9 @@ import java.util.Set;
* framework; consider Jakarta's Commons Lang for a more comprehensive suite
* of class utilities.
*
* @author Juergen Hoeller
* @author Keith Donald
* @author Rob Harrop
* @author Juergen Hoeller
* @since 1.1
* @see TypeUtils
* @see ReflectionUtils
@ -51,8 +51,11 @@ public abstract class ClassUtils {
/** Suffix for array class names: "[]" */
public static final String ARRAY_SUFFIX = "[]";
/** Prefix for internal array class names: "[L" */
private static final String INTERNAL_ARRAY_PREFIX = "[L";
/** Prefix for internal array class names: "[" */
private static final String INTERNAL_ARRAY_PREFIX = "[";
/** Prefix for internal non-primitive array class names: "[L" */
private static final String NON_PRIMITIVE_ARRAY_PREFIX = "[L";
/** The package separator character '.' */
private static final char PACKAGE_SEPARATOR = '.';
@ -85,6 +88,12 @@ public abstract class ClassUtils {
*/
private static final Map<String, Class> primitiveTypeNameMap = new HashMap<String, Class>(16);
/**
* Map with common "java.lang" class name as key and corresponding Class as value.
* Primarily for efficient deserialization of remote invocations.
*/
private static final Map<String, Class> commonClassCache = new HashMap<String, Class>(32);
static {
primitiveWrapperTypeMap.put(Boolean.class, boolean.class);
@ -98,6 +107,7 @@ public abstract class ClassUtils {
for (Map.Entry<Class, Class> entry : primitiveWrapperTypeMap.entrySet()) {
primitiveTypeToWrapperMap.put(entry.getValue(), entry.getKey());
registerCommonClasses(entry.getKey());
}
Set<Class> primitiveTypes = new HashSet<Class>(16);
@ -108,9 +118,25 @@ public abstract class ClassUtils {
for (Class primitiveType : primitiveTypes) {
primitiveTypeNameMap.put(primitiveType.getName(), primitiveType);
}
registerCommonClasses(Boolean[].class, Byte[].class, Character[].class, Double[].class,
Float[].class, Integer[].class, Long[].class, Short[].class);
registerCommonClasses(Number.class, Number[].class, String.class, String[].class,
Object.class, Object[].class, Class.class, Class[].class);
registerCommonClasses(Throwable.class, Exception.class, RuntimeException.class,
Error.class, StackTraceElement.class, StackTraceElement[].class);
}
/**
* Register the given common classes with the ClassUtils cache.
*/
private static void registerCommonClasses(Class... commonClasses) {
for (Class clazz : commonClasses) {
commonClassCache.put(clazz.getName(), clazz);
}
}
/**
* Return the default ClassLoader to use: typically the thread context
* ClassLoader, if available; the ClassLoader that loaded the ClassUtils
@ -188,6 +214,9 @@ public abstract class ClassUtils {
Assert.notNull(name, "Name must not be null");
Class clazz = resolvePrimitiveClassName(name);
if (clazz == null) {
clazz = commonClassCache.get(name);
}
if (clazz != null) {
return clazz;
}
@ -200,16 +229,16 @@ public abstract class ClassUtils {
}
// "[Ljava.lang.String;" style arrays
int internalArrayMarker = name.indexOf(INTERNAL_ARRAY_PREFIX);
if (internalArrayMarker != -1 && name.endsWith(";")) {
String elementClassName = null;
if (internalArrayMarker == 0) {
elementClassName = name.substring(INTERNAL_ARRAY_PREFIX.length(), name.length() - 1);
}
else if (name.startsWith("[")) {
elementClassName = name.substring(1);
}
Class elementClass = forName(elementClassName, classLoader);
if (name.startsWith(NON_PRIMITIVE_ARRAY_PREFIX) && name.endsWith(";")) {
String elementName = name.substring(NON_PRIMITIVE_ARRAY_PREFIX.length(), name.length() - 1);
Class elementClass = forName(elementName, classLoader);
return Array.newInstance(elementClass, 0).getClass();
}
// "[[I" or "[[Ljava.lang.String;" style arrays
if (name.startsWith(INTERNAL_ARRAY_PREFIX)) {
String elementName = name.substring(INTERNAL_ARRAY_PREFIX.length());
Class elementClass = forName(elementName, classLoader);
return Array.newInstance(elementClass, 0).getClass();
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2007 the original author or authors.
* Copyright 2002-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -47,6 +47,22 @@ public interface ITestBean {
void setStringArray(String[] stringArray);
Integer[][] getNestedIntegerArray();
Integer[] getSomeIntegerArray();
void setSomeIntegerArray(Integer[] someIntegerArray);
void setNestedIntegerArray(Integer[][] nestedIntegerArray);
int[] getSomeIntArray();
void setSomeIntArray(int[] someIntArray);
int[][] getNestedIntArray();
void setNestedIntArray(int[][] someNestedArray);
/**
* Throws a given (non-null) exception.
*/

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2008 the original author or authors.
* Copyright 2002-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -66,6 +66,12 @@ public class TestBean implements BeanNameAware, BeanFactoryAware, ITestBean, IOt
private Integer[] someIntegerArray;
private Integer[][] nestedIntegerArray;
private int[] someIntArray;
private int[][] nestedIntArray;
private Date date = new Date();
private Float myFloat = new Float(0.0);
@ -98,7 +104,6 @@ public class TestBean implements BeanNameAware, BeanFactoryAware, ITestBean, IOt
private List pets;
public TestBean() {
}
@ -246,6 +251,30 @@ public class TestBean implements BeanNameAware, BeanFactoryAware, ITestBean, IOt
this.someIntegerArray = someIntegerArray;
}
public Integer[][] getNestedIntegerArray() {
return nestedIntegerArray;
}
public void setNestedIntegerArray(Integer[][] nestedIntegerArray) {
this.nestedIntegerArray = nestedIntegerArray;
}
public int[] getSomeIntArray() {
return someIntArray;
}
public void setSomeIntArray(int[] someIntArray) {
this.someIntArray = someIntArray;
}
public int[][] getNestedIntArray() {
return nestedIntArray;
}
public void setNestedIntArray(int[][] nestedIntArray) {
this.nestedIntArray = nestedIntArray;
}
public Date getDate() {
return date;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2007 the original author or authors.
* Copyright 2002-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -28,7 +28,6 @@ import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@ -97,6 +96,18 @@ public class HttpInvokerTests extends TestCase {
assertEquals(50, proxy.getAge());
proxy.setStringArray(new String[] {"str1", "str2"});
assertTrue(Arrays.equals(new String[] {"str1", "str2"}, proxy.getStringArray()));
proxy.setSomeIntegerArray(new Integer[] {1, 2, 3});
assertTrue(Arrays.equals(new Integer[] {1, 2, 3}, proxy.getSomeIntegerArray()));
proxy.setNestedIntegerArray(new Integer[][] {{1, 2, 3}, {4, 5, 6}});
Integer[][] integerArray = proxy.getNestedIntegerArray();
assertTrue(Arrays.equals(new Integer[] {1, 2, 3}, integerArray[0]));
assertTrue(Arrays.equals(new Integer[] {4, 5, 6}, integerArray[1]));
proxy.setSomeIntArray(new int[] {1, 2, 3});
assertTrue(Arrays.equals(new int[] {1, 2, 3}, proxy.getSomeIntArray()));
proxy.setNestedIntArray(new int[][] {{1, 2, 3}, {4, 5, 6}});
int[][] intArray = proxy.getNestedIntArray();
assertTrue(Arrays.equals(new int[] {1, 2, 3}, intArray[0]));
assertTrue(Arrays.equals(new int[] {4, 5, 6}, intArray[1]));
try {
proxy.exceptional(new IllegalStateException());