Adding JSON objects to existing JSON File

2019-09-21 06:22发布

问题:

So I've recently been tasked with creating a utility which will allow easy addition of JSON to a .json file via the gson library. I've coded this in Kotlin:

fun addObject(filePath: String, name: String, values: Array<Array<String>>) {
try {

    var writer: JsonWriter = JsonWriter(FileWriter(File(filePath)))
    writer.beginObject()
    writer.name(name)
    writer.beginObject()
    for(item in values){
        writer.name(item[0]).value(item[1])
    }
    writer.endObject()
    writer.endObject()

    writer.close()

    println("[JSONUtil] Wrote object successfully!")

} catch (e: IOException) {
    e.printStackTrace()
}
}

I used a 2 Dimensional array to allow the user to add different objects with any number of values in said object. For instance, you would run it like so:

addObject("C:\\Users\\Test\\Desktop\\JsonUtility\\output.json", "GENERAL", 
arrayOf(arrayOf("POS_X","2"), arrayOf("POS_Y","4")))

This creates the following JSON:

{"GENERAL":{"POS_X":"2","POS_Y":"4"}}

This is how it was intended and works, my issue is that upon running the function again it completely overwrites the previous JSON in the file, and this is obviously bad.

My questions are:

  • How can I add new JSON objects inside the entire file, or at specific points, like "addObject("GENERAL", ...)" for this example?

  • How can I make this better?

I'm fairly new to Kotlin and have been coding in Java mostly, so Java solutions are fine as I'm sure I'll be able to convert it.

Thanks in advance!

EDIT: New Code, no idea how to implement it:

fun UpdateJson(path: String, name: String, value: String){
    var gson = Gson()
    var reader: FileReader = FileReader(File(path))

    val type = object : TypeToken<Map<String, String>>() {}.type
    println("Type: " + type.toString())
    println("Existing Json: ${gson.fromJson<Map<String,String>>
    (JsonReader(reader), type)}")
    var existingJson: Map<String, String> = 
    gson.fromJson<Map<String,String>>(JsonReader(reader), type)
    existingJson.put(name, value)
    FileWriter(File(path)).use({ writer -> 
    writer.write(gson.toJson(existingJson)) })
}

回答1:

The easiest way is to, as @KrisRoofe suggested, read the json, then add an element. I would do this by converting the existing json in the file to a Map. Since you don't actually care about the existing json, all you want to do is add a new entry to that Map. Once you do that, simply write the new Map to the File. You can do this like so:

public class UpdateJson {
    public static void main(String[] args) throws IOException {
        addObject("example.json", "GENERAL", arrayOf(arrayOf("POS_X","2"), arrayOf("POS_Y","4")));
    }

    private static void addObject(String fileName, String newObjName, String newObjValue) throws IOException {
        Gson gson = new Gson();
        Type type = new TypeToken<Map<String, String>>(){}.getType();
        Map<String, String> existingJson = gson.fromJson(new JsonReader(new FileReader(new File(fileName))), type);
        existingJson.put(newObjName, newObjValue);
        try (FileWriter writer = new FileWriter(new File(fileName))) {
            writer.write(gson.toJson(existingJson));
        }
    }

    private static String arrayOf(String s1, String s2) {
        return "[" + s1 + ", " + s2 + "]";
    }
}

EDIT: The above solution is a Java solution. There seems to be an issue with the Type in Kotlin.

  1. This Stack Overflow question has a workaround by using object:
  2. Also, note that to use reflection with Kotlin, you need a separate jar, according to Kotlin documentation'

EDIT 2: Provided Kotlin Answer:

fun main(args: Array<String>) {
    addObject("example.json", "GENERAL", arrayOf(arrayOf("POS_X", "2"), arrayOf("POS_Y", "4")))
}


fun addObject(path: String, name: String, value: String) {
    val gson = Gson()
    val reader: FileReader = FileReader(File(path))
    val type = object : TypeToken<Map<String, String>>() {}.type
    System.out.println("Type: " + type.toString())
    val existingJson = gson.fromJson<Map<String, String>>(JsonReader(reader), type)
    System.out.println("Existing Json: ${existingJson}")
    val newJsonMap = existingJson.plus(Pair(name, value))
    FileWriter(File(path)).use(
        { writer -> writer.write(gson.toJson(newJsonMap)) }
    )
}

fun arrayOf(s1: String, s2: String): String {
    return "[$s1, $s2]"
}


标签: java json kotlin