diff --git a/spring-aop/src/main/java/org/springframework/aop/support/ControlFlowPointcut.java b/spring-aop/src/main/java/org/springframework/aop/support/ControlFlowPointcut.java index 1989a6dae41..47d201cfcd0 100644 --- a/spring-aop/src/main/java/org/springframework/aop/support/ControlFlowPointcut.java +++ b/spring-aop/src/main/java/org/springframework/aop/support/ControlFlowPointcut.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2017 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. @@ -22,8 +22,6 @@ import java.lang.reflect.Method; import org.springframework.aop.ClassFilter; import org.springframework.aop.MethodMatcher; import org.springframework.aop.Pointcut; -import org.springframework.core.ControlFlow; -import org.springframework.core.ControlFlowFactory; import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; @@ -34,7 +32,7 @@ import org.springframework.util.ObjectUtils; * * @author Rod Johnson * @author Rob Harrop - * @see org.springframework.core.ControlFlow + * @author Juergen Hoeller */ @SuppressWarnings("serial") public class ControlFlowPointcut implements Pointcut, ClassFilter, MethodMatcher, Serializable { @@ -43,7 +41,7 @@ public class ControlFlowPointcut implements Pointcut, ClassFilter, MethodMatcher private String methodName; - private int evaluations; + private volatile int evaluations; /** @@ -55,11 +53,11 @@ public class ControlFlowPointcut implements Pointcut, ClassFilter, MethodMatcher } /** - * Construct a new pointcut that matches all calls below the - * given method in the given class. If the method name is null, - * matches all control flows below that class. + * Construct a new pointcut that matches all calls below the given method + * in the given class. If no method name is given, matches all control flows + * below the given class. * @param clazz the clazz - * @param methodName the name of the method + * @param methodName the name of the method (may be {@code null}) */ public ControlFlowPointcut(Class clazz, String methodName) { Assert.notNull(clazz, "Class must not be null"); @@ -93,8 +91,14 @@ public class ControlFlowPointcut implements Pointcut, ClassFilter, MethodMatcher @Override public boolean matches(Method method, Class targetClass, Object... args) { this.evaluations++; - ControlFlow cflow = ControlFlowFactory.createControlFlow(); - return (this.methodName != null ? cflow.under(this.clazz, this.methodName) : cflow.under(this.clazz)); + + for (StackTraceElement element : new Throwable().getStackTrace()) { + if (element.getClassName().equals(this.clazz.getName()) && + (this.methodName == null || element.getMethodName().equals(this.methodName))) { + return true; + } + } + return false; } /** @@ -130,8 +134,7 @@ public class ControlFlowPointcut implements Pointcut, ClassFilter, MethodMatcher @Override public int hashCode() { - int code = 17; - code = 37 * code + this.clazz.hashCode(); + int code = this.clazz.hashCode(); if (this.methodName != null) { code = 37 * code + this.methodName.hashCode(); } diff --git a/spring-beans/src/main/java/org/springframework/beans/PropertyAccessException.java b/spring-beans/src/main/java/org/springframework/beans/PropertyAccessException.java index 68bdde7412f..07cbb3d5bcf 100644 --- a/spring-beans/src/main/java/org/springframework/beans/PropertyAccessException.java +++ b/spring-beans/src/main/java/org/springframework/beans/PropertyAccessException.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2017 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. @@ -18,8 +18,6 @@ package org.springframework.beans; import java.beans.PropertyChangeEvent; -import org.springframework.core.ErrorCoded; - /** * Superclass for exceptions related to a property access, * such as type mismatch or invocation target exception. @@ -28,7 +26,7 @@ import org.springframework.core.ErrorCoded; * @author Juergen Hoeller */ @SuppressWarnings("serial") -public abstract class PropertyAccessException extends BeansException implements ErrorCoded { +public abstract class PropertyAccessException extends BeansException { private transient PropertyChangeEvent propertyChangeEvent; @@ -77,4 +75,9 @@ public abstract class PropertyAccessException extends BeansException implements return (this.propertyChangeEvent != null ? this.propertyChangeEvent.getNewValue() : null); } + /** + * Return a corresponding error code for this type of exception. + */ + public abstract String getErrorCode(); + } diff --git a/spring-core/src/main/java/org/springframework/core/ConstantException.java b/spring-core/src/main/java/org/springframework/core/ConstantException.java deleted file mode 100644 index 451b46b8573..00000000000 --- a/spring-core/src/main/java/org/springframework/core/ConstantException.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2002-2012 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. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.core; - -/** - * Exception thrown when the {@link Constants} class is asked for - * an invalid constant name. - * - * @author Rod Johnson - * @since 28.04.2003 - * @see org.springframework.core.Constants - */ -@SuppressWarnings("serial") -public class ConstantException extends IllegalArgumentException { - - /** - * Thrown when an invalid constant name is requested. - * @param className name of the class containing the constant definitions - * @param field invalid constant name - * @param message description of the problem - */ - public ConstantException(String className, String field, String message) { - super("Field '" + field + "' " + message + " in class [" + className + "]"); - } - - /** - * Thrown when an invalid constant value is looked up. - * @param className name of the class containing the constant definitions - * @param namePrefix prefix of the searched constant names - * @param value the looked up constant value - */ - public ConstantException(String className, String namePrefix, Object value) { - super("No '" + namePrefix + "' field with value '" + value + "' found in class [" + className + "]"); - } - -} diff --git a/spring-core/src/main/java/org/springframework/core/Constants.java b/spring-core/src/main/java/org/springframework/core/Constants.java index 16df5584b3e..4b9d6936c6f 100644 --- a/spring-core/src/main/java/org/springframework/core/Constants.java +++ b/spring-core/src/main/java/org/springframework/core/Constants.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2017 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. @@ -333,4 +333,33 @@ public class Constants { return parsedPrefix.toString(); } + + /** + * Exception thrown when the {@link Constants} class is asked for + * an invalid constant name. + */ + @SuppressWarnings("serial") + public static class ConstantException extends IllegalArgumentException { + + /** + * Thrown when an invalid constant name is requested. + * @param className name of the class containing the constant definitions + * @param field invalid constant name + * @param message description of the problem + */ + public ConstantException(String className, String field, String message) { + super("Field '" + field + "' " + message + " in class [" + className + "]"); + } + + /** + * Thrown when an invalid constant value is looked up. + * @param className name of the class containing the constant definitions + * @param namePrefix prefix of the searched constant names + * @param value the looked up constant value + */ + public ConstantException(String className, String namePrefix, Object value) { + super("No '" + namePrefix + "' field with value '" + value + "' found in class [" + className + "]"); + } + } + } diff --git a/spring-core/src/main/java/org/springframework/core/ControlFlow.java b/spring-core/src/main/java/org/springframework/core/ControlFlow.java deleted file mode 100644 index a650c6cb400..00000000000 --- a/spring-core/src/main/java/org/springframework/core/ControlFlow.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2002-2012 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. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.core; - -/** - * Interface to be implemented by objects that can return information about - * the current call stack. Useful in AOP (as in AspectJ cflow concept) - * but not AOP-specific. - * - * @author Rod Johnson - * @since 02.02.2004 - */ -public interface ControlFlow { - - /** - * Detect whether we're under the given class, - * according to the current stack trace. - * @param clazz the clazz to look for - */ - boolean under(Class clazz); - - /** - * Detect whether we're under the given class and method, - * according to the current stack trace. - * @param clazz the clazz to look for - * @param methodName the name of the method to look for - */ - boolean under(Class clazz, String methodName); - - /** - * Detect whether the current stack trace contains the given token. - * @param token the token to look for - */ - boolean underToken(String token); - -} diff --git a/spring-core/src/main/java/org/springframework/core/ControlFlowFactory.java b/spring-core/src/main/java/org/springframework/core/ControlFlowFactory.java deleted file mode 100644 index 167de0f7e00..00000000000 --- a/spring-core/src/main/java/org/springframework/core/ControlFlowFactory.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright 2002-2012 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. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.core; - -import java.io.PrintWriter; -import java.io.StringWriter; - -import org.springframework.util.Assert; - -/** - * Static factory to conceal the automatic choice of the ControlFlow - * implementation class. - * - *

This implementation always uses the efficient Java 1.4 StackTraceElement - * mechanism for analyzing control flows. - * - * @author Rod Johnson - * @author Juergen Hoeller - * @since 02.02.2004 - */ -public abstract class ControlFlowFactory { - - /** - * Return an appropriate {@link ControlFlow} instance. - */ - public static ControlFlow createControlFlow() { - return new Jdk14ControlFlow(); - } - - - /** - * Utilities for cflow-style pointcuts. Note that such pointcuts are - * 5-10 times more expensive to evaluate than other pointcuts, as they require - * analysis of the stack trace (through constructing a new throwable). - * However, they are useful in some cases. - *

This implementation uses the StackTraceElement class introduced in Java 1.4. - * @see java.lang.StackTraceElement - */ - static class Jdk14ControlFlow implements ControlFlow { - - private StackTraceElement[] stack; - - public Jdk14ControlFlow() { - this.stack = new Throwable().getStackTrace(); - } - - /** - * Searches for class name match in a StackTraceElement. - */ - @Override - public boolean under(Class clazz) { - Assert.notNull(clazz, "Class must not be null"); - String className = clazz.getName(); - for (int i = 0; i < stack.length; i++) { - if (this.stack[i].getClassName().equals(className)) { - return true; - } - } - return false; - } - - /** - * Searches for class name match plus method name match - * in a StackTraceElement. - */ - @Override - public boolean under(Class clazz, String methodName) { - Assert.notNull(clazz, "Class must not be null"); - Assert.notNull(methodName, "Method name must not be null"); - String className = clazz.getName(); - for (int i = 0; i < this.stack.length; i++) { - if (this.stack[i].getClassName().equals(className) && - this.stack[i].getMethodName().equals(methodName)) { - return true; - } - } - return false; - } - - /** - * Leave it up to the caller to decide what matches. - * Caller must understand stack trace format, so there's less abstraction. - */ - @Override - public boolean underToken(String token) { - if (token == null) { - return false; - } - StringWriter sw = new StringWriter(); - new Throwable().printStackTrace(new PrintWriter(sw)); - String stackTrace = sw.toString(); - return stackTrace.indexOf(token) != -1; - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder("Jdk14ControlFlow: "); - for (int i = 0; i < this.stack.length; i++) { - if (i > 0) { - sb.append("\n\t@"); - } - sb.append(this.stack[i]); - } - return sb.toString(); - } - } - -} diff --git a/spring-core/src/main/java/org/springframework/core/ErrorCoded.java b/spring-core/src/main/java/org/springframework/core/ErrorCoded.java deleted file mode 100644 index 1425fe8492a..00000000000 --- a/spring-core/src/main/java/org/springframework/core/ErrorCoded.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2002-2012 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. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.core; - -/** - * Interface that can be implemented by exceptions etc that are error coded. - * The error code is a String, rather than a number, so it can be given - * user-readable values, such as "object.failureDescription". - * - *

An error code can be resolved by a MessageSource, for example. - * - * @author Rod Johnson - * @see org.springframework.context.MessageSource - */ -public interface ErrorCoded { - - /** - * Return the error code associated with this failure. - * The GUI can render this any way it pleases, allowing for localization etc. - * @return a String error code associated with this failure, - * or {@code null} if not error-coded - */ - String getErrorCode(); - -} diff --git a/spring-core/src/main/java/org/springframework/util/WeakReferenceMonitor.java b/spring-core/src/main/java/org/springframework/util/WeakReferenceMonitor.java deleted file mode 100644 index 7d9b698c9a2..00000000000 --- a/spring-core/src/main/java/org/springframework/util/WeakReferenceMonitor.java +++ /dev/null @@ -1,179 +0,0 @@ -/* - * Copyright 2002-2016 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. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.util; - -import java.lang.ref.Reference; -import java.lang.ref.ReferenceQueue; -import java.lang.ref.WeakReference; -import java.util.HashMap; -import java.util.Map; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * Track references to arbitrary objects using proxy and weak references. To - * monitor a handle, one should call {@link #monitor(Object, ReleaseListener)}, - * with the given handle object usually being a holder that uses the target - * object underneath, and the release listener performing cleanup of the - * target object once the handle is not strongly referenced anymore. - * - *

When a given handle becomes weakly reachable, the specified listener - * will be called by a background thread. This thread will only be started - * lazily and will be stopped once no handles are registered for monitoring - * anymore, to be restarted if further handles are added. - * - *

Thanks to Tomasz Wysocki for the suggestion and the original - * implementation of this class! - * - * @author Colin Sampaleanu - * @author Juergen Hoeller - * @since 1.2 - * @see #monitor - */ -public class WeakReferenceMonitor { - - private static final Log logger = LogFactory.getLog(WeakReferenceMonitor.class); - - // Queue receiving reachability events - private static final ReferenceQueue handleQueue = new ReferenceQueue<>(); - - // All tracked entries (WeakReference => ReleaseListener) - private static final Map, ReleaseListener> trackedEntries = new HashMap<>(); - - // Thread polling handleQueue, lazy initialized - private static Thread monitoringThread = null; - - - /** - * Start to monitor given handle object for becoming weakly reachable. - * When the handle isn't used anymore, the given listener will be called. - * @param handle the object that will be monitored - * @param listener the listener that will be called upon release of the handle - */ - public static void monitor(Object handle, ReleaseListener listener) { - if (logger.isDebugEnabled()) { - logger.debug("Monitoring handle [" + handle + "] with release listener [" + listener + "]"); - } - - // Make weak reference to this handle, so we can say when - // handle is not used any more by polling on handleQueue. - WeakReference weakRef = new WeakReference<>(handle, handleQueue); - - // Add monitored entry to internal map of all monitored entries. - addEntry(weakRef, listener); - } - - /** - * Add entry to internal map of tracked entries. - * Internal monitoring thread is started if not already running. - * @param ref reference to tracked handle - * @param entry the associated entry - */ - private static void addEntry(Reference ref, ReleaseListener entry) { - synchronized (WeakReferenceMonitor.class) { - // Add entry, the key is given reference. - trackedEntries.put(ref, entry); - - // Start monitoring thread lazily. - if (monitoringThread == null) { - monitoringThread = new Thread(new MonitoringProcess(), WeakReferenceMonitor.class.getName()); - monitoringThread.setDaemon(true); - monitoringThread.start(); - } - } - } - - /** - * Remove entry from internal map of tracked entries. - * @param reference the reference that should be removed - * @return entry object associated with given reference - */ - private static ReleaseListener removeEntry(Reference reference) { - synchronized (WeakReferenceMonitor.class) { - return trackedEntries.remove(reference); - } - } - - /** - * Check whether to keep the monitoring thread alive, - * i.e. whether there are still entries being tracked. - */ - private static boolean keepMonitoringThreadAlive() { - synchronized (WeakReferenceMonitor.class) { - if (!trackedEntries.isEmpty()) { - return true; - } - else { - logger.debug("No entries left to track - stopping reference monitor thread"); - monitoringThread = null; - return false; - } - } - } - - - /** - * Thread implementation that performs the actual monitoring. - */ - private static class MonitoringProcess implements Runnable { - - @Override - public void run() { - logger.debug("Starting reference monitor thread"); - // Check if there are any tracked entries left. - while (keepMonitoringThreadAlive()) { - try { - Reference reference = handleQueue.remove(); - // Stop tracking this reference. - ReleaseListener entry = removeEntry(reference); - if (entry != null) { - // Invoke listener callback. - try { - entry.released(); - } - catch (Throwable ex) { - logger.warn("Reference release listener threw exception", ex); - } - } - } - catch (InterruptedException ex) { - synchronized (WeakReferenceMonitor.class) { - monitoringThread = null; - } - logger.debug("Reference monitor thread interrupted", ex); - break; - } - } - } - } - - - /** - * Listener that is notified when the handle is being released. - * To be implemented by users of this reference monitor. - */ - public static interface ReleaseListener { - - /** - * This callback method is invoked once the associated handle has been released, - * i.e. once there are no monitored strong references to the handle anymore. - */ - void released(); - } - -} diff --git a/spring-core/src/test/java/org/springframework/core/ConstantsTests.java b/spring-core/src/test/java/org/springframework/core/ConstantsTests.java index d0cd4dee4f6..3f795060149 100644 --- a/spring-core/src/test/java/org/springframework/core/ConstantsTests.java +++ b/spring-core/src/test/java/org/springframework/core/ConstantsTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2017 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. @@ -16,11 +16,11 @@ package org.springframework.core; -import org.junit.Test; - import java.util.Locale; import java.util.Set; +import org.junit.Test; + import static org.junit.Assert.*; /** @@ -45,7 +45,7 @@ public class ConstantsTests { c.asNumber("bogus"); fail("Can't get bogus field"); } - catch (ConstantException expected) { + catch (Constants.ConstantException expected) { } assertTrue(c.asString("S1").equals(A.S1)); @@ -53,7 +53,7 @@ public class ConstantsTests { c.asNumber("S1"); fail("Wrong type"); } - catch (ConstantException expected) { + catch (Constants.ConstantException expected) { } } @@ -170,13 +170,13 @@ public class ConstantsTests { c.toCode("bogus", "bogus"); fail("Should have thrown ConstantException"); } - catch (ConstantException expected) { + catch (Constants.ConstantException expected) { } try { c.toCode("bogus", null); fail("Should have thrown ConstantException"); } - catch (ConstantException expected) { + catch (Constants.ConstantException expected) { } assertEquals(c.toCodeForProperty(new Integer(1), "myProperty"), "MY_PROPERTY_NO"); @@ -185,7 +185,7 @@ public class ConstantsTests { c.toCodeForProperty("bogus", "bogus"); fail("Should have thrown ConstantException"); } - catch (ConstantException expected) { + catch (Constants.ConstantException expected) { } assertEquals(c.toCodeForSuffix(new Integer(0), ""), "DOG"); @@ -206,13 +206,13 @@ public class ConstantsTests { c.toCodeForSuffix("bogus", "bogus"); fail("Should have thrown ConstantException"); } - catch (ConstantException expected) { + catch (Constants.ConstantException expected) { } try { c.toCodeForSuffix("bogus", null); fail("Should have thrown ConstantException"); } - catch (ConstantException expected) { + catch (Constants.ConstantException expected) { } } diff --git a/spring-core/src/test/java/org/springframework/core/ControlFlowTests.java b/spring-core/src/test/java/org/springframework/core/ControlFlowTests.java deleted file mode 100644 index 7272e914e5a..00000000000 --- a/spring-core/src/test/java/org/springframework/core/ControlFlowTests.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright 2002-2014 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. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.core; - -import org.junit.Test; - -import static org.junit.Assert.*; - -/** - * @author Rod Johnson - * @author Sam Brannen - */ -public class ControlFlowTests { - - @Test - public void underClassAndMethod() { - new One().test(); - new Two().testing(); - new Three().test(); - } - - static class One { - - void test() { - ControlFlow cflow = ControlFlowFactory.createControlFlow(); - assertTrue(cflow.under(One.class)); - assertTrue(cflow.under(ControlFlowTests.class)); - assertFalse(cflow.under(Two.class)); - assertTrue(cflow.under(One.class, "test")); - assertFalse(cflow.under(One.class, "hashCode")); - } - } - - static class Two { - - void testing() { - ControlFlow cflow = ControlFlowFactory.createControlFlow(); - assertTrue(cflow.under(Two.class)); - assertTrue(cflow.under(ControlFlowTests.class)); - assertFalse(cflow.under(One.class)); - assertFalse(cflow.under(Two.class, "test")); - assertTrue(cflow.under(Two.class, "testing")); - } - } - - static class Three { - - void test() { - testing(); - } - - private void testing() { - ControlFlow cflow = ControlFlowFactory.createControlFlow(); - assertTrue(cflow.under(Three.class)); - assertTrue(cflow.under(ControlFlowTests.class)); - assertFalse(cflow.under(One.class)); - assertTrue(cflow.under(Three.class, "test")); - assertTrue(cflow.under(Three.class, "testing")); - } - } - -}