I'll add a junit test, but this is what it was before I started touching that 
class (except for obj.toString() -> String.valueOf(obj)).

Sent from my iPhone

> On 2014/08/12, at 8:02, Ralph Goers <[email protected]> wrote:
> 
> Serialization does:
> 
>        if (obj instanceof Serializable) {
>            out.writeObject(obj);
>        } else {
>            out.writeObject(String.valueOf(obj));
>        }
> 
> Deserialization does:
> 
>        in.defaultReadObject();
>        obj = in.readObject();
> 
> So if obj is not Serializable a String will be written. Upon deserialization 
> obj will be set to either the the deserialized version of the object or to 
> the String.  I guess this will work.
> 
> Ralph
> 
> 
>> On Aug 11, 2014, at 2:46 PM, Remko Popma <[email protected]> wrote:
>> 
>> I didn't change the serialization behavior.  I only changed 
>> obj.toString()
>> to
>> String.valueOf(obj)
>> 
>> The stringValue field wasn't there originally (I incorrectly added it as 
>> non-transient in my first attempt).  It is now transient so serialized form 
>> should be the same as pre-change. 
>> 
>> The serialization behavior of ObjectMessage has always been to serialize as 
>> Object if possible (Serializable), otherwise as String. Deserialization will 
>> just read whatever was serialized. That may not be the same object field but 
>> is the best we can do. 
>> 
>> Or did I miss something? (away from PC) 
>> 
>> Sent from my iPhone
>> 
>>> On 2014/08/12, at 2:38, Ralph Goers <[email protected]> wrote:
>>> 
>>> I believe this breaks deserialization of ObjectMessage. It is being 
>>> serialized as either the serialized form of the Object or as a String. 
>>> Deserialization doesn't account for this.
>>> 
>>> Ralph
>>> 
>>>> On Aug 11, 2014, at 7:16 AM, [email protected] wrote:
>>>> 
>>>> Author: rpopma
>>>> Date: Mon Aug 11 14:16:22 2014
>>>> New Revision: 1617291
>>>> 
>>>> URL: http://svn.apache.org/r1617291
>>>> Log:
>>>> LOG4J2-763: use different mechanism to solve this problem: instead of 
>>>> initializing the formatted message string in the message constructor, 
>>>> postpone this as long as possible until getFormattedMessage() is called. 
>>>> Async loggers and AsyncAppender now call message.getFormattedMessage() 
>>>> before passing the log event to the background thread. Added more tests.
>>>> 
>>>> Modified:
>>>> logging/log4j/log4j2/trunk/log4j-api/src/main/java/org/apache/logging/log4j/message/FormattedMessage.java
>>>> logging/log4j/log4j2/trunk/log4j-api/src/main/java/org/apache/logging/log4j/message/LocalizedMessage.java
>>>> logging/log4j/log4j2/trunk/log4j-api/src/main/java/org/apache/logging/log4j/message/MessageFormatMessage.java
>>>> logging/log4j/log4j2/trunk/log4j-api/src/main/java/org/apache/logging/log4j/message/ObjectMessage.java
>>>> logging/log4j/log4j2/trunk/log4j-api/src/main/java/org/apache/logging/log4j/message/StringFormattedMessage.java
>>>> logging/log4j/log4j2/trunk/log4j-api/src/test/java/org/apache/logging/log4j/message/FormattedMessageTest.java
>>>> logging/log4j/log4j2/trunk/log4j-api/src/test/java/org/apache/logging/log4j/message/LocalizedMessageTest.java
>>>> logging/log4j/log4j2/trunk/log4j-api/src/test/java/org/apache/logging/log4j/message/MessageFormatMessageTest.java
>>>> logging/log4j/log4j2/trunk/log4j-api/src/test/java/org/apache/logging/log4j/message/ObjectMessageTest.java
>>>> logging/log4j/log4j2/trunk/log4j-api/src/test/java/org/apache/logging/log4j/message/StringFormattedMessageTest.java
>>>> logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AsyncAppender.java
>>>> logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLogger.java
>>>> logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigHelper.java
>>>> logging/log4j/log4j2/trunk/src/changes/changes.xml
>>>> 
>>>> Modified: 
>>>> logging/log4j/log4j2/trunk/log4j-api/src/main/java/org/apache/logging/log4j/message/FormattedMessage.java
>>>> URL: 
>>>> http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-api/src/main/java/org/apache/logging/log4j/message/FormattedMessage.java?rev=1617291&r1=1617290&r2=1617291&view=diff
>>>> ==============================================================================
>>>> --- 
>>>> logging/log4j/log4j2/trunk/log4j-api/src/main/java/org/apache/logging/log4j/message/FormattedMessage.java
>>>>  (original)
>>>> +++ 
>>>> logging/log4j/log4j2/trunk/log4j-api/src/main/java/org/apache/logging/log4j/message/FormattedMessage.java
>>>>  Mon Aug 11 14:16:22 2014
>>>> @@ -46,7 +46,6 @@ public class FormattedMessage implements
>>>>      this.messagePattern = messagePattern;
>>>>      this.argArray = arguments;
>>>>      this.throwable = throwable;
>>>> -        getFormattedMessage(); // LOG4J2-763 take snapshot of parameters 
>>>> at message construction time
>>>>  }
>>>> 
>>>>  public FormattedMessage(final String messagePattern, final Object[] 
>>>> arguments) {
>>>> 
>>>> Modified: 
>>>> logging/log4j/log4j2/trunk/log4j-api/src/main/java/org/apache/logging/log4j/message/LocalizedMessage.java
>>>> URL: 
>>>> http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-api/src/main/java/org/apache/logging/log4j/message/LocalizedMessage.java?rev=1617291&r1=1617290&r2=1617291&view=diff
>>>> ==============================================================================
>>>> --- 
>>>> logging/log4j/log4j2/trunk/log4j-api/src/main/java/org/apache/logging/log4j/message/LocalizedMessage.java
>>>>  (original)
>>>> +++ 
>>>> logging/log4j/log4j2/trunk/log4j-api/src/main/java/org/apache/logging/log4j/message/LocalizedMessage.java
>>>>  Mon Aug 11 14:16:22 2014
>>>> @@ -78,7 +78,6 @@ public class LocalizedMessage implements
>>>>      this.baseName = baseName;
>>>>      this.resourceBundle = null;
>>>>      this.locale = locale;
>>>> -        getFormattedMessage(); // LOG4J2-763 take snapshot of parameters 
>>>> at message construction time
>>>>  }
>>>> 
>>>>  public LocalizedMessage(final ResourceBundle bundle, final Locale locale, 
>>>> final String key,
>>>> @@ -89,7 +88,6 @@ public class LocalizedMessage implements
>>>>      this.baseName = null;
>>>>      this.resourceBundle = bundle;
>>>>      this.locale = locale;
>>>> -        getFormattedMessage(); // LOG4J2-763 take snapshot of parameters 
>>>> at message construction time
>>>>  }
>>>> 
>>>>  public LocalizedMessage(final Locale locale, final String key, final 
>>>> Object[] arguments) {
>>>> 
>>>> Modified: 
>>>> logging/log4j/log4j2/trunk/log4j-api/src/main/java/org/apache/logging/log4j/message/MessageFormatMessage.java
>>>> URL: 
>>>> http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-api/src/main/java/org/apache/logging/log4j/message/MessageFormatMessage.java?rev=1617291&r1=1617290&r2=1617291&view=diff
>>>> ==============================================================================
>>>> --- 
>>>> logging/log4j/log4j2/trunk/log4j-api/src/main/java/org/apache/logging/log4j/message/MessageFormatMessage.java
>>>>  (original)
>>>> +++ 
>>>> logging/log4j/log4j2/trunk/log4j-api/src/main/java/org/apache/logging/log4j/message/MessageFormatMessage.java
>>>>  Mon Aug 11 14:16:22 2014
>>>> @@ -49,7 +49,6 @@ public class MessageFormatMessage implem
>>>>      if (arguments != null && arguments.length > 0 && 
>>>> arguments[arguments.length - 1] instanceof Throwable) {
>>>>          this.throwable = (Throwable) arguments[arguments.length - 1];
>>>>      }
>>>> -        getFormattedMessage(); // LOG4J2-763 take snapshot of parameters 
>>>> at message construction time
>>>>  }
>>>> 
>>>>  /**
>>>> 
>>>> Modified: 
>>>> logging/log4j/log4j2/trunk/log4j-api/src/main/java/org/apache/logging/log4j/message/ObjectMessage.java
>>>> URL: 
>>>> http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-api/src/main/java/org/apache/logging/log4j/message/ObjectMessage.java?rev=1617291&r1=1617290&r2=1617291&view=diff
>>>> ==============================================================================
>>>> --- 
>>>> logging/log4j/log4j2/trunk/log4j-api/src/main/java/org/apache/logging/log4j/message/ObjectMessage.java
>>>>  (original)
>>>> +++ 
>>>> logging/log4j/log4j2/trunk/log4j-api/src/main/java/org/apache/logging/log4j/message/ObjectMessage.java
>>>>  Mon Aug 11 14:16:22 2014
>>>> @@ -29,7 +29,7 @@ public class ObjectMessage implements Me
>>>>  private static final long serialVersionUID = -5903272448334166185L;
>>>> 
>>>>  private transient Object obj;
>>>> -    private final String objectString;
>>>> +    private transient String objectString;
>>>> 
>>>>  /**
>>>>   * Create the ObjectMessage.
>>>> @@ -40,9 +40,6 @@ public class ObjectMessage implements Me
>>>>          obj = "null";
>>>>      }
>>>>      this.obj = obj;
>>>> -        
>>>> -        // LOG4J2-763: take snapshot of parameters at message 
>>>> construction time
>>>> -        objectString = String.valueOf(obj);
>>>>  }
>>>> 
>>>>  /**
>>>> @@ -51,6 +48,10 @@ public class ObjectMessage implements Me
>>>>   */
>>>>  @Override
>>>>  public String getFormattedMessage() {
>>>> +        // LOG4J2-763: cache formatted string in case obj changes later
>>>> +        if (objectString == null) {
>>>> +            objectString = String.valueOf(obj);
>>>> +        }
>>>>      return objectString;
>>>>  }
>>>> 
>>>> @@ -60,7 +61,7 @@ public class ObjectMessage implements Me
>>>>   */
>>>>  @Override
>>>>  public String getFormat() {
>>>> -        return objectString;
>>>> +        return getFormattedMessage();
>>>>  }
>>>> 
>>>>  /**
>>>> @@ -69,7 +70,7 @@ public class ObjectMessage implements Me
>>>>   */
>>>>  @Override
>>>>  public Object[] getParameters() {
>>>> -        return new Object[]{obj};
>>>> +        return new Object[] { obj };
>>>>  }
>>>> 
>>>>  @Override
>>>> @@ -82,8 +83,7 @@ public class ObjectMessage implements Me
>>>>      }
>>>> 
>>>>      final ObjectMessage that = (ObjectMessage) o;
>>>> -
>>>> -        return !(obj != null ? !obj.equals(that.obj) : that.obj != null);
>>>> +        return obj == null ? that.obj == null : obj.equals(that.obj);
>>>>  }
>>>> 
>>>>  @Override
>>>> @@ -93,7 +93,7 @@ public class ObjectMessage implements Me
>>>> 
>>>>  @Override
>>>>  public String toString() {
>>>> -        return "ObjectMessage[obj=" + objectString + ']';
>>>> +        return "ObjectMessage[obj=" + getFormattedMessage() + ']';
>>>>  }
>>>> 
>>>>  private void writeObject(final ObjectOutputStream out) throws IOException 
>>>> {
>>>> @@ -101,7 +101,7 @@ public class ObjectMessage implements Me
>>>>      if (obj instanceof Serializable) {
>>>>          out.writeObject(obj);
>>>>      } else {
>>>> -            out.writeObject(obj.toString());
>>>> +            out.writeObject(String.valueOf(obj));
>>>>      }
>>>>  }
>>>> 
>>>> 
>>>> Modified: 
>>>> logging/log4j/log4j2/trunk/log4j-api/src/main/java/org/apache/logging/log4j/message/StringFormattedMessage.java
>>>> URL: 
>>>> http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-api/src/main/java/org/apache/logging/log4j/message/StringFormattedMessage.java?rev=1617291&r1=1617290&r2=1617291&view=diff
>>>> ==============================================================================
>>>> --- 
>>>> logging/log4j/log4j2/trunk/log4j-api/src/main/java/org/apache/logging/log4j/message/StringFormattedMessage.java
>>>>  (original)
>>>> +++ 
>>>> logging/log4j/log4j2/trunk/log4j-api/src/main/java/org/apache/logging/log4j/message/StringFormattedMessage.java
>>>>  Mon Aug 11 14:16:22 2014
>>>> @@ -48,7 +48,6 @@ public class StringFormattedMessage impl
>>>>      if (arguments != null && arguments.length > 0 && 
>>>> arguments[arguments.length - 1] instanceof Throwable) {
>>>>          this.throwable = (Throwable) arguments[arguments.length - 1];
>>>>      }
>>>> -        getFormattedMessage(); // LOG4J2-763 take snapshot of parameters 
>>>> at message construction time
>>>>  }
>>>> 
>>>>  /**
>>>> 
>>>> Modified: 
>>>> logging/log4j/log4j2/trunk/log4j-api/src/test/java/org/apache/logging/log4j/message/FormattedMessageTest.java
>>>> URL: 
>>>> http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-api/src/test/java/org/apache/logging/log4j/message/FormattedMessageTest.java?rev=1617291&r1=1617290&r2=1617291&view=diff
>>>> ==============================================================================
>>>> --- 
>>>> logging/log4j/log4j2/trunk/log4j-api/src/test/java/org/apache/logging/log4j/message/FormattedMessageTest.java
>>>>  (original)
>>>> +++ 
>>>> logging/log4j/log4j2/trunk/log4j-api/src/test/java/org/apache/logging/log4j/message/FormattedMessageTest.java
>>>>  Mon Aug 11 14:16:22 2014
>>>> @@ -85,14 +85,27 @@ public class FormattedMessageTest {
>>>>  }
>>>> 
>>>>  @Test
>>>> -    public void testSafeWithMutableParams() { // LOG4J2-763
>>>> +    public void testUnsafeWithMutableParams() { // LOG4J2-763
>>>>      final String testMsg = "Test message %s";
>>>>      final Mutable param = new Mutable().set("abc");
>>>> -        FormattedMessage msg = new FormattedMessage(testMsg, param);
>>>> +        final FormattedMessage msg = new FormattedMessage(testMsg, param);
>>>> 
>>>>      // modify parameter before calling msg.getFormattedMessage
>>>>      param.set("XYZ");
>>>> -        String actual = msg.getFormattedMessage();
>>>> +        final String actual = msg.getFormattedMessage();
>>>> +        assertEquals("Expected most recent param value", "Test message 
>>>> XYZ", actual);
>>>> +    }
>>>> +
>>>> +    @Test
>>>> +    public void testSafeAfterGetFormattedMessageIsCalled() { // LOG4J2-763
>>>> +        final String testMsg = "Test message %s";
>>>> +        final Mutable param = new Mutable().set("abc");
>>>> +        final FormattedMessage msg = new FormattedMessage(testMsg, param);
>>>> +
>>>> +        // modify parameter after calling msg.getFormattedMessage
>>>> +        msg.getFormattedMessage(); // freeze the formatted message
>>>> +        param.set("XYZ");
>>>> +        final String actual = msg.getFormattedMessage();
>>>>      assertEquals("Should use initial param value", "Test message abc", 
>>>> actual);
>>>>  }
>>>> }
>>>> 
>>>> Modified: 
>>>> logging/log4j/log4j2/trunk/log4j-api/src/test/java/org/apache/logging/log4j/message/LocalizedMessageTest.java
>>>> URL: 
>>>> http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-api/src/test/java/org/apache/logging/log4j/message/LocalizedMessageTest.java?rev=1617291&r1=1617290&r2=1617291&view=diff
>>>> ==============================================================================
>>>> --- 
>>>> logging/log4j/log4j2/trunk/log4j-api/src/test/java/org/apache/logging/log4j/message/LocalizedMessageTest.java
>>>>  (original)
>>>> +++ 
>>>> logging/log4j/log4j2/trunk/log4j-api/src/test/java/org/apache/logging/log4j/message/LocalizedMessageTest.java
>>>>  Mon Aug 11 14:16:22 2014
>>>> @@ -65,15 +65,27 @@ public class LocalizedMessageTest {
>>>>  }
>>>> 
>>>>  @Test
>>>> -    public void testSafeWithMutableParams() { // LOG4J2-763
>>>> +    public void testUnsafeWithMutableParams() { // LOG4J2-763
>>>>      final String testMsg = "Test message %s";
>>>>      final Mutable param = new Mutable().set("abc");
>>>> -        LocalizedMessage msg = new LocalizedMessage(testMsg, param);
>>>> +        final LocalizedMessage msg = new LocalizedMessage(testMsg, param);
>>>> 
>>>>      // modify parameter before calling msg.getFormattedMessage
>>>>      param.set("XYZ");
>>>> -        String actual = msg.getFormattedMessage();
>>>> -        assertEquals("Should use initial param value", "Test message 
>>>> abc", actual);
>>>> +        final String actual = msg.getFormattedMessage();
>>>> +        assertEquals("Expected most recent param value", "Test message 
>>>> XYZ", actual);
>>>>  }
>>>> 
>>>> +    @Test
>>>> +    public void testSafeAfterGetFormattedMessageIsCalled() { // LOG4J2-763
>>>> +        final String testMsg = "Test message %s";
>>>> +        final Mutable param = new Mutable().set("abc");
>>>> +        final LocalizedMessage msg = new LocalizedMessage(testMsg, param);
>>>> +
>>>> +        // modify parameter after calling msg.getFormattedMessage
>>>> +        msg.getFormattedMessage();
>>>> +        param.set("XYZ");
>>>> +        final String actual = msg.getFormattedMessage();
>>>> +        assertEquals("Should use initial param value", "Test message 
>>>> abc", actual);
>>>> +    }
>>>> }
>>>> 
>>>> Modified: 
>>>> logging/log4j/log4j2/trunk/log4j-api/src/test/java/org/apache/logging/log4j/message/MessageFormatMessageTest.java
>>>> URL: 
>>>> http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-api/src/test/java/org/apache/logging/log4j/message/MessageFormatMessageTest.java?rev=1617291&r1=1617290&r2=1617291&view=diff
>>>> ==============================================================================
>>>> --- 
>>>> logging/log4j/log4j2/trunk/log4j-api/src/test/java/org/apache/logging/log4j/message/MessageFormatMessageTest.java
>>>>  (original)
>>>> +++ 
>>>> logging/log4j/log4j2/trunk/log4j-api/src/test/java/org/apache/logging/log4j/message/MessageFormatMessageTest.java
>>>>  Mon Aug 11 14:16:22 2014
>>>> @@ -63,14 +63,27 @@ public class MessageFormatMessageTest {
>>>>  }
>>>> 
>>>>  @Test
>>>> -    public void testSafeWithMutableParams() { // LOG4J2-763
>>>> +    public void testUnsafeWithMutableParams() { // LOG4J2-763
>>>>      final String testMsg = "Test message {0}";
>>>>      final Mutable param = new Mutable().set("abc");
>>>> -        MessageFormatMessage msg = new MessageFormatMessage(testMsg, 
>>>> param);
>>>> +        final MessageFormatMessage msg = new 
>>>> MessageFormatMessage(testMsg, param);
>>>> 
>>>>      // modify parameter before calling msg.getFormattedMessage
>>>>      param.set("XYZ");
>>>> -        String actual = msg.getFormattedMessage();
>>>> +        final String actual = msg.getFormattedMessage();
>>>> +        assertEquals("Expected most recent param value", "Test message 
>>>> XYZ", actual);
>>>> +    }
>>>> +
>>>> +    @Test
>>>> +    public void testSafeAfterGetFormattedMessageIsCalled() { // LOG4J2-763
>>>> +        final String testMsg = "Test message {0}";
>>>> +        final Mutable param = new Mutable().set("abc");
>>>> +        final MessageFormatMessage msg = new 
>>>> MessageFormatMessage(testMsg, param);
>>>> +
>>>> +        // modify parameter after calling msg.getFormattedMessage
>>>> +        msg.getFormattedMessage();
>>>> +        param.set("XYZ");
>>>> +        final String actual = msg.getFormattedMessage();
>>>>      assertEquals("Should use initial param value", "Test message abc", 
>>>> actual);
>>>>  }
>>>> }
>>>> 
>>>> Modified: 
>>>> logging/log4j/log4j2/trunk/log4j-api/src/test/java/org/apache/logging/log4j/message/ObjectMessageTest.java
>>>> URL: 
>>>> http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-api/src/test/java/org/apache/logging/log4j/message/ObjectMessageTest.java?rev=1617291&r1=1617290&r2=1617291&view=diff
>>>> ==============================================================================
>>>> --- 
>>>> logging/log4j/log4j2/trunk/log4j-api/src/test/java/org/apache/logging/log4j/message/ObjectMessageTest.java
>>>>  (original)
>>>> +++ 
>>>> logging/log4j/log4j2/trunk/log4j-api/src/test/java/org/apache/logging/log4j/message/ObjectMessageTest.java
>>>>  Mon Aug 11 14:16:22 2014
>>>> @@ -41,13 +41,25 @@ public class ObjectMessageTest {
>>>>  }
>>>> 
>>>>  @Test
>>>> -    public void testSafeWithMutableParams() { // LOG4J2-763
>>>> +    public void testUnsafeWithMutableParams() { // LOG4J2-763
>>>>      final Mutable param = new Mutable().set("abc");
>>>> -        ObjectMessage msg = new ObjectMessage(param);
>>>> +        final ObjectMessage msg = new ObjectMessage(param);
>>>> 
>>>>      // modify parameter before calling msg.getFormattedMessage
>>>>      param.set("XYZ");
>>>> -        String actual = msg.getFormattedMessage();
>>>> +        final String actual = msg.getFormattedMessage();
>>>> +        assertEquals("Expected most recent param value", "XYZ", actual);
>>>> +    }
>>>> +
>>>> +    @Test
>>>> +    public void testSafeAfterGetFormattedMessageIsCalled() { // LOG4J2-763
>>>> +        final Mutable param = new Mutable().set("abc");
>>>> +        final ObjectMessage msg = new ObjectMessage(param);
>>>> +
>>>> +        // modify parameter after calling msg.getFormattedMessage
>>>> +        msg.getFormattedMessage();
>>>> +        param.set("XYZ");
>>>> +        final String actual = msg.getFormattedMessage();
>>>>      assertEquals("Should use initial param value", "abc", actual);
>>>>  }
>>>> }
>>>> 
>>>> Modified: 
>>>> logging/log4j/log4j2/trunk/log4j-api/src/test/java/org/apache/logging/log4j/message/StringFormattedMessageTest.java
>>>> URL: 
>>>> http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-api/src/test/java/org/apache/logging/log4j/message/StringFormattedMessageTest.java?rev=1617291&r1=1617290&r2=1617291&view=diff
>>>> ==============================================================================
>>>> --- 
>>>> logging/log4j/log4j2/trunk/log4j-api/src/test/java/org/apache/logging/log4j/message/StringFormattedMessageTest.java
>>>>  (original)
>>>> +++ 
>>>> logging/log4j/log4j2/trunk/log4j-api/src/test/java/org/apache/logging/log4j/message/StringFormattedMessageTest.java
>>>>  Mon Aug 11 14:16:22 2014
>>>> @@ -62,14 +62,27 @@ public class StringFormattedMessageTest 
>>>>  }
>>>> 
>>>>  @Test
>>>> -    public void testSafeWithMutableParams() { // LOG4J2-763
>>>> +    public void testUnsafeWithMutableParams() { // LOG4J2-763
>>>>      final String testMsg = "Test message %s";
>>>>      final Mutable param = new Mutable().set("abc");
>>>> -        StringFormattedMessage msg = new StringFormattedMessage(testMsg, 
>>>> param);
>>>> +        final StringFormattedMessage msg = new 
>>>> StringFormattedMessage(testMsg, param);
>>>> 
>>>>      // modify parameter before calling msg.getFormattedMessage
>>>>      param.set("XYZ");
>>>> -        String actual = msg.getFormattedMessage();
>>>> +        final String actual = msg.getFormattedMessage();
>>>> +        assertEquals("Should use initial param value", "Test message 
>>>> XYZ", actual);
>>>> +    }
>>>> +
>>>> +    @Test
>>>> +    public void testSafeAfterGetFormattedMessageIsCalled() { // LOG4J2-763
>>>> +        final String testMsg = "Test message %s";
>>>> +        final Mutable param = new Mutable().set("abc");
>>>> +        final StringFormattedMessage msg = new 
>>>> StringFormattedMessage(testMsg, param);
>>>> +
>>>> +        // modify parameter after calling msg.getFormattedMessage
>>>> +        msg.getFormattedMessage();
>>>> +        param.set("XYZ");
>>>> +        final String actual = msg.getFormattedMessage();
>>>>      assertEquals("Should use initial param value", "Test message abc", 
>>>> actual);
>>>>  }
>>>> }
>>>> 
>>>> Modified: 
>>>> logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AsyncAppender.java
>>>> URL: 
>>>> http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AsyncAppender.java?rev=1617291&r1=1617290&r2=1617291&view=diff
>>>> ==============================================================================
>>>> --- 
>>>> logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AsyncAppender.java
>>>>  (original)
>>>> +++ 
>>>> logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AsyncAppender.java
>>>>  Mon Aug 11 14:16:22 2014
>>>> @@ -138,6 +138,7 @@ public final class AsyncAppender extends
>>>>          }
>>>>          logEvent = ((RingBufferLogEvent) logEvent).createMemento();
>>>>      }
>>>> +        logEvent.getMessage().getFormattedMessage(); // LOG4J2-763: ask 
>>>> message to freeze parameters
>>>>      final Log4jLogEvent coreEvent = (Log4jLogEvent) logEvent;
>>>>      boolean appendSuccessful = false;
>>>>      if (blocking) {
>>>> 
>>>> Modified: 
>>>> logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLogger.java
>>>> URL: 
>>>> http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLogger.java?rev=1617291&r1=1617290&r2=1617291&view=diff
>>>> ==============================================================================
>>>> --- 
>>>> logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLogger.java
>>>>  (original)
>>>> +++ 
>>>> logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLogger.java
>>>>  Mon Aug 11 14:16:22 2014
>>>> @@ -226,6 +226,7 @@ public class AsyncLogger extends Logger 
>>>> 
>>>>  @Override
>>>>  public void logMessage(final String fqcn, final Level level, final Marker 
>>>> marker, final Message message, final Throwable thrown) {
>>>> +        // TODO refactor to reduce size to <= 35 bytecodes to allow JVM 
>>>> to inline it
>>>>      Info info = threadlocalInfo.get();
>>>>      if (info == null) {
>>>>          info = new Info(new RingBufferLogEventTranslator(), 
>>>> Thread.currentThread().getName(), false);
>>>> @@ -245,6 +246,7 @@ public class AsyncLogger extends Logger 
>>>>          config.loggerConfig.log(getName(), fqcn, marker, level, message, 
>>>> thrown);
>>>>          return;
>>>>      }
>>>> +        message.getFormattedMessage(); // LOG4J2-763: ask message to 
>>>> freeze parameters
>>>>      final boolean includeLocation = 
>>>> config.loggerConfig.isIncludeLocation();
>>>>      info.translator.setValues(this, getName(), marker, fqcn, level, 
>>>> message, //
>>>>              // don't construct ThrowableProxy until required
>>>> 
>>>> Modified: 
>>>> logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigHelper.java
>>>> URL: 
>>>> http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigHelper.java?rev=1617291&r1=1617290&r2=1617291&view=diff
>>>> ==============================================================================
>>>> --- 
>>>> logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigHelper.java
>>>>  (original)
>>>> +++ 
>>>> logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigHelper.java
>>>>  Mon Aug 11 14:16:22 2014
>>>> @@ -316,6 +316,7 @@ class AsyncLoggerConfigHelper {
>>>>   *          calling thread needs to process the event itself
>>>>   */
>>>>  public boolean callAppendersFromAnotherThread(final LogEvent event) {
>>>> +        // TODO refactor to reduce size to <= 35 bytecodes to allow JVM 
>>>> to inline it
>>>>      final Disruptor<Log4jEventWrapper> temp = disruptor;
>>>>      if (temp == null) { // LOG4J2-639
>>>>          LOGGER.fatal("Ignoring log event after log4j was shut down");
>>>> @@ -336,6 +337,8 @@ class AsyncLoggerConfigHelper {
>>>>          if (event instanceof RingBufferLogEvent) {
>>>>              logEvent = ((RingBufferLogEvent) event).createMemento();
>>>>          }
>>>> +            logEvent.getMessage().getFormattedMessage(); // LOG4J2-763: 
>>>> ask message to freeze parameters
>>>> +
>>>>          // Note: do NOT use the temp variable above!
>>>>          // That could result in adding a log event to the disruptor after 
>>>> it was shut down,
>>>>          // which could cause the publishEvent method to hang and never 
>>>> return.
>>>> 
>>>> Modified: logging/log4j/log4j2/trunk/src/changes/changes.xml
>>>> URL: 
>>>> http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/src/changes/changes.xml?rev=1617291&r1=1617290&r2=1617291&view=diff
>>>> ==============================================================================
>>>> --- logging/log4j/log4j2/trunk/src/changes/changes.xml (original)
>>>> +++ logging/log4j/log4j2/trunk/src/changes/changes.xml Mon Aug 11 14:16:22 
>>>> 2014
>>>> @@ -29,8 +29,7 @@
>>>>      Startup takes a long time if you have empty packages attribute.
>>>>    </action>
>>>>    <action issue="LOG4J2-763" dev="rpopma" type="fix" due-to="Stephen 
>>>> Connolly">
>>>> -        Improved FormattedMessage, StringFormattedMessage, 
>>>> LocalizedMessage, MessageFormatMessage and
>>>> -        ObjectMessage for asynchronous logging to ensure the formatted 
>>>> message does not change even if
>>>> +        Improved asynchronous loggers and appenders to ensure the 
>>>> formatted message does not change even if
>>>>      parameters are modified by the application. (ParameterizedMessage was 
>>>> already safe.)
>>>>      Improved documentation.
>>>>    </action>
>>> 
>>> 
>>> ---------------------------------------------------------------------
>>> To unsubscribe, e-mail: [email protected]
>>> For additional commands, e-mail: [email protected]
>> 
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: [email protected]
>> For additional commands, e-mail: [email protected]
> 
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: [email protected]
> For additional commands, e-mail: [email protected]
> 

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to