Author: joehni Date: Mon Mar 15 17:11:55 2010 New Revision: 923341 URL: http://svn.apache.org/viewvc?rev=923341&view=rev Log: Fix DefaultExceptionContext.addValue that overwrites information in a recursive situation (LANG-605). Allow explicit replacement of a label with the new replaceValue methods.
Modified: commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/exception/ContextedException.java commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/exception/ContextedRuntimeException.java commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/exception/DefaultExceptionContext.java commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/exception/ExceptionContext.java commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/exception/ContextedExceptionTest.java commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/exception/ContextedRuntimeExceptionTest.java commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/exception/DefaultExceptionContextTest.java Modified: commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/exception/ContextedException.java URL: http://svn.apache.org/viewvc/commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/exception/ContextedException.java?rev=923341&r1=923340&r2=923341&view=diff ============================================================================== --- commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/exception/ContextedException.java (original) +++ commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/exception/ContextedException.java Mon Mar 15 17:11:55 2010 @@ -139,9 +139,11 @@ public class ContextedException extends /** * Adds information helpful to a developer in diagnosing and correcting * the problem. For the information to be meaningful, the value passed - * should have a reasonable toString() implementation. + * should have a reasonable toString() implementation. If the added label + * is already available, the label is appended with an index. * <p> * Note: This exception is only serializable if the object added is serializable. + * </p> * * @param label a textual label associated with information, null not recommended * @param value information needed to understand exception, may be null @@ -153,6 +155,24 @@ public class ContextedException extends } /** + * Replaces information helpful to a developer in diagnosing and correcting + * the problem. For the information to be meaningful, the value passed + * should have a reasonable toString() implementation. If the replaced + * label does not yet exist, it is simply added. + * <p> + * Note: This exception is only serializable if the object added is serializable. + * </p> + * + * @param label a textual label associated with information, null not recommended + * @param value information needed to understand exception, may be null + * @return this, for method chaining + */ + public ContextedException replaceValue(String label, Object value) { + exceptionContext.replaceValue(label, value); + return this; + } + + /** * Retrieves a contextual data value associated with the label. * * @param label the label to get the contextual value for, may be null Modified: commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/exception/ContextedRuntimeException.java URL: http://svn.apache.org/viewvc/commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/exception/ContextedRuntimeException.java?rev=923341&r1=923340&r2=923341&view=diff ============================================================================== --- commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/exception/ContextedRuntimeException.java (original) +++ commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/exception/ContextedRuntimeException.java Mon Mar 15 17:11:55 2010 @@ -64,7 +64,6 @@ import java.util.Set; * @see ContextedException * @author Apache Software Foundation * @author D. Ashmore - * @author Jörg Schaible * @since 3.0 */ public class ContextedRuntimeException extends RuntimeException implements ExceptionContext { @@ -140,9 +139,11 @@ public class ContextedRuntimeException e /** * Adds information helpful to a developer in diagnosing and correcting * the problem. For the information to be meaningful, the value passed - * should have a reasonable toString() implementation. + * should have a reasonable toString() implementation. If the added label + * is already available, the label is appended with an index. * <p> * Note: This exception is only serializable if the object added is serializable. + * </p> * * @param label a textual label associated with information, null not recommended * @param value information needed to understand exception, may be null @@ -154,6 +155,24 @@ public class ContextedRuntimeException e } /** + * Replaces information helpful to a developer in diagnosing and correcting + * the problem. For the information to be meaningful, the value passed + * should have a reasonable toString() implementation. If the replaced + * label does not yet exist, it is simply added. + * <p> + * Note: This exception is only serializable if the object added is serializable. + * </p> + * + * @param label a textual label associated with information, null not recommended + * @param value information needed to understand exception, may be null + * @return this, for method chaining + */ + public ContextedRuntimeException replaceValue(String label, Object value) { + exceptionContext.replaceValue(label, value); + return this; + } + + /** * Retrieves a contextual data value associated with the label. * * @param label the label to get the contextual value for, may be null Modified: commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/exception/DefaultExceptionContext.java URL: http://svn.apache.org/viewvc/commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/exception/DefaultExceptionContext.java?rev=923341&r1=923340&r2=923341&view=diff ============================================================================== --- commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/exception/DefaultExceptionContext.java (original) +++ commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/exception/DefaultExceptionContext.java Mon Mar 15 17:11:55 2010 @@ -43,13 +43,41 @@ class DefaultExceptionContext implements /** * Adds a contextual label-value pair into this context. * <p> - * This label-value pair provides information useful for debugging. + * This label-value pair provides information useful for debugging. If the + * label already exists and the provided information is different, the + * label will be added with an appended index. + * </p> * * @param label the label of the item to add, null not recommended * @param value the value of item to add, may be null * @return this, for method chaining */ public ExceptionContext addValue(String label, Object value) { + String key = label; + int i = 0; + while (contextValueMap.containsKey(key)) { + Object information = contextValueMap.get(key); + if ((value == null && information == null) + || (value != null && value.equals(information))) + return this; + key = label + "[" + ++i +"]"; + } + contextValueMap.put(key, value); + return this; + } + + /** + * Replaces a contextual label-value pair of this context. + * <p> + * This label-value pair provides information useful for debugging. If the + * label does not yet exists, a simply add operation is performed. + * </p> + * + * @param label the label of the item to add, null not recommended + * @param value the value of item to add, may be null + * @return this, for method chaining + */ + public ExceptionContext replaceValue(String label, Object value) { contextValueMap.put(label, value); return this; } Modified: commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/exception/ExceptionContext.java URL: http://svn.apache.org/viewvc/commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/exception/ExceptionContext.java?rev=923341&r1=923340&r2=923341&view=diff ============================================================================== --- commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/exception/ExceptionContext.java (original) +++ commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/exception/ExceptionContext.java Mon Mar 15 17:11:55 2010 @@ -33,7 +33,10 @@ public interface ExceptionContext { /** * Adds a contextual label-value pair into this context. * <p> - * This label-value pair provides information useful for debugging. + * This label-value pair provides information useful for debugging. If the + * provided label already exists, it depends on the implementation what + * happens with the new value. + * </p> * * @param label the label of the item to add, null not recommended * @param value the value of item to add, may be null @@ -42,6 +45,20 @@ public interface ExceptionContext { public ExceptionContext addValue(String label, Object value); /** + * Replaces a contextual label-value pair of this context. + * <p> + * This label-value pair provides information useful for debugging. If the + * label does not exist yet, it depends on the implementation what happens + * with the provided value. + * </p> + * + * @param label the label of the item to add, null not recommended + * @param value the value of item to add, may be null + * @return context itself to allow method chaining + */ + public ExceptionContext replaceValue(String label, Object value); + + /** * Retrieves a contextual data value associated with the label. * * @param label the label to get the contextual value for, may be null Modified: commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/exception/ContextedExceptionTest.java URL: http://svn.apache.org/viewvc/commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/exception/ContextedExceptionTest.java?rev=923341&r1=923340&r2=923341&view=diff ============================================================================== --- commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/exception/ContextedExceptionTest.java (original) +++ commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/exception/ContextedExceptionTest.java Mon Mar 15 17:11:55 2010 @@ -26,7 +26,7 @@ import org.apache.commons.lang3.StringUt /** * JUnit tests for ContextedException. * @author D. Ashmore - * + * @author Apache Software Foundation */ public class ContextedExceptionTest extends TestCase { @@ -34,10 +34,6 @@ public class ContextedExceptionTest exte private static final String TEST_MESSAGE = "Test Message"; private ContextedException contextedException; - public ContextedExceptionTest(String name) { - super(name); - } - public void testContextedException() { contextedException = new ContextedException(); String message = contextedException.getMessage(); @@ -88,8 +84,7 @@ public class ContextedExceptionTest exte .addValue("test1", null) .addValue("test2", "some value") .addValue("test Date", new Date()) - .addValue("test Nbr", new Integer(5)) - .addValue("test Poorly written obj", new ObjectWithFaultyToString()); + .addValue("test Nbr", new Integer(5)); String message = contextedException.getMessage(); assertTrue(message.indexOf(TEST_MESSAGE)>=0); @@ -97,27 +92,49 @@ public class ContextedExceptionTest exte assertTrue(message.indexOf("test2")>=0); assertTrue(message.indexOf("test Date")>=0); assertTrue(message.indexOf("test Nbr")>=0); - assertTrue(message.indexOf("test Poorly written obj")>=0); assertTrue(message.indexOf("some value")>=0); assertTrue(message.indexOf("5")>=0); - assertTrue(message.indexOf("Crap")>=0); assertTrue(contextedException.getValue("test1") == null); assertTrue(contextedException.getValue("test2").equals("some value")); - assertTrue(contextedException.getValue("crap") == null); - assertTrue(contextedException.getValue("test Poorly written obj") instanceof ObjectWithFaultyToString); - assertTrue(contextedException.getLabelSet().size() == 5); + assertTrue(contextedException.getLabelSet().size() == 4); assertTrue(contextedException.getLabelSet().contains("test1")); assertTrue(contextedException.getLabelSet().contains("test2")); assertTrue(contextedException.getLabelSet().contains("test Date")); assertTrue(contextedException.getLabelSet().contains("test Nbr")); + + contextedException.addValue("test2", "different value"); + assertTrue(contextedException.getLabelSet().size() == 5); + assertTrue(contextedException.getLabelSet().contains("test2")); + assertTrue(contextedException.getLabelSet().contains("test2[1]")); + + String contextMessage = contextedException.getFormattedExceptionMessage(null); + assertTrue(contextMessage.indexOf(TEST_MESSAGE) == -1); + assertTrue(contextedException.getMessage().endsWith(contextMessage)); + } + + public void testReplaceValue() { + contextedException = new ContextedException(new Exception(TEST_MESSAGE)) + .addValue("test Poorly written obj", new ObjectWithFaultyToString()); + + String message = contextedException.getMessage(); + assertTrue(message.indexOf(TEST_MESSAGE)>=0); + assertTrue(message.indexOf("test Poorly written obj")>=0); + assertTrue(message.indexOf("Crap")>=0); + + assertTrue(contextedException.getValue("crap") == null); + assertTrue(contextedException.getValue("test Poorly written obj") instanceof ObjectWithFaultyToString); + + assertTrue(contextedException.getLabelSet().size() == 1); assertTrue(contextedException.getLabelSet().contains("test Poorly written obj")); assertTrue(!contextedException.getLabelSet().contains("crap")); - contextedException.addValue("test Poorly written obj", "replacement"); - + contextedException.replaceValue("test Poorly written obj", "replacement"); + + assertTrue(contextedException.getLabelSet().size() == 1); + String contextMessage = contextedException.getFormattedExceptionMessage(null); assertTrue(contextMessage.indexOf(TEST_MESSAGE) == -1); assertTrue(contextedException.getMessage().endsWith(contextMessage)); @@ -134,10 +151,6 @@ public class ContextedExceptionTest exte String message = contextedException.getMessage(); assertTrue(message != null); } - - public void testGetMessage() { - testAddValue(); - } static class ObjectWithFaultyToString implements Serializable { Modified: commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/exception/ContextedRuntimeExceptionTest.java URL: http://svn.apache.org/viewvc/commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/exception/ContextedRuntimeExceptionTest.java?rev=923341&r1=923340&r2=923341&view=diff ============================================================================== --- commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/exception/ContextedRuntimeExceptionTest.java (original) +++ commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/exception/ContextedRuntimeExceptionTest.java Mon Mar 15 17:11:55 2010 @@ -26,6 +26,7 @@ import org.apache.commons.lang3.exceptio /** * JUnit tests for ContextedRuntimeException. * @author D. Ashmore + * @author Apache Software Foundation * */ public class ContextedRuntimeExceptionTest extends TestCase { @@ -34,10 +35,6 @@ public class ContextedRuntimeExceptionTe private static final String TEST_MESSAGE = "Test Message"; private ContextedRuntimeException contextedRuntimeException; - public ContextedRuntimeExceptionTest(String name) { - super(name); - } - public void testContextedException() { contextedRuntimeException = new ContextedRuntimeException(); String message = contextedRuntimeException.getMessage(); @@ -88,8 +85,7 @@ public class ContextedRuntimeExceptionTe .addValue("test1", null) .addValue("test2", "some value") .addValue("test Date", new Date()) - .addValue("test Nbr", new Integer(5)) - .addValue("test Poorly written obj", new ObjectWithFaultyToString()); + .addValue("test Nbr", new Integer(5)); String message = contextedRuntimeException.getMessage(); assertTrue(message.indexOf(TEST_MESSAGE)>=0); @@ -97,27 +93,49 @@ public class ContextedRuntimeExceptionTe assertTrue(message.indexOf("test2")>=0); assertTrue(message.indexOf("test Date")>=0); assertTrue(message.indexOf("test Nbr")>=0); - assertTrue(message.indexOf("test Poorly written obj")>=0); assertTrue(message.indexOf("some value")>=0); assertTrue(message.indexOf("5")>=0); - assertTrue(message.indexOf("Crap")>=0); assertTrue(contextedRuntimeException.getValue("test1") == null); assertTrue(contextedRuntimeException.getValue("test2").equals("some value")); - assertTrue(contextedRuntimeException.getValue("crap") == null); - assertTrue(contextedRuntimeException.getValue("test Poorly written obj") instanceof ObjectWithFaultyToString); - assertTrue(contextedRuntimeException.getLabelSet().size() == 5); + assertTrue(contextedRuntimeException.getLabelSet().size() == 4); assertTrue(contextedRuntimeException.getLabelSet().contains("test1")); assertTrue(contextedRuntimeException.getLabelSet().contains("test2")); assertTrue(contextedRuntimeException.getLabelSet().contains("test Date")); assertTrue(contextedRuntimeException.getLabelSet().contains("test Nbr")); + + contextedRuntimeException.addValue("test2", "different value"); + assertTrue(contextedRuntimeException.getLabelSet().size() == 5); + assertTrue(contextedRuntimeException.getLabelSet().contains("test2")); + assertTrue(contextedRuntimeException.getLabelSet().contains("test2[1]")); + + String contextMessage = contextedRuntimeException.getFormattedExceptionMessage(null); + assertTrue(contextMessage.indexOf(TEST_MESSAGE) == -1); + assertTrue(contextedRuntimeException.getMessage().endsWith(contextMessage)); + } + + public void testReplaceValue() { + contextedRuntimeException = new ContextedRuntimeException(new Exception(TEST_MESSAGE)) + .addValue("test Poorly written obj", new ObjectWithFaultyToString()); + + String message = contextedRuntimeException.getMessage(); + assertTrue(message.indexOf(TEST_MESSAGE)>=0); + assertTrue(message.indexOf("test Poorly written obj")>=0); + assertTrue(message.indexOf("Crap")>=0); + + assertTrue(contextedRuntimeException.getValue("crap") == null); + assertTrue(contextedRuntimeException.getValue("test Poorly written obj") instanceof ObjectWithFaultyToString); + + assertTrue(contextedRuntimeException.getLabelSet().size() == 1); assertTrue(contextedRuntimeException.getLabelSet().contains("test Poorly written obj")); assertTrue(!contextedRuntimeException.getLabelSet().contains("crap")); - contextedRuntimeException.addValue("test Poorly written obj", "replacement"); - + contextedRuntimeException.replaceValue("test Poorly written obj", "replacement"); + + assertTrue(contextedRuntimeException.getLabelSet().size() == 1); + String contextMessage = contextedRuntimeException.getFormattedExceptionMessage(null); assertTrue(contextMessage.indexOf(TEST_MESSAGE) == -1); assertTrue(contextedRuntimeException.getMessage().endsWith(contextMessage)); @@ -134,10 +152,4 @@ public class ContextedRuntimeExceptionTe String message = contextedRuntimeException.getMessage(); assertTrue(message != null); } - - public void testGetMessage() { - testAddValue(); - } - - } Modified: commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/exception/DefaultExceptionContextTest.java URL: http://svn.apache.org/viewvc/commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/exception/DefaultExceptionContextTest.java?rev=923341&r1=923340&r2=923341&view=diff ============================================================================== --- commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/exception/DefaultExceptionContextTest.java (original) +++ commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/exception/DefaultExceptionContextTest.java Mon Mar 15 17:11:55 2010 @@ -23,7 +23,7 @@ import org.apache.commons.lang3.exceptio import junit.framework.TestCase; /** - * JUnit tests for DefaultExceptionContext + * JUnit tests for DefaultExceptionContext. * @author D. Ashmore * */ @@ -46,21 +46,42 @@ public class DefaultExceptionContextTest } public void testAddValue() { + defaultExceptionContext.addValue("test2", "different value"); String message = defaultExceptionContext.getFormattedExceptionMessage("This is an error"); assertTrue(message.indexOf("This is an error")>=0); assertTrue(message.indexOf("test1")>=0); assertTrue(message.indexOf("test2")>=0); + assertTrue(message.indexOf("test2[1]")>=0); assertTrue(message.indexOf("test Date")>=0); assertTrue(message.indexOf("test Nbr")>=0); assertTrue(message.indexOf("test Poorly written obj")>=0); assertTrue(message.indexOf("some value")>=0); + assertTrue(message.indexOf("different value")>=0); assertTrue(message.indexOf("5")>=0); assertTrue(message.indexOf("Crap")>=0); - - //contextedException.printStackTrace(); } + public void testReplaceValue() { + defaultExceptionContext.replaceValue("test2", "different value"); + defaultExceptionContext.replaceValue("test3", "3"); + + String message = defaultExceptionContext.getFormattedExceptionMessage("This is an error"); + assertTrue(message.indexOf("This is an error")>=0); + assertTrue(message.indexOf("test1")>=0); + assertTrue(message.indexOf("test2")>=0); + assertTrue(message.indexOf("test3")>=0); + assertTrue(message.indexOf("test Date")>=0); + assertTrue(message.indexOf("test Nbr")>=0); + assertTrue(message.indexOf("test Poorly written obj")>=0); + assertTrue(message.indexOf("different value")>=0); + assertTrue(message.indexOf("5")>=0); + assertTrue(message.indexOf("Crap")>=0); + + assertTrue(message.indexOf("test2[1]")<0); + assertTrue(message.indexOf("some value")<0); +} + public void testFormattedExceptionMessageNull() { defaultExceptionContext = new DefaultExceptionContext(); defaultExceptionContext.getFormattedExceptionMessage(null);