web-dev-qa-db-fra.com

Conversion de JSON entre chaîne et octet [] avec GSON

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.

8
Biscuit128

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

18
Ken de Guzman

À 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));
        }
    }
}
2
Ankur Singhal

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();
    }
}
0
yogendra saxena