简体   繁体   中英

Convert JSON to a single line String and vice versa

I want to convert a JSON into a string field to save into database and again convert it back to JSON.

Ex. below is structure of JSON:

{
"students":[{
"name": "Albert",
"code":"GE",
"marks":[{"mark":"20"},{"mark":"40"}]},
{
"name": "Gert",
"code":"LE",
"marks":[{"mark":"26"}]},
{
"name": "John"
},
{
"name": "John Doe",
"code":"LP",
"marks":[{"mark":"40"}]}
]
}

I want to convert this into a String field, "storedInput", so that i can save it into database, ideally saving only the JSON data. I also want to convert it back to the JSON when I send it back to the user.

Below is the conversion strategy I used to convert it into delimited String.

"Albert-GE-20&40#Gert-LE-26#John-$-$#Johnah Doe-LP-40"

But I dont think its the best strategy as it gets extremely complicated to convert it back.

public String convertStudentList(List<Student> studentList) {
    return studentList.stream().map(this::mapStudent).collect(Collectors.joining("#"));
}

public String checkData(String data) {
    return Optional.ofNullable(data).isPresent() ? data : "$";
}

public String mapStudent(Student student) {
    List<Marks> marks = student.getMarks();
    if (marks != null) {
        String mark = marks.stream().map(m -> m.getMark()).collect(Collectors.joining("&"));
        return checkData(student.getName()) + "-" + checkData(student.getCode()) + "-" + mark;
    } else {
        return checkData(student.getName()) + "-" + checkData(student.getCode()) + "-" + "$";
    }
}

Edit:

  1. I do not have access to make any changes to the table structure.
  2. I cannot simply store the entire JSON, ex. using Jackson Object Mapper, as there are space constraints, ideally i just want to store the value and convert it back.

Using JDK 15

Text Blocks : Text blocks start with a “”” (three double-quote marks) followed by optional whitespaces and a newline.

Please find the solution below to convert json to string and vice-versa, it might help you in some way.

public class Test {
  public static void main(String[] args) throws JsonProcessingException {
    String s = """
        {
        "students":[{
        "name": "Albert",
        "code":"GE",
        "marks":[{"mark":"20"},{"mark":"40"}]},
        {
        "name": "Gert",
        "code":"LE",
        "marks":[{"mark":"26"}]},
        {
        "name": "John"
        },
        {
        "name": "John Doe",
        "code":"LP",
        "marks":[{"mark":"40"}]}
        ]
        }
        """;
    //JSON TO STRING
    ObjectMapper mapper = new ObjectMapper();
    String s2 = mapper.writeValueAsString(s);
    System.out.println("JSON TO STRING:" + s2);

    //STRING TO JSON
    String s3 = mapper.readValue(s2, new TypeReference<>() {});
    System.out.println("STRING TO JSON:" + s3);

  }
}

Output:

 JSON TO STRING:"{\n\"students\":[{\n\"name\": \"Albert\",\n\"code\":\"GE\",\n\"marks\":[{\"mark\":\"20\"},{\"mark\":\"40\"}]},\n{\n\"name\": \"Gert\",\n\"code\":\"LE\",\n\"marks\":[{\"mark\":\"26\"}]},\n{\n\"name\": \"John\"\n},\n{\n\"name\": \"John Doe\",\n\"code\":\"LP\",\n\"marks\":[{\"mark\":\"40\"}]}\n]\n}\n"
    STRING TO JSON:{
    "students":[{
    "name": "Albert",
    "code":"GE",
    "marks":[{"mark":"20"},{"mark":"40"}]},
    {
    "name": "Gert",
    "code":"LE",
    "marks":[{"mark":"26"}]},
    {
    "name": "John"
    },
    {
    "name": "John Doe",
    "code":"LP",
    "marks":[{"mark":"40"}]}
    ]
    }

I suggest you store the students in a table with a column for each attribute from the JSON. I am not familiar with Spring, but other web frameworks I used are able to fetch a row from the database and seralize it to JSON in the way you want. They can also take JSON and put it into the database as individual columns rather than an single string.

Library Josson has the capability.

https://github.com/octomix/josson

Encode

Josson josson = Josson.fromJsonString(
    "{" +
    "\"students\":[{" +
    "\"name\": \"Albert\"," +
    "\"code\":\"GE\"," +
    "\"marks\":[{\"mark\":\"20\"},{\"mark\":\"40\"}]}," +
    "{" +
    "\"name\": \"Gert\"," +
    "\"code\":\"LE\"," +
    "\"marks\":[{\"mark\":\"26\"}]}," +
    "{" +
    "\"name\": \"John\"" +
    "}," +
    "{" +
    "\"name\": \"John Doe\"," +
    "\"code\":\"LP\"," +
    "\"marks\":[{\"mark\":\"40\"}]}" +
    "]" +
    "}");
