0

Let's say my app has to create a JSON text file in this form

{
 "key1"
:
"value1"
,
"key2"
:
"value2"
,
"arrayKey"
:
[
{
"keyA"
:
"valueA"
,
"keyB"
:
"valueB"
,
"keyC"
:
[
0
,
1
,
2
]
}
]
}

from

JSONObject.toString()

that is one long line of text in my Android Java app

{"key1":"value1","key2":"value2","arrayKey":[{"keyA":"valueA","keyB":"valueB","keyC":[0,1,2]}]}

It has been proved that a regex approach does not work.

There are many pitfalls.

So I decided to create my own parser to get the work done

Edit: Attention! There is a mistake in the following code, causing escaped quotes being treated as normal ones, see my very answer to this question (also with further improvement)

public static String JSONTextToCRSeparatedJSONText(String JSONText)
{
    String result="";
    String symbolList="{}[]:,";
    char ch;
    char previousChar=0;

    int charNum=JSONText.length();
    boolean inRegion=false;
    boolean insertedBefore=false;
    char startRegionChar=0;
    for (int i=0;i<charNum;i++)
    {

    ch=JSONText.charAt(i);
    previousChar=ch; // mistake here, should be after the conditional statements, please see my answer with new code version


    if (!inRegion) 
    {
        if (((ch=='\"')||(ch=='\''))&&(previousChar!='\\'))
        {
            inRegion=true;
            startRegionChar=ch;
        }
    } else
    {
        if ((ch==startRegionChar)&&(previousChar!='\\'))
        {
            inRegion=false;

        }
    }

    if ((!inRegion)&& (symbolList.indexOf(ch)>-1)&&(!insertedBefore))
    {
        result=result+"\n";
    } 
    result=result+ch;
    insertedBefore=false; 
    if ((!inRegion)&& (symbolList.indexOf(ch)>-1))
    {
        result=result+"\n";
        insertedBefore=true; //it will be useful next iteration

    }
}
    return result;
}

It seems to be working.

Just I would like to know

if the symbols it checks to insert the \n control character against are all symbols possible in a JSON text

and if there are some pitfalls that I am not able to see.

P5music
  • 3,197
  • 2
  • 32
  • 81
  • If your code works as intended, it belongs elsewhere (probably https://codereview.stackexchange.com). SO proper is all (and only) about fixing broken code – The Head Rush Oct 23 '19 at 14:39
  • @The Head Rush It works on my test JSON, I would like to know about JSON pitfalls in regard to my algorithm. – P5music Oct 23 '19 at 14:42
  • Is there a reason not to use some open-source library for parsing JSON? Searching "lightweight json parser java" on the internet comes up with many links leading to projects that you can use after reading the "quick start" documentation for ten minutes or so. – Sergey Kalinichenko Oct 23 '19 at 14:44
  • @dasblinkenlight When possible I avoid using libraries I will have to take into account bugs and versions forever, especially when my need is very limited. – P5music Oct 23 '19 at 14:47
  • It seems that the 1st line is always a newline with your code. – LHCHIN Oct 24 '19 at 02:07
  • Important: there is a mistake causing escaped quotes to be considered as normal quotes, please see my answer and edits. – P5music Oct 24 '19 at 10:43

2 Answers2

0

I think that you are doing way too much work by yourself. Today there are 2 major known libraries that are used to work with JSON. One is Jackson-JSON (otherwise known as "Fast XML" - go figure...) and the other is GSON - a Google library based on Jackson-JSON but also supports passing binary objects. I personally prefer Jackson-JSON, but that's the matter of personal preference. For GSON library look here. For Jackson look here. For Maven artifacts for Jackson look here. If you choose to work with Jackson, then the main class that you need is ObjectMapper. Start from looking into methods readValue() and writeValue(). Look for endless examples on the web on how to work with it. This should give you a good start.

Anyway, both of those libraries allow you to produce well-formatted JSON. For Gson:

  String content = new String(Files.readAllBytes(resource.toPath()));

    Gson gson = new GsonBuilder().setPrettyPrinting().create();
    JsonParser jp = new JsonParser();
    JsonElement je = jp.parse(content);
    String prettyJsonString = gson.toJson(je);
    System.out.println(prettyJsonString);

    return prettyJsonString;

For Jackson-JSON:

  ObjectMapper mapper = new ObjectMapper();
    mapper.enable(SerializationFeature.INDENT_OUTPUT);
    String prettyJsonString = mapper.writeValueAsString(content);

    return prettyJsonString;

By far less work then you have done and by far better tested. Also, if you want to present the same formatting in Html then see the answer to this question: Pretty print for JSON in JAVA works fine for the console, but in browser it does not work

Michael Gantman
  • 7,315
  • 2
  • 19
  • 36
  • Looking at the question OP does not want a well-formatted JSON, but rather a specific one-line-per-token format. Are you sure these libraries can handle that? – RobCo Oct 23 '19 at 14:53
  • @Michael Gantman The fact is that I want the formatting to be exactly as displayed in my question. I think the output of the formatting functions you refer to is not the same, and I think I would not get the complete freedom to create a custom formatting. – P5music Oct 23 '19 at 14:54
  • @P5music - you are correct, Well-formatted JSON looks different from your desired format. I suppose that if you really need format exactly as you posted, then I guess you will have to do it the way you already did. Symbols '\n' are valid in JSON, so if your code works it could be an acceptable solution. – Michael Gantman Oct 23 '19 at 14:59
  • @Michael Gantman My question is also about pitfalls of JSON in regard to my algorithm. Do you see any? Are []{},: all symbols I have to take into account? – P5music Oct 23 '19 at 15:02
  • Also symbols " and ' but you treat them in your code, just didn't mention in your comment. So, no at first glance I don't see any problems. Here is a good site that gives you a SPEC for JSON standard: https://www.json.org/ – Michael Gantman Oct 23 '19 at 15:06
  • @Michael Gantman Important: there is a mistake causing escaped quotes to be considered as normal quotes, please see my answer and edits – P5music Oct 24 '19 at 10:51
0

The code in the question is wrong because

previousChar=ch;

is going to be the current char, not the previous one, so it has to be put after the conditional statements.

The right code is the following (also, it is simplified and not producing unwanted lines):

public static String JSONTextToLineSeparatedJSONText(String JSONText)
{
    String result="";
    String symbolList="{}[]:,";
    char ch;
    char previousChar=0;

    int charNum=JSONText.length();
    boolean inRegion=false;
    boolean insertedBefore=false;
    char startRegionChar=0;
    for (int i=0;i<charNum;i++)
    {

    ch=JSONText.charAt(i);



    if (!inRegion) 
    {
        if (((ch=='\"')||(ch=='\''))&&(previousChar!='\\'))
        {
            inRegion=true;
            startRegionChar=ch;
        }
    } else
    {
        if ((ch==startRegionChar)&&(previousChar!='\\'))
        {
            inRegion=false;

        }
    }
    previousChar=ch; 

    if ((!inRegion)&& (symbolList.indexOf(ch)>-1)&&(!insertedBefore))
    {
       if (i>0) result=result+"\n";
    } 
    result=result+ch;
    insertedBefore=false; 
    if ((!inRegion)&& (symbolList.indexOf(ch)>-1))
    {
        result=result+"\n";
        insertedBefore=true; //it will be useful next iteration

    }
}
    return result;
}
P5music
  • 3,197
  • 2
  • 32
  • 81