Browse Source

Polishing

pull/457/head
Juergen Hoeller 12 years ago
parent
commit
426f52b393
  1. 27
      spring-context/src/test/java/org/springframework/aop/framework/CglibProxyTests.java
  2. 10
      spring-core/src/main/java/org/springframework/core/ResolvableType.java
  3. 21
      spring-core/src/main/java/org/springframework/util/ConcurrentReferenceHashMap.java
  4. 31
      spring-core/src/main/java/org/springframework/util/CustomizableThreadCreator.java
  5. 25
      spring-core/src/main/java/org/springframework/util/ReflectionUtils.java
  6. 46
      spring-expression/src/test/java/org/springframework/expression/spel/MapAccessTests.java

27
spring-context/src/test/java/org/springframework/aop/framework/CglibProxyTests.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2013 the original author or authors. * Copyright 2002-2014 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -21,6 +21,8 @@ import java.io.Serializable;
import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation; import org.aopalliance.intercept.MethodInvocation;
import org.junit.Test; import org.junit.Test;
import test.mixin.LockMixinAdvisor;
import org.springframework.aop.ClassFilter; import org.springframework.aop.ClassFilter;
import org.springframework.aop.MethodMatcher; import org.springframework.aop.MethodMatcher;
import org.springframework.aop.Pointcut; import org.springframework.aop.Pointcut;
@ -34,7 +36,6 @@ import org.springframework.tests.aop.interceptor.NopInterceptor;
import org.springframework.tests.sample.beans.ITestBean; import org.springframework.tests.sample.beans.ITestBean;
import org.springframework.tests.sample.beans.TestBean; import org.springframework.tests.sample.beans.TestBean;
import test.mixin.LockMixinAdvisor;
import static org.hamcrest.CoreMatchers.*; import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*; import static org.junit.Assert.*;
@ -140,9 +141,7 @@ public final class CglibProxyTests extends AbstractAopProxyTests implements Seri
AopProxy aop = new CglibAopProxy(as); AopProxy aop = new CglibAopProxy(as);
CglibTestBean proxy = (CglibTestBean) aop.getProxy(); CglibTestBean proxy = (CglibTestBean) aop.getProxy();
assertEquals("The name property has been overwritten by the constructor", "Rob Harrop", proxy.getName());
assertEquals("The name property has been overwritten by the constructor",
"Rob Harrop", proxy.getName());
} }
@Test @Test
@ -155,9 +154,7 @@ public final class CglibProxyTests extends AbstractAopProxyTests implements Seri
pc.setTarget(target); pc.setTarget(target);
CglibAopProxy aop = new CglibAopProxy(pc); CglibAopProxy aop = new CglibAopProxy(pc);
CglibTestBean proxy = (CglibTestBean) aop.getProxy(); CglibTestBean proxy = (CglibTestBean) aop.getProxy();
assertNotNull("Proxy should not be null", proxy); assertNotNull("Proxy should not be null", proxy);
assertEquals("Constructor overrode the value of name", "Rob Harrop", proxy.getName()); assertEquals("Constructor overrode the value of name", "Rob Harrop", proxy.getName());
@ -187,21 +184,18 @@ public final class CglibProxyTests extends AbstractAopProxyTests implements Seri
public ClassFilter getClassFilter() { public ClassFilter getClassFilter() {
return ClassFilter.TRUE; return ClassFilter.TRUE;
} }
@Override @Override
public MethodMatcher getMethodMatcher() { public MethodMatcher getMethodMatcher() {
return MethodMatcher.TRUE; return MethodMatcher.TRUE;
} }
@Override
public int hashCode() {
return 0;
}
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
return true; return true;
} }
@Override
public int hashCode() {
return 0;
}
}; };
pf.addAdvisor(new DefaultPointcutAdvisor(pointcut, advice)); pf.addAdvisor(new DefaultPointcutAdvisor(pointcut, advice));
@ -225,7 +219,7 @@ public final class CglibProxyTests extends AbstractAopProxyTests implements Seri
} }
private ITestBean getIntroductionAdvisorProxy(TestBean target) { private ITestBean getIntroductionAdvisorProxy(TestBean target) {
ProxyFactory pf = new ProxyFactory(new Class<?>[]{ITestBean.class}); ProxyFactory pf = new ProxyFactory(new Class<?>[] {ITestBean.class});
pf.setProxyTargetClass(true); pf.setProxyTargetClass(true);
pf.addAdvisor(new LockMixinAdvisor()); pf.addAdvisor(new LockMixinAdvisor());
@ -245,8 +239,7 @@ public final class CglibProxyTests extends AbstractAopProxyTests implements Seri
AdvisedSupport pc = new AdvisedSupport(new Class<?>[]{}); AdvisedSupport pc = new AdvisedSupport(new Class<?>[]{});
pc.setTargetSource(mockTargetSource); pc.setTargetSource(mockTargetSource);
CglibAopProxy aop = new CglibAopProxy(pc); CglibAopProxy aop = new CglibAopProxy(pc);
aop.setConstructorArguments(new Object[] {"Rob Harrop", new Integer(22)}, aop.setConstructorArguments(new Object[] {"Rob Harrop", 22}, new Class<?>[] {String.class, int.class});
new Class<?>[] {String.class, int.class});
NoArgCtorTestBean proxy = (NoArgCtorTestBean) aop.getProxy(); NoArgCtorTestBean proxy = (NoArgCtorTestBean) aop.getProxy();
proxy = (NoArgCtorTestBean) aop.getProxy(); proxy = (NoArgCtorTestBean) aop.getProxy();

10
spring-core/src/main/java/org/springframework/core/ResolvableType.java

@ -77,19 +77,17 @@ import org.springframework.util.StringUtils;
@SuppressWarnings("serial") @SuppressWarnings("serial")
public final class ResolvableType implements Serializable { public final class ResolvableType implements Serializable {
private static ConcurrentReferenceHashMap<ResolvableType, ResolvableType> cache =
new ConcurrentReferenceHashMap<ResolvableType, ResolvableType>();
/** /**
* {@code ResolvableType} returned when no value is available. {@code NONE} is used * {@code ResolvableType} returned when no value is available. {@code NONE} is used
* in preference to {@code null} so that multiple method calls can be safely chained. * in preference to {@code null} so that multiple method calls can be safely chained.
*/ */
public static final ResolvableType NONE = new ResolvableType(null, null, null, null); public static final ResolvableType NONE = new ResolvableType(null, null, null, null);
private static final ResolvableType[] EMPTY_TYPES_ARRAY = new ResolvableType[0]; private static final ResolvableType[] EMPTY_TYPES_ARRAY = new ResolvableType[0];
private static final ConcurrentReferenceHashMap<ResolvableType, ResolvableType> cache =
new ConcurrentReferenceHashMap<ResolvableType, ResolvableType>(256);
/** /**
* The underlying Java type being managed (only ever {@code null} for {@link #NONE}). * The underlying Java type being managed (only ever {@code null} for {@link #NONE}).
@ -1085,7 +1083,7 @@ public final class ResolvableType implements Serializable {
* @see #forType(Type, ResolvableType) * @see #forType(Type, ResolvableType)
*/ */
public static ResolvableType forType(Type type) { public static ResolvableType forType(Type type) {
return forType(type, (VariableResolver) null); return forType(type, null, null);
} }
/** /**

21
spring-core/src/main/java/org/springframework/util/ConcurrentReferenceHashMap.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2013 the original author or authors. * Copyright 2002-2014 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -132,6 +132,15 @@ public class ConcurrentReferenceHashMap<K, V> extends AbstractMap<K, V> implemen
this(initialCapacity, DEFAULT_LOAD_FACTOR, concurrencyLevel, DEFAULT_REFERENCE_TYPE); this(initialCapacity, DEFAULT_LOAD_FACTOR, concurrencyLevel, DEFAULT_REFERENCE_TYPE);
} }
/**
* Create a new {@code ConcurrentReferenceHashMap} instance.
* @param initialCapacity the initial capacity of the map
* @param referenceType the reference type used for entries (soft or weak)
*/
public ConcurrentReferenceHashMap(int initialCapacity, ReferenceType referenceType) {
this(initialCapacity, DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL, referenceType);
}
/** /**
* Create a new {@code ConcurrentReferenceHashMap} instance. * Create a new {@code ConcurrentReferenceHashMap} instance.
* @param initialCapacity the initial capacity of the map * @param initialCapacity the initial capacity of the map
@ -151,7 +160,7 @@ public class ConcurrentReferenceHashMap<K, V> extends AbstractMap<K, V> implemen
* table exceeds this value, resize will be attempted. * table exceeds this value, resize will be attempted.
* @param concurrencyLevel the expected number of threads that will concurrently * @param concurrencyLevel the expected number of threads that will concurrently
* write to the map * write to the map
* @param referenceType the reference type used for entries * @param referenceType the reference type used for entries (soft or weak)
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public ConcurrentReferenceHashMap(int initialCapacity, float loadFactor, int concurrencyLevel, public ConcurrentReferenceHashMap(int initialCapacity, float loadFactor, int concurrencyLevel,
@ -165,10 +174,10 @@ public class ConcurrentReferenceHashMap<K, V> extends AbstractMap<K, V> implemen
this.shift = calculateShift(concurrencyLevel, MAXIMUM_CONCURRENCY_LEVEL); this.shift = calculateShift(concurrencyLevel, MAXIMUM_CONCURRENCY_LEVEL);
int size = 1 << this.shift; int size = 1 << this.shift;
this.referenceType = referenceType; this.referenceType = referenceType;
int roundedUpSegmentCapactity = (int) ((initialCapacity + size - 1L) / size); int roundedUpSegmentCapacity = (int) ((initialCapacity + size - 1L) / size);
this.segments = (Segment[]) Array.newInstance(Segment.class, size); this.segments = (Segment[]) Array.newInstance(Segment.class, size);
for (int i = 0; i < this.segments.length; i++) { for (int i = 0; i < this.segments.length; i++) {
this.segments[i] = new Segment(roundedUpSegmentCapactity); this.segments[i] = new Segment(roundedUpSegmentCapacity);
} }
} }
@ -186,8 +195,8 @@ public class ConcurrentReferenceHashMap<K, V> extends AbstractMap<K, V> implemen
} }
/** /**
* Factory method that returns the {@link ReferenceManager}. This method will be * Factory method that returns the {@link ReferenceManager}.
* called once for each {@link Segment}. * This method will be called once for each {@link Segment}.
* @return a new reference manager * @return a new reference manager
*/ */
protected ReferenceManager createReferenceManager() { protected ReferenceManager createReferenceManager() {

31
spring-core/src/main/java/org/springframework/util/CustomizableThreadCreator.java

@ -20,8 +20,8 @@ import java.io.Serializable;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
/** /**
* Simple customizable helper class for creating threads. Provides various * Simple customizable helper class for creating new {@link Thread} instances.
* bean properties, such as thread name prefix, thread priority, etc. * Provides various bean properties: thread name prefix, thread priority, etc.
* *
* <p>Serves as base class for thread factories such as * <p>Serves as base class for thread factories such as
* {@link org.springframework.scheduling.concurrent.CustomizableThreadFactory}. * {@link org.springframework.scheduling.concurrent.CustomizableThreadFactory}.
@ -41,7 +41,7 @@ public class CustomizableThreadCreator implements Serializable {
private ThreadGroup threadGroup; private ThreadGroup threadGroup;
private final AtomicInteger threadCount = new AtomicInteger(); private final AtomicInteger threadCount = new AtomicInteger(0);
/** /**
@ -95,11 +95,11 @@ public class CustomizableThreadCreator implements Serializable {
/** /**
* Set whether this factory is supposed to create daemon threads, * Set whether this factory is supposed to create daemon threads,
* just executing as long as the application itself is running. * just executing as long as the application itself is running.
* <p>Default is "false": Concrete factories usually support explicit * <p>Default is "false": Concrete factories usually support explicit cancelling.
* cancelling. Hence, if the application shuts down, Runnables will * Hence, if the application shuts down, Runnables will by default finish their
* by default finish their execution. * execution.
* <p>Specify "true" for eager shutdown of threads which still * <p>Specify "true" for eager shutdown of threads which still actively execute
* actively execute a Runnable. * a {@link Runnable} at the time that the application itself shuts down.
* @see java.lang.Thread#setDaemon * @see java.lang.Thread#setDaemon
*/ */
public void setDaemon(boolean daemon) { public void setDaemon(boolean daemon) {
@ -131,7 +131,7 @@ public class CustomizableThreadCreator implements Serializable {
/** /**
* Return the thread group that threads should be created in * Return the thread group that threads should be created in
* (or {@code null}) for the default group. * (or {@code null} for the default group).
*/ */
public ThreadGroup getThreadGroup() { public ThreadGroup getThreadGroup() {
return this.threadGroup; return this.threadGroup;
@ -139,9 +139,9 @@ public class CustomizableThreadCreator implements Serializable {
/** /**
* Template method for the creation of a Thread. * Template method for the creation of a new {@link Thread}.
* <p>Default implementation creates a new Thread for the given * <p>The default implementation creates a new Thread for the given
* Runnable, applying an appropriate thread name. * {@link Runnable}, applying an appropriate thread name.
* @param runnable the Runnable to execute * @param runnable the Runnable to execute
* @see #nextThreadName() * @see #nextThreadName()
*/ */
@ -153,10 +153,9 @@ public class CustomizableThreadCreator implements Serializable {
} }
/** /**
* Return the thread name to use for a newly created thread. * Return the thread name to use for a newly created {@link Thread}.
* <p>Default implementation returns the specified thread name prefix * <p>The default implementation returns the specified thread name prefix
* with an increasing thread count appended: for example, * with an increasing thread count appended: e.g. "SimpleAsyncTaskExecutor-0".
* "SimpleAsyncTaskExecutor-0".
* @see #getThreadNamePrefix() * @see #getThreadNamePrefix()
*/ */
protected String nextThreadName() { protected String nextThreadName() {

25
spring-core/src/main/java/org/springframework/util/ReflectionUtils.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2013 the original author or authors. * Copyright 2002-2014 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -44,8 +44,13 @@ import java.util.regex.Pattern;
*/ */
public abstract class ReflectionUtils { public abstract class ReflectionUtils {
/**
* Pattern for detecting CGLIB-renamed methods.
* @see #isCglibRenamedMethod
*/
private static final Pattern CGLIB_RENAMED_METHOD_PATTERN = Pattern.compile("CGLIB\\$(.+)\\$\\d+"); private static final Pattern CGLIB_RENAMED_METHOD_PATTERN = Pattern.compile("CGLIB\\$(.+)\\$\\d+");
/** /**
* Attempt to find a {@link Field field} on the supplied {@link Class} with the * Attempt to find a {@link Field field} on the supplied {@link Class} with the
* supplied {@code name}. Searches all superclasses up to {@link Object}. * supplied {@code name}. Searches all superclasses up to {@link Object}.
@ -373,19 +378,21 @@ public abstract class ReflectionUtils {
* Determine whether the given method is originally declared by {@link java.lang.Object}. * Determine whether the given method is originally declared by {@link java.lang.Object}.
*/ */
public static boolean isObjectMethod(Method method) { public static boolean isObjectMethod(Method method) {
if (method == null) {
return false;
}
try { try {
Object.class.getDeclaredMethod(method.getName(), method.getParameterTypes()); Object.class.getDeclaredMethod(method.getName(), method.getParameterTypes());
return true; return true;
} catch (SecurityException ex) { }
return false; catch (Exception ex) {
} catch (NoSuchMethodException ex) {
return false; return false;
} }
} }
/** /**
* Determine whether the given method is a CGLIB 'renamed' method, following * Determine whether the given method is a CGLIB 'renamed' method,
* the pattern "CGLIB$methodName$0". * following the pattern "CGLIB$methodName$0".
* @param renamedMethod the method to check * @param renamedMethod the method to check
* @see org.springframework.cglib.proxy.Enhancer#rename * @see org.springframework.cglib.proxy.Enhancer#rename
*/ */
@ -514,15 +521,15 @@ public abstract class ReflectionUtils {
public void doWith(Method method) { public void doWith(Method method) {
boolean knownSignature = false; boolean knownSignature = false;
Method methodBeingOverriddenWithCovariantReturnType = null; Method methodBeingOverriddenWithCovariantReturnType = null;
for (Method existingMethod : methods) { for (Method existingMethod : methods) {
if (method.getName().equals(existingMethod.getName()) && if (method.getName().equals(existingMethod.getName()) &&
Arrays.equals(method.getParameterTypes(), existingMethod.getParameterTypes())) { Arrays.equals(method.getParameterTypes(), existingMethod.getParameterTypes())) {
// is this a covariant return type situation? // Is this a covariant return type situation?
if (existingMethod.getReturnType() != method.getReturnType() && if (existingMethod.getReturnType() != method.getReturnType() &&
existingMethod.getReturnType().isAssignableFrom(method.getReturnType())) { existingMethod.getReturnType().isAssignableFrom(method.getReturnType())) {
methodBeingOverriddenWithCovariantReturnType = existingMethod; methodBeingOverriddenWithCovariantReturnType = existingMethod;
} else { }
else {
knownSignature = true; knownSignature = true;
} }
break; break;

46
spring-expression/src/test/java/org/springframework/expression/spel/MapAccessTests.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2013 the original author or authors. * Copyright 2002-2014 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,13 +16,11 @@
package org.springframework.expression.spel; package org.springframework.expression.spel;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import org.junit.Test; import org.junit.Test;
import org.springframework.expression.AccessException; import org.springframework.expression.AccessException;
import org.springframework.expression.EvaluationContext; import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression; import org.springframework.expression.Expression;
@ -32,6 +30,8 @@ import org.springframework.expression.TypedValue;
import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext; import org.springframework.expression.spel.support.StandardEvaluationContext;
import static org.junit.Assert.*;
/** /**
* Testing variations on map access. * Testing variations on map access.
* *
@ -73,64 +73,60 @@ public class MapAccessTests extends ExpressionTestCase {
@Test @Test
public void testGetValue(){ public void testGetValue(){
Map<String,String> props1 = new HashMap<String,String>();
Map props1= new HashMap<String,String>();
props1.put("key1", "value1"); props1.put("key1", "value1");
props1.put("key2", "value2"); props1.put("key2", "value2");
props1.put("key3", "value3"); props1.put("key3", "value3");
Object bean = new TestBean("name1", new TestBean("name2", null, "Description 2", 15, props1), "description 1", 6, props1);
Object bean = new TestBean("name1",new TestBean("name2",null,"Description 2",15,props1),"description 1", 6,props1);
ExpressionParser parser = new SpelExpressionParser(); ExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression("testBean.properties['key2']"); Expression exp = parser.parseExpression("testBean.properties['key2']");
String key = (String) exp.getValue(bean); String key = (String) exp.getValue(bean);
assertNotNull(key); assertNotNull(key);
} }
public static class TestBean
{ public static class TestBean {
private String name; private String name;
private TestBean testBean; private TestBean testBean;
private String description; private String description;
private Integer priority; private Integer priority;
private Map properties; private Map<String, String> properties;
public TestBean(String name, TestBean testBean, String description, Integer priority, Map<String, String> props) {
public TestBean() {
super();
}
public TestBean(String name, TestBean testBean, String description,Integer priority,Map props) {
super();
this.name = name; this.name = name;
this.testBean = testBean; this.testBean = testBean;
this.description = description; this.description = description;
this.priority=priority; this.priority = priority;
this.properties=props; this.properties = props;
} }
public String getName() { public String getName() {
return name; return name;
} }
public void setName(String name) { public void setName(String name) {
this.name = name; this.name = name;
} }
public TestBean getTestBean() { public TestBean getTestBean() {
return testBean; return testBean;
} }
public void setTestBean(TestBean testBean) { public void setTestBean(TestBean testBean) {
this.testBean = testBean; this.testBean = testBean;
} }
public String getDescription() { public String getDescription() {
return description; return description;
} }
public void setDescription(String description) { public void setDescription(String description) {
this.description = description; this.description = description;
} }
public Integer getPriority() { public Integer getPriority() {
return priority; return priority;
} }
@ -168,16 +164,14 @@ public class MapAccessTests extends ExpressionTestCase {
@Override @Override
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public void write(EvaluationContext context, Object target, String name, Object newValue) public void write(EvaluationContext context, Object target, String name, Object newValue) throws AccessException {
throws AccessException {
((Map) target).put(name, newValue); ((Map) target).put(name, newValue);
} }
@Override @Override
public Class<?>[] getSpecificTargetClasses() { public Class<?>[] getSpecificTargetClasses() {
return new Class[] { Map.class }; return new Class<?>[] {Map.class};
} }
} }
} }

Loading…
Cancel
Save