Base64 Encoding and Decoding Example in Java 8 and before

Though, there are a couple of ways to Base64 encode a String in Java e.g. by using Java 6's javax.xml.bind.DatatypeConverter#printBase64Binary(byte[]) or by using Apache Commons Codec's Base64.encodeBase64(byte[) and Base64.decodeBase64(byte[])as shown here, or the infamous Sun's internal base64 encoder and decoder, sun.misc.BASE64Encoder().encode() and sun.misc.BASE64Decoder().decode(), there was no standard way in JDK API itself. That was one of the few missing item (another one is about joining string) which is addressed in Java 8. The JDK 8 API contains a Base64 class in java.util package which supports both encoding and decoding text in Base64. You can use Base64.Encoder to encode a byte array or String and Base64.Decoder to decode a base64 encoded byte array or String in Java 8.

The JDK 8 API also provides different types of Base64 encoder e.g. basic, URL and MIME to support different needs. I'll tell you what is the difference between Basic, URL and MIME Base64 encoder and why you need in this article, but before that let's revise what is base64 encoding itself?

The Base64 Encoding is an encoding scheme which uses 64 printable characters (A-Za-z0-9+/) to replace each character in original String in an algorithmic way so that it can be decoded later. The process which converts original String to something else is known as encoding and the reverse process to convert an encoded String to original content is known as decoding.

You can further read, Code: The Hidden Language of Computer Hardware and Software to learn more about the history of text encoding, it explains Morse code, Brail, and several others including ASCII.

The base64 is one of the oldest encoding scheme, which prevents misuse of data by encoding into ASCII format. Even though there are more advanced encoding and encryption schemes available e.g. MD5 or RSH-SHA, Base64 is the best for simple encoding needs.



JDK 8 Base64 class provides three types of encoder and decoder:
  1. Basic
  2. URL
  3. MIME
The reason for that is the character used in Basic encoding is not URL safe or filename e.g. it uses "\" as one of the encoding character, which is a valid character in URL and PATH. The URL base64 encoder instead uses - and _ (minus and underscore) to encode a String, which can then be safely attached to a URL. You can use the Base64.getUrlEncoder() method to retrieve a URL base encoder in Java 8.

Similarly, The MIME encoder generates a Base64 encoded String using the basic alphabets (A-Za-Z0-9) but in an 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), which is not the case with Basic base64 encoding. You can use the Base64.getMimeEncoder() method to retrieve a MIME Base64 encoder. See Java SE 8 for Really Impatient by Cay S. Horstmann to learn more about basic and MIME base64 encoding in Java 8.

Now lets some example of base64 encoding and decoding in Java 8



Base64 Basic Encoding Example

As I said before, the Basic encoder uses + and \ along with alphabets and digits. In order to encode a String in Base64 using this Encoder follow below steps

- get the Basic encder by calling Base64.getEncoder()
- convert String to byte array, use StandardCharSet.UTF_8 instead of "UTF-8" String
- call the encodeToString(byte[]), result is your base 64 encoded String

In order to decode just reverse the process, get the Decoder, pass the encoded String, receive the byte array and convert it to String using new String(byte[]) constructor, make sure you use the same character encoding.

Here is an example:

String original = "It's a secret that C++ developer are better than Java";
byte[] bytes = original.getBytes(StandardCharsets.UTF_8);
String base64Encoded = Base64.getEncoder().encodeToString(bytes);
System.out.println("original text: " + original); 
System.out.println("Base64 encoded text: " + base64Encoded);

// Decode
byte[] asBytes = Base64.getDecoder().decode(base64Encoded);
String base64Decoded = new String(asBytes, StandardCharsets.UTF_8);
System.out.println("Base64 decoded text: " + base64Decoded); 

Output
original text: It's a secret that C++ developer are better than Java
Base64 encoded text: SXQncyBhIHNlY3JldCB0aGF0IEMrKyBkZXZlbG9wZXIgYXJlIGJldHRlciB0aGFuIEphdmE=
Base64 decoded text: It's a secret that C++ developer are better than Java

