使用GSON在string和byte[]之间转换JSON

hc8w905p  于 2022-11-06  发布在  其他
关注(0)|答案(5)|浏览(240)

我使用Hibernate将对象Map到数据库,客户端(一个iOS应用程序)以JSON格式发送给我特定的对象,我使用下面的实用程序方法将其转换为它们的真实表示:

/**
     * 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;
    }

然而问题是,在我的pogo中,我将值存储为byte[],如下所示(因为这是存储在数据库中的内容-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;

当然,转换会失败,因为它无法在byte[]和String之间进行转换。
这里最好的方法是将构造函数更改为接受字符串而不是字节数组,然后在设置字节数组值的同时自己进行转换,或者有更好的方法来完成此操作。
引发的错误如下所示;
com.google.gson.JsonSyntaxException:java.lang.IllegalStateException:预期为开始_ARRAY,但在第1行第96列路径$.optionalImage处为字符串

  • 谢谢-谢谢

Edit事实上,由于GSON生成对象的方式,即使是我建议的方法也不起作用。

yruzcnhs

yruzcnhs1#

您可以使用这个adapter来序列化和反序列化base64中的字节数组。

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));
        }
    }

感谢作者Ori Peleg

nukf8bse

nukf8bse2#

来自一些博客供将来参考,如果链接不可用,至少用户可以在这里参考。

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));
        }
    }
}
7ajki6be

7ajki6be3#

我需要解决方案符合OpenAPI规范,该规范规定格式字节的String类型必须保存base64编码值。POJO保存byte[],JSON对象具有String属性。
在我的例子中,我不能使用android库进行base64处理,因为后端应用程序使用了Gson序列化。出于这个原因,我使用了java提供的java.util.Base64类。
而不是基于JsonSerializer〈byte[]〉的适配器,JsonDeserializer〈byte[]〉接口我使用了**TypeAdapter〈byte[]〉**适配器。使用它,我可以覆盖Gson的HTML转义功能,以防止在base64编码中转义填充字符“=”。如果不这样做,则“hello World“的编码值将是 “aGVsbG8gV29ybGQ\u003d” 而不是 “aGVsbG8gV29ybGQ=" 而另一端反串行化器将失败。
下面是自定义适配器的代码:

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);
    }
  }
}
snvhrwxg

snvhrwxg4#

这对我来说很管用:

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();
kb5ga3dv

kb5ga3dv5#

您可以在POJO中简单地将照片取为String,在Setter方法中将String转换为byte[],在Getter方法中返回byte[

@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();
    }
}

相关问题