使用gson在json中剪切太长的字符串

时间:2017-01-22 17:19:26

标签: java json gson

我想在json中删除太长的字符串。

为了做到这一点,我想为String类型注册新类型的适配器,在这个反序列化器中,我将检查并限制太长的字符串。

Gson gson = new GsonBuilder().registerTypeAdapter(String.class, new CuttingStringDeserializer()).create();
JsonElement element = gson.fromJson(jsonString, JsonElement.class);
return new GsonBuilder().setPrettyPrinting().create().toJson(element);

我要处理的json文件示例:

{
    "myString": "this string is too long - cut it",
    "other": "this is ok"
}

期望的输出:

{
    "myString": "this strin",
    "other": "this is ok"
}

一般来说,我不知道json的结构,但我想过滤掉所有字符串的出现。

解串器:

public class CuttingStringDeserializer implements JsonDeserializer<String> {

  @Override
  public String deserialize(final JsonElement json, final Type typeOfT, final JsonDeserializationContext context)
      throws JsonParseException {

      String s = json.getAsString();

    if(s.lenght() > MAX_CONTENT_LENGTH){
        return s.substring(0, MAX_CONTENT_LENGTH);
    }else{
        return s;
  }
}

不幸的是我的自定义反序列化器不是由gson调用的。

3 个答案:

答案 0 :(得分:1)

对我来说,你想要存档的内容似乎没有意义,但是这里开始应该有用的代码。

public class Main {
    private static String json = "{\"myString\": \"this string is too long - limit it\",\"other\": \"this is ok\"}";

    public static void main(String... var) {
        System.out.print(cutJson(json));
    }

    public static String cutJson(String json) {
        Type type = new TypeToken<Map<String, String>>() {
        }.getType();
        Gson gson = new GsonBuilder().registerTypeAdapter(type, new CuttingStringDeserializer()).create();
        Map<String, String> element = gson.fromJson(json, type);
        return new GsonBuilder().setPrettyPrinting().create().toJson(element);
    }

    private static class CuttingStringDeserializer implements JsonDeserializer<Map<String, String>> {

        @Override
        public Map<String, String> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
            Iterator<Map.Entry<String, JsonElement>> iterator = ((JsonObject) json).entrySet().iterator();
            Map<String, String> result = new HashMap<String, String>();
            while (iterator.hasNext()) {
                Map.Entry<String, JsonElement> entry = iterator.next();
                if (entry.getValue().getAsString().length() > 10) {
                    entry.setValue(new JsonPrimitive(entry.getValue().getAsString().substring(0, 9)));
                }
                result.put(entry.getKey(), entry.getValue().getAsString());
            }
            return result;
        }
    }
}

打印:

{
  "myString": "this stri",
  "other": "this is ok"
}

答案 1 :(得分:1)

这(使用一些自定义JsonWriter)有效:

package so41793888;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonElement;
import com.google.gson.stream.JsonWriter;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;

import java.io.IOException;
import java.io.StringWriter;

public class Demo {

    public static void main(String[] args) {
        String jsonString = "{\n" +
                "    \"myString\": \"this string is too long - cut it\",\n" +
                "    \"other\": \"this is ok\"\n" +
                "}";
        Gson gson = new GsonBuilder().create();
        JsonElement element = gson.fromJson(jsonString, JsonElement.class);
        StringWriter out = null;
        try {
            out = new StringWriter();
            new GsonBuilder().create().toJson(element, new MyJsonWriter(out));
            System.out.println(out.getBuffer().toString());
        } finally {
            IOUtils.closeQuietly(out);
        }
    }

    private static class MyJsonWriter extends JsonWriter {

        public MyJsonWriter(final StringWriter out) {
            super(out);
            setIndent("  ");
        }

        @Override
        public JsonWriter value(final String value) throws IOException {
            return super.value(StringUtils.abbreviate(value, 12));
        }
    }
}

输出:

{
  "myString": "this stri...",
  "other": "this is ok"
}

