Bruno
Bruno

Reputation: 432

Modify and re-write key from json file

I'm currently having some problems with the JSON file in java. The goal here is to modify every "timestamp_ms" present at the JSON file to UTC time and date

My code input the JSON file, read it and output it in JSON format like I want at the end. Then I iterate through all the timestamp_ms and convert them.

I want now to replace all that timestamp_ms with the output I get and rewrite the file to JSON format again (now with the timestamp_ms converted). I've roamed at SO answers but no success so far. Can anyone know a good way to achieve this?

Here's the code:

public class JsonMain {
    public static void main(String[] args) throws IOException {
        String first = "chatMessage.json";
        String jsonSource = new String((Files.readAllBytes(Paths.get(first))),"UTF-8");
        //print the json file
        System.out.println(jsonSource);

        JSONObject obj = new JSONObject(jsonSource);
        JSONArray arr = new JSONArray(obj.getJSONArray("messages"));

        //iterate trough all the timestamp_ms and get the value
        for(int i=0; i< arr.length(); i++)
        {
            long time = (long)arr.getJSONObject(i).get("timestamp_ms");
            SimpleDateFormat sdf = new SimpleDateFormat();
            sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
            System.out.println(sdf.format(new Date(time)));
            //arr.put("timestamp_ms",sdf.format(new Date(time)));
        }

    }
}

Heres the json file chatMessage.json

{
  "participants": [
    {
      "name": "User1"
    },
    {
      "name": "User2"
    }
  ],
  "messages": [
    {
      "sender_name": "User1",
      "timestamp_ms": 1620663455808,
      "content": "Hello ç á à â ã ",
      "type": "Generic",
      "is_unsent": false
    },
    {
      "sender_name": "User2",
      "timestamp_ms": 1620663401347,
      "content": "Hi, how are you?",
      "type": "Generic",
      "is_unsent": false
    },
    {
      "sender_name": "User1",
      "timestamp_ms": 1620662999730,
      "content": "\u00c3\u0089 to utf?",
      "type": "Generic",
      "is_unsent": false
    }
  ],
  "title": "chatTitle",
  "is_still_participant": true,
  "thread_type": "RegularGroup",
  "thread_path": "inbox/chatTitle_4hyfdfnnhw"
}

Upvotes: 0

Views: 302

Answers (2)

Most Noble Rabbit
Most Noble Rabbit

Reputation: 2776

You are close.

Just need to reference the JSON message object instead of the array, then rewrite the file.

You can do:

String first = "chatMessage.json";
String jsonSource = new String((Files.readAllBytes(Paths.get(first))),"UTF-8");
//print the json file
System.out.println(jsonSource);

JSONObject obj = new JSONObject(jsonSource);
JSONArray arr = new JSONArray(obj.getJSONArray("messages"));

//iterate trough all the timestamp_ms and get the value
for(int i=0; i< arr.length(); i++) {
    JSONObject currMessage = arr.getJSONObject(i);
    long time = (long) currMessage.get("timestamp_ms");
    SimpleDateFormat sdf = new SimpleDateFormat();
    sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
    System.out.println(sdf.format(new Date(time)));
    currMessage.put("timestamp_ms", sdf.format(new Date(time)));
}

Files.write(Paths.get(first), obj.toString(2).getBytes());

String output = new String((Files.readAllBytes(Paths.get(first))),"UTF-8");
System.out.println(output);

Output:

{
    "is_still_participant": true,
    "thread_type": "RegularGroup",
    "messages": [{
        "is_unsent": false,
        "sender_name": "User1",
        "timestamp_ms": "10.5.2021, 16:17",
        "type": "Generic",
        "content": "Hello ç á à â ã "
    }, {
        "is_unsent": false,
        "sender_name": "User2",
        "timestamp_ms": "10.5.2021, 16:16",
        "type": "Generic",
        "content": "Hi, how are you?"
    }, {
        "is_unsent": false,
        "sender_name": "User1",
        "timestamp_ms": "10.5.2021, 16:09",
        "type": "Generic",
        "content": "Ã\u0089 to utf?"
    }],
    "title": "chatTitle",
    "thread_path": "inbox/chatTitle_4hyfdfnnhw",
    "participants": [{
        "name": "User1"
    }, {
        "name": "User2"
    }]
}

Upvotes: 1

AnatolyG
AnatolyG

Reputation: 1587

I'd suggest to use token/event/stream-based solution. The following is just an illustration using tiny parser/generator lib https://github.com/anatolygudkov/green-jelly (both Gson and Jackson also provide stream-oriented API):

import org.green.jelly.AppendableWriter;
import org.green.jelly.CharArrayCharSequence;
import org.green.jelly.JsonEventPump;
import org.green.jelly.JsonNumber;
import org.green.jelly.JsonParser;

import java.io.FileReader;
import java.io.FileWriter;
import java.io.Writer;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;

public class TransformMyJson {
    public static void main(String[] args) throws Exception {
        try (FileReader input = new FileReader("/home/user/input.json");
                FileWriter output = new FileWriter("/home/user/output.json")) {

            final JsonParser parser = new JsonParser();
            parser.setListener(new MyTransformer(output));

            final CharArrayCharSequence charSequence = new CharArrayCharSequence(4096);
            final char[] buffer = charSequence.getChars();

            int len;
            while ((len = input.read(buffer,0, buffer.length)) > -1) {
                charSequence.setLength(len);
                parser.parse(charSequence);
            }
            parser.eoj();
        }
    }

    static class MyTransformer extends JsonEventPump {
        private final SimpleDateFormat sdf = new SimpleDateFormat();
        private boolean isTimestamp;

        MyTransformer(final Writer output) {
            super(new AppendableWriter<>(output));
            sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
        }

        @Override
        public boolean onObjectMember(final CharSequence name) {
            isTimestamp = "timestamp_ms".contentEquals(name);
            return super.onObjectMember(name);
        }

        @Override
        public boolean onNumberValue(final JsonNumber number) {
            if (isTimestamp) {
                return super.onStringValue(sdf.format(new Date(number.mantissa())));
            }
            return super.onNumberValue(number);
        }
    }
}

Props of such type of solution:

  • the file/data doesn't require to be loaded entirely into memory, you can process megs/gigs with no problems
  • it works much faster, especially for large files, than any Object Mapping code
  • you naturally have the same JSON structure as the result
  • it's easy to implement any custom type/rule of transformation

Upvotes: 1

Related Questions