-1

I'm trying to get raw xml of SOAPMessage object and I'm doing that using ByteArrayOutputStream class, but its losing readability once there's compressed attachment added to the message object.

Here's my code:

ByteArrayOutputStream out = new ByteArrayOutputStream();
message.writeTo(out);
strMsg = new String(out.toByteArray());

where message is SOAPMessage object. The problem is, when I print it to the stdout or logs, or some other output, strMsg might be huge and contain byte data of compressed attachment. Is there a way to truncate it at the moment of writing message to ByteArrayOutputStream object? I know, that I can easily truncate strMsg, but I don't see a reason to collect all the data inside ByteArrayOutputStream.

erhesto
  • 1,176
  • 7
  • 20
  • If the data is compressed it doesn't *have* any readability to lose, and you don't have any business trying to turn it into a String in the first place. Unclear what you're really asking. – user207421 Apr 23 '16 at 01:09
  • @EJP - It is pretty clear to me. He is trying to capture the SOAP messages in a log without filling up the log file with vasts amounts of unreadable stuff when there are attachments. – Stephen C Apr 23 '16 at 01:29
  • @StephenC So he needs to get the pieces of the message that are readable, via the `SoapMessage` API, and log those. Not convert the whole thing to a `ByteArrayOutputStream` and then a `String`, which doesn't begin to accomplish that objective. – user207421 Apr 24 '16 at 01:53
  • 1
    @EJP .... so write an Answer! – Stephen C Apr 24 '16 at 03:12

1 Answers1

1

I know, that I can easily truncate strMsg, but I don't see a reason to collect all the data inside ByteArrayOutputStream.

The problem is that you only have the writeTo method to work with, and that is designed to output the entire message.

You could create a custom variant of ByteArrayOutputStream that will only accept a specified number of bytes. When if writeTo exceeds the limit, your class needs to throw an IO exception.

The practical problem is that creating and throwing an exception is expensive. This is the real basis for the mantra "Only use exceptions in exceptional case" - https://softwareengineering.stackexchange.com/questions/184654/ive-been-told-that-exceptions-should-only-be-used-in-exceptional-cases-how-do. If you are logging lots of SOAP messages, that could be a problem.

The main performance bottleneck for exception creation / throwing is actually the creation of the exception object: specifically the part where the Throwable constructor calls fillInStacktrace to capture the stack frames. There are a couple of ways to ameliorate this:

  • Instead of new-ing an exception object each time, you can create one instance, cache it in a "global" and reuse it multiple times.

  • If the exception is a custom one, you can override its fillInStacktrace method to do nothing.

In both cases, you end up with exceptions that will give you incorrect results if you try to print the stacktraces. But if you are using exceptions to implement a "non-exceptional" code path ('cos you have no real alternative!) then that's probably not relevant.


There is a variant of my solution above where custom byte sink class silently throws away bytes instead of throwing an exception. That avoids the cost of exceptions (but see above), but it does not avoid the unnecessary work that writeOut is doing when serializing a large SOAP message to a byte sink that has "stopped listening".


The other thing to note is truncating after a certain number of bytes is liable to break if you are using a multi-byte character encoding such as UTF-8. Consider what happens if you truncate at 100 bytes, and the 100th byte is in the middle of a character. Note that the behavior of new String(byte[]) is unspecified if byte[] contains sequences that are not valid characters in the default characterset.

Community
  • 1
  • 1
Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
  • Why is four-fiths of this answer about exceptions? When you're outputting large amounts of data the minor overhead of an exception, if you get one at all, isn't relevant. There's no real reason why the class shoudld throw an exception at all actually. But why he isn't using `writeTo(System.out)`, or indeed why he is trying to log compressed data at all, is the real question. – user207421 Apr 23 '16 at 01:16
  • @EJP - It depends on how often the exception is thrown, and the spread of message sizes. Anyway, I write answers the way I write them, because that's what >>I<< think the reader needs to know. Feel free to write your own Answer if you think different things need to be said. – Stephen C Apr 23 '16 at 01:22
  • @EJP - *"There's no real reason why the class shoudld throw an exception at all actually."* - Actually there is. The `writeTo` method is doing a lot of work (e.g. XML DOM unparsing) to generate the bytes of the serialization. If you throw the exception, then you save a bunch of unnecessary work. (Yes, I did consider the alternative where the custom BAOS just eats characters.) – Stephen C Apr 23 '16 at 01:26