【问题标题】:Prevent GSON from serializing JSON string防止 GSON 序列化 JSON 字符串
【发布时间】:2015-08-29 05:41:45
【问题描述】:

我是 gson 的新手,并且有一些我没有找到答案的新问题,所以请多多包涵。 StackOverflow 和 google 不是我的朋友 :(

我有一个 java 类“User”,它的属性之一“externalProfile”是一个包含已序列化 JSON 的 Java 字符串。当 gson 序列化 User 对象时,它会将 externalProfile 视为原始对象,从而转义 JSON 添加额外的斜杠等。 我希望 gson 不理会字符串,只是“按原样”使用它,因为它已经是有效且可用的 JSON。

为了区分 JSON 字符串,我创建了一个名为 JSONString 的简单类,并尝试使用读取器/写入器 registerTypeAdapter,但没有任何效果。 你能帮帮我吗?

public class User {
    private JSONString externalProfile;
    public void setExternalProfile(JSONString externalProfile) { this.externalProfile = externalProfile; }

}

public final class JSONString {
    private String simpleString;
    public JSONString(String simpleString) { this.simpleString = simpleString; }
}

public customJsonBuilder(Object object) {
    GsonBuilder builder = new GsonBuilder();
        builder.registerTypeAdapter(GregorianCalendar.class, new JsonSerializer<GregorianCalendar>() {
            public JsonElement serialize(GregorianCalendar src, Type type, JsonSerializationContext context) {
                if (src == null) {
                    return null;
                }
                return new JsonPrimitive(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(src.getTime()));
            }
        });
        Gson gson = builder.create();
        return gson.toJson(object);
}

作为示例,externalProfile 将保存(作为字符串值):

{"profile":{"registrationNumber": 11111}}

在我将它作为 JSONString 存储在 User 对象中之后,我们将 user 对象转换为 JSON:

User user = new User();
user.setExternalProfile(new JSONString(externalProfile)),  
String json = customJsonBuilder(user);

json 将包含如下内容:

{\"profile\":{\"registrationNumber\": 11111}}

因此,gson 将 externalProfile JSONString 序列化为 String 原语,在双引号前添加额外的斜杠。 我希望 gson 保持这个 JSONString 不变,因为它已经是可用的 JSON。 我正在寻找一个类型适配器/读写器来执行此操作,但我无法让它工作。

【问题讨论】:

  • 能否提供输入示例,以便我们重现并尝试解决您的问题?
  • 嗨@Alexis C.,我已将其添加到我最初的问题中。谢谢!
  • 你签出sites.google.com/site/gson/…了吗?
  • 是的,我做了@Reek,但我确实想要响应中的 externalProfile!所以它应该是对象序列化输出的一部分,但我希望 gson 不理会它(并防止双重序列化)。
  • 嗯,一个肮脏的解决方案可能首先排除该属性并将其手动添加到序列化响应中。或者,先反序列化externalProfile,再序列化User?

标签: java json serialization gson


【解决方案1】:

正如亚历克西斯 C 所说:

首先将 externalProfile 存储为 JsonObject:

new Gson().fromJson(externalProfile, JsonObject.class));

并让 gson 在输出 User 对象时再次序列化它。 将产生完全相同的 JSON!

【讨论】:

    【解决方案2】:

    我在没有不必要的反序列化序列化的情况下解决了它。创建类:

    public class RawJsonGsonAdapter extends TypeAdapter<String> {
    
        @Override
        public void write(final JsonWriter out, final String value) throws IOException {
            out.jsonValue(value);
        }
    
        @Override
        public String read(final JsonReader in) throws IOException {
            return null; // Not supported
        }
    }
    

    并在需要的地方通过注释使用它。例如:

    public class MyPojo {
        @JsonAdapter(RawJsonGsonAdapter.class)
        public String someJsonInAString;
    
        public String normalString;
    }
    

    就是这样。正常使用 Gson。

    【讨论】:

      【解决方案3】:

      添加读取方法。

      public class RawJsonGsonAdapter extends TypeAdapter<String> {
      
          @Override
          public void write(final JsonWriter out, final String value) throws IOException {
              out.jsonValue(value);
          }
      
          @Override
          public String read(final JsonReader in) throws IOException {
              var sb = new StringBuilder();
              int n = 0;
              while (true) {    
                  switch (in.peek()) {
                  case BEGIN_ARRAY:
                      in.beginArray();
                      sb.append("[");
                      break;
                  case BEGIN_OBJECT:
                      in.beginObject();
                      sb.append("{");
                      n++;
                      break;
                  case BOOLEAN:
                      sb.append(in.nextBoolean()).append(",");
                      break;
                  case END_ARRAY:
                      dropLastComma(sb);
                      in.endArray();
                      sb.append("]");
                      break;
                  case END_DOCUMENT:
                      throw new RuntimeException("END_DOCUMENT invalid here");
                  case END_OBJECT:
                      dropLastComma(sb);
                      in.endObject();
                      sb.append("}");
                      if (--n == 0)
                          return sb.toString();
                      break;
                  case NAME:
                      sb.append("\"").append(in.nextName()).append("\":");
                      break;
                  case NULL:
                      in.nextNull();
                      sb.append("");
                      break;
                  case NUMBER:
                      try {
                          sb.append(in.nextInt()).append(",");
                          break;
                      } catch (Exception e1) {
                          try {
                              sb.append(in.nextLong()).append(",");
                              break;
                          } catch (Exception e2) {
                              sb.append(in.nextDouble()).append(",");
                              break;
                          }
                      }
                  case STRING:
                      sb.append("\"").append(in.nextString()).append("\",");
                      break;
                  }
              }
          }
      
          private void dropLastComma(StringBuilder sb) {
              if (sb.charAt(sb.length() - 1) == ',') {
                  sb.setLength(sb.length() - 1);
              }
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-01-18
        • 1970-01-01
        • 1970-01-01
        • 2016-01-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多