Base64 Encoding and Decoding Example in Java 6 and 8


Base64 URL Encoding Example

If you want to send base64 encoded6 String as part of URL or use it inside system file path, you should use this encoder. It uses - and _ (minus and underline) instead of + and / to encode text to base64. The result is a URL safe String. The steps are same as previous, except that this time you need to call the Base64.getUrlEncoder() method to retrieve the URL encoder.

Here is an example of how to use Base64 URL encoder and how it's different from Basic encoder:

// Base64 encoding using URL encoder
String basicEncoded = Base64.getEncoder()
.encodeToString("JavaOrScala?".getBytes(StandardCharsets.UTF_8));
System.out.println("Using Basic encoding: " + basicEncoded);

String urlEncoded = Base64.getUrlEncoder()
.encodeToString("JavaOrScala?".getBytes(StandardCharsets.UTF_8));
System.out.println("Using URL encoding: " + urlEncoded);

Output
Using Basic encoding: SmF2YU9yU2NhbGE/
Using URL encoding: SmF2YU9yU2NhbGE_

You can see that in URL encoder, forward slash(/) is replaced with _ (underscore). Now for decoding, you can just follow the steps given in the previous example using getUrlDecoder() method. See Java SE8 for Programmers (3rd Edition) by Deitel and Deitel for more examples on base64 encoding and decoding in Java 8.

Base64 Encoding and Decoding in Java 8




MIME URL Encoding Example
The third type of Base64 encoder provided by JDK 8 is used to encode MIME content, where each line is not more than 76 character and ends with \r\n. You can obtain a MIME type of Base64 encoder using getMimeEncoder() method as shown in the following example:

// Base64 encoding using MIME encoder
String text = "Best Credit Card for Student is something which 
                give maximum rebate to Student"
+ "when they purchase books, courses and other stationary items";
String mimeEndoded = Base64.getMimeEncoder()
                        .encodeToString(text.getBytes(StandardCharsets.UTF_8));
System.out.println("original string: " + text);
System.out.println("base65 encoded using MIME encoder: ");
System.out.println(mimeEndoded);

// Base64 decoding
byte[] decodedBytes = Base64.getMimeDecoder().decode(mimeEndoded);
String mimeDecoded = new String(decodedBytes, StandardCharsets.UTF_8);
System.out.println("MIME decoded String: " + mimeDecoded);

Output
base65 encoded using MIME encoder: 
QmVzdCBDcmVkaXQgQ2FyZCBmb3IgU3R1ZGVudCBpcyBzb21ldGhpbmcgd2hpY2ggZ2l2ZSBtYXhp
bXVtIHJlYmF0ZSB0byBTdHVkZW50d2hlbiB0aGV5IHB1cmNoYXNlIGJvb2tzLCBjb3Vyc2VzIGFu
ZCBvdGhlciBzdGF0aW9uYXJ5IGl0ZW1z
MIME decoded String: Best Credit Card for Student is something 
which give maximum rebate to Studentwhen they purchase books, courses and 
other stationary items

You can see in Base64 encoded text, each line is 70 characters long because we have used the MIME Base64 encoder.



Important points

Based on my experience in Java, following are some worth remembering point about Base64 encoding and decoding:

1) Use Apache Commons' Codec's Base64.encodeBase64() and Base64.decodeBase64() prior to Java 6 for encoding a String in base64 and decoding.

2) Don't use Sun's sun.misc.BASE64Encoder and sun.misc.BASE64Decoder as they are Sun's internal classes and can be removed without any notice. They are also only available on Oracle or Sun JDK, you won't get them in other JVM. Though, they are still lurking around even in Java 8 :-)