答案 2 :(得分:1)

您可以拒绝树处理的想法(JsonSerializerJsonDeserializer的工作方式),支持流处理,您可以自己分析每个令牌。 GsonBuilder似乎也不允许覆盖流式TypeAdapters,但您可以使用JsonReader来解析输入流中的每个令牌,并JsonWriter将处理过的令牌发送到输出流。这可能看起来太低了,但由于它是一种流媒体方式,它非常便宜并且不会像树处理那样消耗太多内存。因此,您甚至可以处理无限的流。

@SuppressWarnings("resource")
private static void trim(final int maxStringLength, final Reader reader, final Writer writer)
        throws IOException {
    // a specifically configured IDEA complains for the unclosed jsonReader, but invoking the `close` method is a like a chain and sometimes undesirable
    @SuppressWarnings("all")
    final JsonReader jsonReader = new JsonReader(reader);
    // the same goes to jsonWriter
    @SuppressWarnings("all")
    final JsonWriter jsonWriter = new JsonWriter(writer);
    for ( JsonToken token; (token = jsonReader.peek()) != END_DOCUMENT; ) {
        switch ( token ) {
        case BEGIN_ARRAY:
            // merely reflect a BEGIN_ARRAY token
            jsonReader.beginArray();
            jsonWriter.beginArray();
            break;
        case END_ARRAY:
            // merely reflect an END_ARRAY token
            jsonReader.endArray();
            jsonWriter.endArray();
            break;
        case BEGIN_OBJECT:
            // merely reflect a BEGIN_OBJECT token
            jsonReader.beginObject();
            jsonWriter.beginObject();
            break;
        case END_OBJECT:
            // merely reflect an END_OBJECT token
            jsonReader.endObject();
            jsonWriter.endObject();
            break;
        case NAME:
            // merely reflect NAME tokens (or trim?)
            jsonWriter.name(jsonReader.nextName());
            break;
        case STRING:
            // trimming a STRING token if necessary
            final String string = jsonReader.nextString();
            jsonWriter.value(string.length() > maxStringLength ? string.substring(0, maxStringLength) : string);
            break;
        case NUMBER:
            // NUMBER tokens are a bit complex because JSON only denotes a double number that can be literally an integer
            final String rawNumber = jsonReader.nextString();
            try {
                // try to write the biggest integer number supported by Java, floating points also fail to be parsed as long values
                jsonWriter.value(parseLong(rawNumber));
            } catch ( final NumberFormatException nex1 ) {
                try {
                    // not a long value, then perhaps it's a double value?
                    jsonWriter.value(parseDouble(rawNumber));
                } catch ( final NumberFormatException nex2 ) {
                    // can't think of specific cases here...
                    throw new AssertionError("Must not happen", nex2);
                }
            }
            break;
        case BOOLEAN:
            // merely reflect BOOLEAN tokens
            jsonWriter.value(jsonReader.nextBoolean());
            break;
        case NULL:
            // merely reflect NULL tokens
            jsonReader.nextNull();
            jsonWriter.nullValue();
            break;
        case END_DOCUMENT:
            // fall through, because this type of tokens is checked above, and it's fine to throw an assertion error
        default:
            throw new AssertionError(token);
        }
    }
}

当然,这种方法不支持漂亮的打印,但如果真的有必要,可以很容易地实现。

它是如何使用的:

final Reader reader = new StringReader("{\"myString\":\"this string is too long - cut it\",\"other\":\"this is ok\"}");
final Writer writer = new OutputStreamWriter(System.out); // redirect the output to System.out
trim(10, reader, writer);
writer.flush(); // flushing at a call-site, we decide

输出:

  

{&#34; myString&#34;:&#34;这个strin&#34;,&#34;其他&#34;:&#34;这没关系&#34;}

该解决方案可以使用任何类型的JSON,没有特定类型的背景。简单来说,它只是类型不知道,甚至可以处理像"foo-bar-baz-qux"这样简单的单一文字。