Jeeri
Jeeri

Reputation: 504

How to template JSON in java

My Use case is I have a json file but I have to share only few of them to client. Ex: Consider the source json file as shown below.

{
    "name": "XYZ",
    "age": 24,
    "education": {
        "college": "ppppp",
        "study": "b.tech",
        "grade": 6.8
    },
    "friends": ["kkkk",
    "bbbbbbbbbbb",
    "jjjjjj"],
    "dob":"01-08-1990"
}

For client 1 I have to share below output

{
    "personalInfo": {
        "name": "XYZ",
        "age": 24,
        "friendsNames": ["kkkk","bbbbbbbbbbb","jjjjjj"]
    },
    "educationalInfo": {
        "college": "ppppp",
        "study": "b.tech",
        "grade": 6.8
    }
}

For client 2 I have to share below output

{
    "personalInformation": {
        "nameOfEmployee": "XYZ",
        "ageOfEmployee": 24
    },
    "educationalInformation": {
        "college": "ppppp",
        "study": "b.tech"
    }
}

And for other clients also the use case is same, I have to skip some keys and give different names to the keys. How to dynamically do this by some kind of configuration. I used jsonPath to achieve this but removing few keys from json object is difficult. Any suggestions can be appreciated.

Upvotes: 3

Views: 18728

Answers (6)

charlie
charlie

Reputation: 1527

Use a JSON Path library, like JayWay.

Then the 2 templates to transform your source JSON would be:

  • client 1:

    {
        "personalInfo": {
            "name": "$.name",
            "age": "$.age",
            "friendsNames": "$.friends"
        },
        "educationalInfo": "$.education"
    }
    
  • client 2:

    {
        "personalInformation": {
            "nameOfEmployee": "$.name",
            "ageOfEmployee": "$.age"
        },
        "educationalInformation": {
            "college": "$.education.college",
            "study": "$.education.study"
        }
    }
    

What you need to implement is the recursive template traversal via the JayWay's MapFunction:

{
    ReadContext source = JsonPath.parse(...);
    MapFunction mapper = mapFunction(source);

    WriteContext template1 = JsonPath.parse(...);
    WriteContext template2 = JsonPath.parse(...);

    String client1 = template1.map("*", mapper).jsonString();
    String client2 = template2.map("*", mapper).jsonString();
}

MapFunction mapFunction(ReadContext source) {
    return (templateNode, __) -> switch (templateNode) {
        case Map map -> recurse(map, mapFunction(source));
        case List list -> recurse(list, mapFunction(source));
        case String path -> source.read(path);
    };
}

<T, R> R recurse(T templateNode, MapFunction mapper) {
    return JsonPath.parse(templateNode).map("*", mapper).read("$");
}

Optionally, if you also need to transform each element of a list of variable length, using the same sub-template for each element, extend the case List list branch of the mapFunction() to support a template syntax like:

{
    "targetProperty": [ "$.source.path.to.an.array", {
        ... element template ...
    } ]
}

E.g. a template like:

{
    "friends": [ "$.friends[?(@ =~ /.{5,}/)]", {
        "name": "@",
        "since": "$.dob"
    } ]
}

would result into:

{
    "friends": [ {
        "name": "bbbbbbbbbbb",
        "since": "01-08-1990"
    }, {
        "name": "jjjjjj",
        "since": "01-08-1990"
    } ]
}

Upvotes: 4

fijiaaron
fijiaaron

Reputation: 5185

Java doesn't have great templating built in.

But if you want to do a quick an dirty JSON template where you can replace a few values -- especially without all that ugly quote escaping:

{"key":"value"}

You can use single quotes and string replace:

