Drakes :
Without deserializing and reserializing the following deeply-nested JSON string (if this is possible), how to remove any key with the name "REMOVEME" from any nested level?
Tried:
Reluctantly tried deserializing to JsonObject
/ LinkedHashMap
to traverse the structure with node.remove(e.getKey())
on offending keys, but Gson throws concurrent modification exceptions, and Jackson requires full deserialization.
Before:
{
"a": {
"REMOVEME" : "unwanted",
"b": {
"REMOVEME" : "unwanted",
"c": {
"d": {
"REMOVEME" : "unwanted",
"something": "default",
"e": {
"f": {
"REMOVEME" : "unwanted",
"g": {
"REMOVEME" : "unwanted",
"h": {
... ,
After:
{
"a": {
"b": {
"c": {
"d": {
"something": "default",
"e": {
"f": {
"g": {
"h": {
... ,
Drakes :
One way to solve this is with streaming token-parsing with Gson. This method handles extremely large JSON strings with ease.
Example before and after:
{"a":{"removeme":"unwanted","b":{"c":{"removeme":{"x":1},"d":{"e":123}}}}}
{"a":{"b":{"c":{"d":{"e":123}}}}}
Essential test harness:
String rawJson = "{\"a\":{\"removeme\":\"unwanted\",\"b\":{\"c\":{\"removeme\":{\"x\":1},\"d\":{\"e\":123}}}}}";
final Gson gson = new GsonBuilder().create();
JsonReader reader = gson.newJsonReader( new StringReader( rawJson ) );
StringWriter outWriter = new StringWriter();
JsonWriter writer = gson.newJsonWriter( outWriter );
JsonStreamFilter.streamFilter( reader, writer, Arrays.asList( "removeme" ) );
System.out.println( rawJson );
System.out.println( outWriter.toString() );
Tokenizing and filtering magic:
public class JsonStreamFilter
{
/**
* Filter out all properties with names included in the `propertiesToRemove` list.
*
* @param reader JsonReader to read in the JSON token
* @param writer JsonWriter to accept modified JSON tokens
* @param propertiesToRemove List of property names to remove
* @throws IOException
* @see Gson docs at https://sites.google.com/site/gson/streaming
*/
public static void streamFilter(
final JsonReader reader,
final JsonWriter writer,
final List<String> propertiesToRemove
) throws IOException
{
while ( true )
{
JsonToken token = reader.peek();
switch ( token )
{
case BEGIN_ARRAY:
reader.beginArray();
writer.beginArray();
break;
case END_ARRAY:
reader.endArray();
writer.endArray();
break;
case BEGIN_OBJECT:
reader.beginObject();
writer.beginObject();
break;
case END_OBJECT:
reader.endObject();
writer.endObject();
break;
case NAME:
String name = reader.nextName();
// Skip all nested structures stemming from this property
if ( propertiesToRemove.contains( name ) )
{
reader.skipValue();
break;
}
writer.name( name );
break;
case STRING:
String s = reader.nextString();
writer.value( s );
break;
case NUMBER:
String n = reader.nextString();
writer.value( new BigDecimal( n ) );
break;
case BOOLEAN:
boolean b = reader.nextBoolean();
writer.value( b );
break;
case NULL:
reader.nextNull();
writer.nullValue();
break;
case END_DOCUMENT:
return;
}
}
}
}