J'utilise hibernate pour mapper des objets à la base de données. Un client (une application iOS) m'envoie des objets particuliers au format JSON que je convertis en leur représentation vraie à l'aide de la méthode d'utilitaire suivante
/**
* Convert any json string to a relevant object type
* @param jsonString the string to convert
* @param classType the class to convert it too
* @return the Object created
*/
public static <T> T getObjectFromJSONString(String jsonString, Class<T> classType) {
if(stringEmptyOrNull(jsonString) || classType == null){
throw new IllegalArgumentException("Cannot convert null or empty json to object");
}
try(Reader reader = new StringReader(jsonString)){
Gson gson = new GsonBuilder().create();
return gson.fromJson(reader, classType);
} catch (IOException e) {
Logger.error("Unable to close the reader when getting object as string", e);
}
return null;
}
Le problème cependant est que, dans mon pogo, je stocke la valeur sous forme d'octet [], comme on peut le voir ci-dessous (car c'est ce qui est stocké dans la base de données - un blob)
@Entity
@Table(name = "PersonalCard")
public class PersonalCard implements Card{
@Id @GeneratedValue
@Column(name = "id")
private int id;
@OneToOne
@JoinColumn(name="userid")
private int userid;
@Column(name = "homephonenumber")
protected String homeContactNumber;
@Column(name = "mobilephonenumber")
protected String mobileContactNumber;
@Column(name = "photo")
private byte[] optionalImage;
@Column(name = "address")
private String address;
Bien entendu, la conversion échoue car elle ne peut pas convertir un octet [] en une chaîne.
La meilleure approche consiste ici à changer le constructeur pour qu'il accepte une chaîne au lieu d'un tableau d'octets, puis effectue la conversion moi-même tout en définissant la valeur du tableau d'octets, ou existe-t-il une meilleure approche pour ce faire?.
L'erreur renvoyée est la suivante.
com.google.gson.JsonSyntaxException: Java.lang.IllegalStateException: BEGIN_ARRAY attendu mais chaîne était STRING à la ligne 1 de la colonne 96 chemin $ .optionalImage
Merci
Edit En fait, même l'approche que j'ai suggérée ne fonctionnera pas à cause de la manière dont GSON génère l'objet.
Vous pouvez utiliser cet adaptateur adapter pour sérialiser et désérialiser des tableaux d'octets en base 64. Voici le contenu.
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));
}
}
Crédit à l'auteur Ori Peleg .
À partir de certains blogs pour référence future, si le lien n'est pas disponible, les utilisateurs au moins peuvent se référer ici.
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));
}
}
}
Vous pouvez simplement prendre la photo sous forme de chaîne dans POJO et dans la méthode Setter, convertir String en octet [] et renvoyer octet [] dans la méthode Getter
@Entity
@Table(name = "PersonalCard")
public class PersonalCard implements Card
{
@Id @GeneratedValue
@Column(name = "id")
private int id;
@OneToOne
@JoinColumn(name="userid")
private int userid;
@Column(name = "homephonenumber")
protected String homeContactNumber;
@Column(name = "mobilephonenumber")
protected String mobileContactNumber;
@Column(name = "photo")
private byte[] optionalImage;
@Column(name = "address")
private String address;
@Column
byte[] optionalImage;
public byte[] getOptionalImage()
{
return optionalImage;
}
public void setOptionalImage(String s)
{
this.optionalImage= s.getBytes();
}
}