Converting JSON between string and byte[] with GSON
You can use this adapter to serialize and deserialize byte arrays in base64. Here's the content.
public static final Gson customGson = new GsonBuilder().registerTypeHierarchyAdapter(byte[].class,
new ByteArrayToBase64TypeAdapter()).create();
// Using Android's base64 libraries. This can be replaced with any base64 library.
private static class ByteArrayToBase64TypeAdapter implements JsonSerializer<byte[]>, JsonDeserializer<byte[]> {
public byte[] deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
return Base64.decode(json.getAsString(), Base64.NO_WRAP);
}
public JsonElement serialize(byte[] src, Type typeOfSrc, JsonSerializationContext context) {
return new JsonPrimitive(Base64.encodeToString(src, Base64.NO_WRAP));
}
}
Credit to the author Ori Peleg.
This is works for me:
Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss")
.registerTypeAdapter(byte[].class, (JsonSerializer<byte[]>) (src, typeOfSrc, context) -> new JsonPrimitive(new String(src)))
.registerTypeAdapter(byte[].class, (JsonDeserializer<byte[]>) (json, typeOfT, context) -> json == null ? null : json.getAsString() == null ? null : json.getAsString().getBytes())
.create();
From some blog for future reference, incase the link is not available, atleast users can refer here.
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
import java.lang.reflect.Type;
import java.util.Date;
public class GsonHelper {
public static final Gson customGson = new GsonBuilder()
.registerTypeAdapter(Date.class, new JsonDeserializer<Date>() {
@Override
public Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
return new Date(json.getAsLong());
}
})
.registerTypeHierarchyAdapter(byte[].class,
new ByteArrayToBase64TypeAdapter()).create();
// Using Android's base64 libraries. This can be replaced with any base64 library.
private static class ByteArrayToBase64TypeAdapter implements JsonSerializer<byte[]>, JsonDeserializer<byte[]> {
public byte[] deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
return Base64.decode(json.getAsString(), Base64.NO_WRAP);
}
public JsonElement serialize(byte[] src, Type typeOfSrc, JsonSerializationContext context) {
return new JsonPrimitive(Base64.encodeToString(src, Base64.NO_WRAP));
}
}
}
I needed the solution to comply with the OpenAPI specification that states String type of format byte has to hold base64 encoded values. POJO holds byte[] and JSON object has String property.
In my case I couldn't use android library for base64 processing as Gson serialization was used in backend application. For this reason I used java provided java.util.Base64 class.
Instead of adapter based on JsonSerializer<byte[]>, JsonDeserializer<byte[]> interfaces I used TypeAdapter<byte[]> adapter. With it I could override HTML escaping functionality of Gson to prevent escaping padding character '=' in base64 encoding. If this isn't done then encoded value of "hello World"would be "aGVsbG8gV29ybGQ\u003d" instead of "aGVsbG8gV29ybGQ=" and deserializer on other side would fail.
Below is the code of custom adapter:
public class ByteArrayAdapter extends TypeAdapter<byte[]> {
@Override
public void write(JsonWriter out, byte[] byteValue) throws IOException {
boolean oldHtmlSafe = out.isHtmlSafe();
try {
out.setHtmlSafe(false);
out.value(new String(Base64.getEncoder().encode(byteValue)));
} finally {
out.setHtmlSafe(oldHtmlSafe);
}
}
@Override
public byte[] read(JsonReader in) {
try {
if (in.peek() == JsonToken.NULL) {
in.nextNull();
return new byte[]{};
}
String byteValue = in.nextString();
if (byteValue != null) {
return Base64.getDecoder().decode(byteValue);
}
return new byte[]{};
} catch (Exception e) {
throw new JsonParseException(e);
}
}
}