Base64 Encoding in Java 8

The lack of Base64 encoding API in Java is, in my opinion, by far one of the most annoying holes in the libraries. Finally Java 8 includes a decent API for it in the java.util package. Here is a short introduction of this new API (apparently it has a little more than the regular encode/decode API).

The java.util.Base64 Utility Class

The entry point to Java 8's Base64 support is the java.util.Base64 class. It provides a set of static factory methods used to obtain one of the three Base64 encodes and decoders:
  • Basic
  • URL
  • MIME

Basic Encoding

The standard encoding we all think about when we deal with Base64: no line feeds are added to the output and the output is mapped to characters in the Base64 Alphabet: A-Za-z0-9+/ (we see in a minute why is it important). Here is a sample usage:

// Encode 
String asB64 = Base64.getEncoder().encodeToString("some string".getBytes("utf-8"));
System.out.println(asB64); // Output will be: c29tZSBzdHJpbmc=

// Decode
byte[] asBytes = Base64.getDecoder().decode("c29tZSBzdHJpbmc=");
System.out.println(new String(asBytes, "utf-8")); // And the output is: some string

It can't get simpler than that and, unlike in earlier versions of Java, there is any need for external dependencies (commons-codec), Sun classes (sun.misc.BASE64Decoder) or JAXB's DatatypeConverter (Java 6 and above). However it gets even better.

URL Encoding

Most of us are used to get annoyed when we have to encode something to be later included in a URL or as a filename - the problem is that the Base64 Alphabet contains meaningful characters in both URIs and filesystems (most specifically the forward slash (/)). The second type of encoder uses the alternative "URL and Filename safe" Alphabet which includes -_ (minus and underline) instead of +/. See the following example:

String basicEncoded = Base64.getEncoder().encodeToString("subjects?abcd".getBytes("utf-8"));
System.out.println("Using Basic Alphabet: " + basicEncoded);

String urlEncoded = Base64.getUrlEncoder().encodeToString("subjects?abcd".getBytes("utf-8"));
System.out.println("Using URL Alphabet: " + urlEncoded);


The output will be:
Using Basic Alphabet: c3ViamVjdHM/YWJjZA==
Using URL Alphabet: c3ViamVjdHM_YWJjZA==

The sample above illustrates some content which if encoded using a basic encoder will result in a string containing a forward slash while when using a URL safe encoder the output will include an underscore instead (URL Safe encoding is described in clause 5 of the RFC)

MIME Encoding

The MIME encoder generates a Base64 encoded output using the Basic Alphabet but in a MIME friendly format: each line of the output is no longer than 76 characters and ends with a carriage return followed by a linefeed (\r\n). The following example generates a block of text (this is needed just to make sure we have enough 'body' to encode into more than 76 characters) and encodes it using the MIME encoder:

StringBuilder sb = new StringBuilder();
for (int t = 0; t < 10; ++t) {
 sb.append(UUID.randomUUID().toString());
}

byte[] toEncode = sb.toString().getBytes("utf-8");
String mimeEncoded = Base64.getMimeEncoder().encodeToString(toEncode);
System.out.println(mimeEncoded);


The output:
NDU5ZTFkNDEtMDVlNy00MDFiLTk3YjgtMWRlMmRkMWEzMzc5YTJkZmEzY2YtM2Y2My00Y2Q4LTk5
ZmYtMTU1NzY0MWM5Zjk4ODA5ZjVjOGUtOGMxNi00ZmVjLTgyZjctNmVjYTU5MTAxZWUyNjQ1MjJj
NDMtYzA0MC00MjExLTk0NWMtYmFiZGRlNDk5OTZhMDMxZGE5ZTYtZWVhYS00OGFmLTlhMjgtMDM1
ZjAyY2QxNDUyOWZiMjI3NDctNmI3OC00YjgyLThiZGQtM2MyY2E3ZGNjYmIxOTQ1MDVkOGQtMzIz
Yi00MDg0LWE0ZmItYzkwMGEzNDUxZTIwOTllZTJiYjctMWI3MS00YmQzLTgyYjUtZGRmYmYxNDA4
Mjg3YTMxZjMxZmMtYTdmYy00YzMyLTkyNzktZTc2ZDc5ZWU4N2M5ZDU1NmQ4NWYtMDkwOC00YjIy
LWIwYWItMzJiYmZmM2M0OTBm

Wrapping

All encoders and decoders created by the java.util.Base64 class support streams wrapping - this is a very elegant construct - both coding and efficiency wise (since no redundant buffering are needed) - to stream in and out buffers via encoders and decoders. The sample bellow illustrates how a FileOutputStream can be wrapped with an encoder and a FileInputStream is wrapped with a decoder - in both cases there is no need to buffer the content:

 public void wrapping() throws IOException {

   String src = "This is the content of any resource read from somewhere" +
   " into a stream. This can be text, image, video or any other stream.";

   // An encoder wraps an OutputStream. The content of /tmp/buff-base64.txt will be the
   // Base64 encoded form of src.
   try (OutputStream os = Base64.getEncoder().wrap(new FileOutputStream("/tmp/buff-base64.txt"))) {
     os.write(src.getBytes("utf-8"));
   }

   // The section bellow illustrates a wrapping of an InputStream and decoding it as the stream
   // is being consumed. There is no need to buffer the content of the file just for decoding it.
   try (InputStream is = Base64.getDecoder().wrap(new FileInputStream("/tmp/buff-base64.txt"))) {
     int len;
     byte[] bytes = new byte[100];
     while ((len = is.read(bytes)) != -1) {
       System.out.print(new String(bytes, 0, len, "utf-8"));
     }
   }
 }


Comments

Anonymous said…
If it's just Base64 Encoding you're looking for, than have a look at javax.xml.bind.DatatypeConverter. Added to Java SE since version 6 (December 2006).
Java String said…
good post. looking for more like this for java.
java training said…
Your technical information related with java programming is very useful and interesting. Also share updated details about java in your website. Thanks for sharing this article.

Tomek said…
Thank you for this clear explanation. I think it is very good that Java now supports Base64 encoding. BTW. I have just discovered that in one of my projects I use 2 different implementations (sun.misc and common-codec) added at different times. :)
Selva said…
Good one.. Thanks for sharing this.. love to read some more on the same topic..
dovy said…
These examples are very useful and easy understand. Thank you from Hanoi :)
grails hql said…
It's about time that java include this feature
Anonymous said…
Thanks for posting this.

I have been looking for a couple of hours on cogent examples on how to use java.util.Base64. It's a pity that Oracle don't have an example among all of their documentation.
Unknown said…
Nice Article you can read more about base 64 encoding using Java 8 at Modern Pathshala

Popular posts from this blog

New in Spring MVC 3.1: CSRF Protection using RequestDataValueProcessor

Hibernate Exception - Simultaneously Fetch Multiple Bags

Hibernate Derived Properties - Performance and Portability