2017-01-22 8 views
1

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ファイルの例:私はJSONの構造を知らないが、私はすべてフィルタリングする一般的に

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

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

所望の出力文字列の出現。

デシリアライザ:

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によって呼び出されません。

答えて

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 

出力:

{ "のmyString": "このstrin"、 "その他": "これは大丈夫です"}

このソリューションは、特定の種類のバックグラウンドを持たない、あらゆる種類のJSONで動作します。簡単に言えば、それはちょうどタイプ非認識であり、"foo-bar-baz-qux"のような単純な単一リテラルを処理することもできます。

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

プリント:(いくつかのカスタムJsonWriterを使用して)

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

もう1つ - 私はJSONの構造を知らない – pixel

+0

この場合は全く意味がありません。 jsonの構造がわからない場合は、なぜ静的型付けされたPOJOでJson文字列を変換するために 'gson'が必要ですか?文字列を処理します。 – Divers

+0

私はjson内で文字列値を制限したいので、基本レベルでjsonを解析する必要があります。 – pixel

1

この作品:

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" 
} 
+0

もう1つ - 私はJSONの構造を知らない – pixel

+0

@pixelここには 'JsonElement'を保つ別の解決策があります。 –

関連する問題