Remove outdated abstractions/delegates from core/util

Issue: SPR-15159
This commit is contained in:
Juergen Hoeller 2017-01-23 13:41:55 +01:00
parent 6fe7e56598
commit ed40b1c8ee
10 changed files with 63 additions and 544 deletions

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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 + "]");
}
}

View File

@ -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 + "]");
}
}
}

View File

@ -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);
}

View File

@ -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.
*
* <p>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.
* <p>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();
}
}
}

View File

@ -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".
*
* <p>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();
}

View File

@ -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.
*
* <p>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.
*
* <p>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<Object> handleQueue = new ReferenceQueue<>();
// All tracked entries (WeakReference => ReleaseListener)
private static final Map<Reference<?>, 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<Object> 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();
}
}

View File

@ -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) {
}
}

View File

@ -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"));
}
}
}