JsonNode encoded = josson.getNode(
    "students@.concatFree(name,'-',code,'-',marks.mark.join('&')).@join('#')");
System.out.println(encoded.toPrettyString());

Output

"Albert-GE-20&40#Gert-LE-26#John--#John Doe-LP-40"

Decode

Josson josson = Josson.fromJsonString(
    "\"Albert-GE-20&40#Gert-LE-26#John--#Johnah Doe-LP-40\"");
JsonNode decoded = josson.getNode(
    "split('#').split('-').map(name:[0],code:[1],marks:[2].split('&').map(mark:?)).toObject('students')");
System.out.println(decoded.toPrettyString());

Output

{
  "students" : [ {
    "name" : "Albert",
    "code" : "GE",
    "marks" : [ {
      "mark" : "20"
    }, {
      "mark" : "40"
    } ]
  }, {
    "name" : "Gert",
    "code" : "LE",
    "marks" : [ {
      "mark" : "26"
    } ]
  }, {
    "name" : "John"
  }, {
    "name" : "Johnah Doe",
    "code" : "LP",
    "marks" : [ {
      "mark" : "40"
    } ]
  } ]
}

Using JDK 17:

I have implemented the below code using some of the latest java features apart from Java 8.

Records in java 14: As of JDK 14, we can replace our data classes with records. Records are immutable classes that require only the type and name of fields. We do not need to create constructor, getters, setters, override toString() methods, override hashcode and equals methods.

Text Blocks in java 15: Text blocks start with a “”” (three double-quote marks) followed by optional whitespaces and a newline.

The below code will give you the pattern that you want to store in the database in the form of a string. I hope this will solve your query.

public class JsonTest {
          public static void main(String[] args) throws JsonProcessingException {
            
            //Converting json to formatted String
            record Marks(String mark){}
            record Student(String name, String code, List<Marks> marks){}
            record Response(List<Student> students){}
        
            String input = """
                     {
                               "students":[{
                               "name": "Albert",
                               "code":"GE",
                               "marks":[{"mark":"20"},{"mark":"40"}]},
                               {
                               "name": "Gert",
                               "code":"LE",
                               "marks":[{"mark":"26"}]},
                               {
                               "name": "John"
                               },
                               {
                               "name": "John Doe",
                               "code":"LP",
                               "marks":[{"mark":"40"}]}
                               ]
                               }
                """;
        
            ObjectMapper mapper = new ObjectMapper();
            Response studentData = mapper.readValue(input, new TypeReference<>() {});
        
            StringBuilder sb = new StringBuilder();
            
            studentData.students().forEach(x -> {
              sb.append(x.name() + "-");
              sb.append(x.code()!= null ? x.code() : "$");
              sb.append("-");
              sb.append(x.marks()!= null ? x.marks().stream().filter(y -> y.mark()!=null).map(Marks::mark).collect(Collectors.joining("&")) : "$");
              sb.append("#");
            });
            
            System.out.println(sb);
          }
    
    //Converting formatted String to original json
    List<Student> students = new ArrayList<>();
        Arrays.asList(sb.toString().split("#")).forEach(student -> {
    
          String[] splitArr1 = student.split("-");
          String[] splitArr2 = splitArr1[2].split("&");
    
          String name = splitArr1[0];
          String code = splitArr1[1].contains("$")?null:splitArr1[1];
          List<Marks> marks = Arrays.stream(splitArr2).filter(y -> !y.contains("$")).map(Marks::new).toList();
    
          Student s = new Student(name,code,marks);
          students.add(s);
        });
        Response out = new Response(students);
    
        String backToJson = mapper.writeValueAsString(out);
    
        System.out.println(backToJson);
    }
        }

Output:

//Converting json to formatted String
 Albert-GE-20&40#Gert-LE-26#John-$-$#John Doe-LP-40#
//Converting formatted String to original json
{"students":[{"name":"Albert","code":"GE","marks":[{"mark":"20"},{"mark":"40"}]},{"name":"Gert","code":"LE","marks":[{"mark":"26"}]},{"name":"John","code":null,"marks":[]},{"name":"John Doe","code":"LP","marks":[{"mark":"40"}]}]}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM