我想在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调用的。
答案 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)
您可以拒绝树处理的想法(JsonSerializer
和JsonDeserializer
的工作方式),支持流处理,您可以自己分析每个令牌。 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"
这样简单的单一文字。