{'key':'VALUE'}.replace("'", """).replace("VALUE", 42)

A few caveats:

This will break if any existing keys or values have single quotes (like O'malley).

It won't replace strings with numbers, boolean, or null

It can't -- by itself -- insert nested arrays or objects (e.g. [] {}) other than as strings.

But with a little bit of of extra work, you can accomplish the 80/20 rule. After that point you'd probably want to look into parsing or generating -- but by then you're not looking for a quick template.

Upvotes: 0

LeoTaylor
LeoTaylor

Reputation: 11

Your job is to output multilevel JSON data as multiple JSON formats. JSONPath can do this but the process is a hassle.

A simple alternative is to use SPL. SPL is a Java open-source package. You just need three lines of code to get the job done:

enter image description here

SPL offers JDBC driver to be invoked by Java. Just store the above SPL script as jsonparse.splx and invoke it in a Java application as you call a stored procedure:

…
Class.forName("com.esproc.jdbc.InternalDriver");
con= DriverManager.getConnection("jdbc:esproc:local://");
st = con.prepareCall("call jsonparse()");
st.execute();
…

Upvotes: 0

Steklorez
Steklorez

Reputation: 109

I push full worked example in java into GIT with libs (lombok and jackson) Template json mapped to object and object to json with different clients.

Upvotes: 0

Emre Savcı
Emre Savcı

Reputation: 3080

You can use Jackson to serialize and deserialize json. I suggest you to create seperate classes which represents your client data.

I show you an example of how you can deserialize your data and map it to your client json.

You can generate corresponding classes for client 2 with getting some help from http://www.jsonschema2pojo.org/ for mapping json to pojo.

Here is the code :

public class Main {
    public static void main(String[] args) throws ParseException, ParserConfigurationException, IOException, SAXException {

        ObjectMapper mapper = new ObjectMapper();

        Root root = mapper.readValue(new File("test.json"), Root.class);

        Client1 c1 = new Client1();
        PersonalInfo personalInfo1 = new PersonalInfo();
        personalInfo1.setAge(root.getAge());
        personalInfo1.setFriendsNames(root.getFriends());
        personalInfo1.setName(root.getName());

        EducationalInfo educationalInfo1 = new EducationalInfo();
        educationalInfo1.setCollege(root.getEducation().getCollege());
        educationalInfo1.setGrade(root.getEducation().getGrade());
        educationalInfo1.setStudy(root.getEducation().getStudy());

        c1.setPersonalInfo(personalInfo1);
        c1.setEducationalInfo(educationalInfo1);

        mapper.writeValue(new File("client1.json"), c1);
    }
}

Inside test.json file :

{
  "name": "XYZ",
  "age": 24,
  "education": {
    "college": "ppppp",
    "study": "b.tech",
    "grade": 6.8
  },
  "friends": [
    "kkkk",
    "bbbbbbbbbbb",
    "jjjjjj"
  ],
  "dob": "01-08-1990"
}

Inside client1.json file :

{
  "personalInfo": {
    "name": "XYZ",
    "age": 24,
    "friendsNames": [
      "kkkk",
      "bbbbbbbbbbb",
      "jjjjjj"
    ]
  },
  "educationalInfo": {
    "college": "ppppp",
    "study": "b.tech",
    "grade": 6.8
  }
}

Here is the classes which represents your json data:

class Education {
    private String college;
    private String study;
    private float grade;

    public String getCollege() {
        return college;
    }

    public void setCollege(String college) {
        this.college = college;
    }

    public String getStudy() {
        return study;
    }

    public void setStudy(String study) {
        this.study = study;
    }

    public float getGrade() {
        return grade;
    }

    public void setGrade(float grade) {
        this.grade = grade;
    }
}

// root of your base json data
class Root {

    private String name;
    private int age;
    private Education education;
    private List<String> friends;
    private String dob;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public Education getEducation() {
        return education;
    }

    public void setEducation(Education education) {
        this.education = education;
    }

    public List<String> getFriends() {
        return friends;
    }

    public void setFriends(List<String> friends) {
        this.friends = friends;
    }

    public String getDob() {
        return dob;
    }

    public void setDob(String dob) {
        this.dob = dob;
    }
}

class EducationalInfo {

    private String college;
    private String study;
    private float grade;

    public String getCollege() {
        return college;
    }

    public void setCollege(String college) {
        this.college = college;
    }

    public String getStudy() {
        return study;
    }

    public void setStudy(String study) {
        this.study = study;
    }

    public float getGrade() {
        return grade;
    }

    public void setGrade(float grade) {
        this.grade = grade;
    }
}

// class which represents client 1 json data
class Client1 {

    private PersonalInfo personalInfo;
    private EducationalInfo educationalInfo;

    public PersonalInfo getPersonalInfo() {
        return personalInfo;
    }

    public void setPersonalInfo(PersonalInfo personalInfo) {
        this.personalInfo = personalInfo;
    }

    public EducationalInfo getEducationalInfo() {
        return educationalInfo;
    }

    public void setEducationalInfo(EducationalInfo educationalInfo) {
        this.educationalInfo = educationalInfo;
    }
}

class PersonalInfo {

    private String name;
    private int age;
    private List<String> friendsNames = null;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public List<String> getFriendsNames() {
        return friendsNames;
    }

    public void setFriendsNames(List<String> friendsNames) {
        this.friendsNames = friendsNames;
    }
}

Upvotes: 3

Soma S&#246;r&#246;s
Soma S&#246;r&#246;s

Reputation: 64

What about converting it to XML then create some XSLT? it might be much readable and cleaner.

Upvotes: 0

Related Questions