I've knocked together a solution to this as discussed in Neuchatel (and elsewhere) based on delegates.
The idea is we provide a very thin delegate for each type of message, that basically just delegates to the "real" messages methods for read-only operations.
For methods that change the state of the message, e.g. setting headers, setting jmsproperties, or setting bodies, the delegate copies the relevant parts of the message.
If you only change the headers, it doesn't copy the properties or body, if you only change the properties it doesn't copy the body etc.
This means that if nothing is changed zero copying occurs and we can still guarantee the 3.9 and 3.10 of the JMS spec. :)
Previously we were copying the entire message twice - once on send, and again on receive, even if nothing was changed.