3) The difference between Basic and URL Base64 encoder is that later is URL safe. It uses - and _ instead of / and + to encode String which can be used in URL safely. If you know forward slash (/) has a different meaning in URL.

4) The MIME Base64 Encoder generate output which is no longer 76 characters and ends with \r\n

5) In Java 6, you can use also use JAXB's DatatypeConverter for encoding a String into base64 in Java e.g. by using method printBase64Binary(byte[]) of javax.xml.bind.DatatypeConverter class.

6) Make sure you use the same type of Base64 decoder e.g. Basic, URL or MIME which you have used while encoding. Using a different type of encoder will result in error or incorrect output.



Java Program to Base64 Encoding and Decoding String

Here is our complete Java program to demonstrate the use of all three types of Base64 encoder in Java 8. You can run this example to get more sense of how Base64 encoding works in Java 8:

package test;

import java.nio.charset.StandardCharsets;
import java.util.Base64;

/**
 * Java Program to show how to base64 encode and decode text in Java 8. It also
 * shows use of different types of Base64 encoder in Java
 */
public class Base64Demo {

  public static void main(String[] args) {

    // Base64 encoding and decoding in Java 8
    // let's use Basic encoding first

    // Encode
    String original = "It's a secret that C++ developer are better than Java";
    byte[] bytes = original.getBytes(StandardCharsets.UTF_8);
    String base64Encoded = Base64.getEncoder().encodeToString(bytes);
    System.out.println("original text: " + original);
    System.out.println("Base64 encoded text: " + base64Encoded);

    // Decode
    byte[] asBytes = Base64.getDecoder().decode(base64Encoded);
    String base64Decoded = new String(asBytes, StandardCharsets.UTF_8);
    System.out.println("Base64 decoded text: " + base64Decoded);

    // Base64 encoding using URL encoder
    String basicEncoded = Base64.getEncoder().encodeToString(
        "JavaOrScala?".getBytes(StandardCharsets.UTF_8));
    System.out.println("Using Basic encoding: " + basicEncoded);

    String urlEncoded = Base64.getUrlEncoder().encodeToString(
        "JavaOrScala?".getBytes(StandardCharsets.UTF_8));
    System.out.println("Using URL encoding: " + urlEncoded);

    // Base64 encoding using MIME encoder
    String text = "Best Credit Card for Student is something which give maximum rebate to Student"
        + "when they purchase books, courses and other stationary items";
    String mimeEndoded = Base64.getMimeEncoder().encodeToString(
        text.getBytes(StandardCharsets.UTF_8));
    System.out.println("original string: " + text);
    System.out.println("base65 encoded using MIME encoder: ");
    System.out.println(mimeEndoded);

    // Base64 decoding
    byte[] decodedBytes = Base64.getMimeDecoder().decode(mimeEndoded);
    String mimeDecoded = new String(decodedBytes, StandardCharsets.UTF_8);
    System.out.println("MIME decoded String: " + mimeDecoded);
  }

}


That's all about how to encode and decode a String in base64 in Java 6 and 8. We have discussed several options for Base64 encoding depending upon the Java version you are running, though the standard way is to use the JDK 8 Base64 class from Java 8 onward. It is also more feature rich and provides Basic, URL and MIME Base64 encoder and decoder. It's also faster than Sun and Apache's encoder for most of the input. In Java 6, you can also use JAXB's DatatypeConverter for base64 encoding.

Other Java tutorials you may like to explore
  • How to get the default character encoding in Java? (answer)
  • How to base 64 encode and decode using Apache Commons Codec? (tutorial)
  • Difference between UTF-8, UTF-16, and UTF-32 encoding? (answer)
  • Difference between URL rewriting and URL encoding in Servlet? (answer)
  • How to convert byte array to String in Java? (example)
  • How to generate MD5 hash in Java? (tutorial)
  • 10 Articles Every Programmer Should Read (article)


References
Base64.Encoder in Java SE 8
Base64 Encoding



No comments:

Post a Comment