Pinkie Swirl Pinkie Swirl - 2 months ago 15
Java Question

Java 8 Base64 stream wrapper eats last two chars?

I have the following code:

public static String encode(Object object)
{
final String result;

try (ByteArrayOutputStream bOut = new ByteArrayOutputStream();
Output output = new Output(bOut))
{
KRYO.writeObject(output, object);
output.flush();
result = Base64.getUrlEncoder().encodeToString(bOut.toByteArray());
} catch (IOException e)
{
// Do nothing, should never happen!
throw new RuntimeException("MEGA FAIL");
}

return result;
}

public static String encodeTest(Object object)
{
final String result;

try (ByteArrayOutputStream bOut = new ByteArrayOutputStream();
OutputStream base64Out = Base64.getUrlEncoder().wrap(bOut);
Output output = new Output(base64Out))
{
KRYO.writeObject(output, object);
output.flush();
result = bOut.toString();
} catch (IOException e)
{
// Do nothing, should never happen!
throw new RuntimeException("MEGA FAIL");
}

return result;
}


Test:

String test = "asdf";
System.out.println(encode(test));
System.out.println(encodeTest(test));


gives the output (with kryo logger):

00:10 TRACE: [kryo] Write: asdf
00:10 TRACE: [kryo] Object graph complete.
YXNk5g==
00:10 TRACE: [kryo] Write: asdf
00:10 TRACE: [kryo] Object graph complete.
YXNk


So is there an error in my code?

Am I misusing the wrapper?

Is the error in kryo (tested with version 3.0.3 and 4.0.0)?

Answer

Per the documentation for Base64.Encoder.wrap(), you need to close the stream once you're done with it:

It is recommended to promptly close the returned output stream after use, during which it will flush all possible leftover bytes to the underlying output stream.

Calling bOut.toString() after the encoder stream is closed will fix the problem:

public static String encodeTest(Object object)
{
    ByteArrayOutputStream bOut = new ByteArrayOutputStream();
    try (OutputStream base64Out = Base64.getUrlEncoder().wrap(bOut);
         Output output = new Output(base64Out))
    {
        KRYO.writeObject(output, object);
    } catch (IOException e)
    {
        // Do nothing, should never happen!
        throw new RuntimeException("MEGA FAIL");
    }

    return bOut.toString();
}