2

While saving json object containing multiple jsons, the json object is being saved as a single array instead of multiple rows.

sample json:

[
    {
     "id"   : 1, -- this is not a primary key and not unique but cannot be null
     "name" : "John Doe",
     "phone" : [
       { "type" : "home", "ref" : "111-111-1234"},
       { "type" : "work", "ref" : "222-222-2222"}
     ]
   },
   {
    "id"   : 2, -- this is not a primary key and not unique but cannot be null
    "name" : "Jane Doe",
    "phone" : [
      { "type" : "home", "ref" : "111-111-1234"},
      { "type" : "work", "ref" : "222-222-2222"}
    ]
  }
]

This is what i need after saving in the database

id   name         phone    
1    John Doe     { "type" : "home", "ref" : "111-111-1234"}
1    John Doe     { "type" : "work", "ref" : "222-222-2222"}
2    Jane Doe     { "type" : "home", "ref" : "111-111-1234"}
2    Jane Doe     { "type" : "work", "ref" : "222-222-2222"}

This is what I am getting

id   name         phone    
1    John Doe     [{ "type" : "home", "ref" : "111-111-1234"},{ "type" : "work", "ref" : "222-222-2222"}]
2    Jane Doe    [{ "type" : "home", "ref" : "111-111-1234"},{ "type" : "work", "ref" : "222-222-2222"}]

here is how i am parsing the json object to pojo and saving to db

@Entity
@Table(name="person")
public class person{
    private Integer id;
    private String name;
    private String phone;
    @Transient 
    JsonNode phoneJson;

    private static OhjectMapper mapper = new ObjectMapper();

    getter/setter

    @Transient
    public JsonNode getPhoneJson(){
        return phoneJson;
    }

    public void setPhoneJson(JsonNode phoneJson){
        this.phoneJson = phoneJson;
    }

    @JsonIgnore
    @Column(name="phone")
    public String getPhone() throws Exception{
        return mapper.writeValueAsString(phoneJson);
    }

    public void setPhone(String phone) throws Exception{
        this.phone = mapper.readTree(phone);
    }
}

dao- save

personRepository.save(person)

any help would be appreciated.

UPDATE

Multiple jSON Column

[
    {
     "id"   : 1, -- this primary key and not unique but cannot be null
     "name" : { --this element can be empty/null
        "first" : "John",
        "last" : "Doe" 
      },
     "phone" : [
       { "type" : "home", "ref" : 1111111234},
       { "type" : "work", "ref" : 2222222222}
     ]
   },
   {
    "id"   : 2, -- this primary key and not unique but cannot be null
    "name" : {
        "first" : "Jane",
        "last" : "Doe" 
      },
    "phone" : [
      { "type" : "home", "ref" : 1111111234},
      { "type" : "work", "ref" : 2222222222}
    ]
  }
]

how do i get result as below

id   name                   phone    
1    [{John},{Doe}]     { "type" : "home", "ref" : "111-111-1234"}
1    [{John},{Doe}]     { "type" : "work", "ref" : "222-222-2222"}
2    [{Jane},{Doe}]     { "type" : "home", "ref" : "111-111-1234"}
2    [{Jane},{Doe}]     { "type" : "work", "ref" : "222-222-2222"}

1 Answer 1

2

You need to duplicate Person objects n times where n is size of phone array. To make it clear, I propose, to create two separate models which we can use separately for parsing JSON and saving in DB. Below you can find simple example which:

  1. Parses JSON to List<JsonPerson>
  2. Converts List<JsonPerson> to List<Person>
  3. Prints List<Person> (you can save it to DB)

Example:

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.type.CollectionType;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

public class JsonApp {

    public static void main(String[] args) throws Exception {
        File jsonFile = new File("./resource/test.json").getAbsoluteFile();

        ObjectMapper mapper = new ObjectMapper();
        CollectionType personsType = mapper.getTypeFactory().constructCollectionType(List.class, JsonPerson.class);

        // parse
        List<JsonPerson> jsonPersons = mapper.readValue(jsonFile, personsType);

        // convert
        List<Person> persons = jsonPersons.stream()
                .map(p -> p.mapTo(mapper))
                .flatMap(List::stream)
                .collect(Collectors.toList());

        persons.forEach(System.out::println);

        // save persons to DB
        // ...
    }
}

class JsonPerson {

    private Integer id;
    private String name;
    private ArrayNode phone;

    public List<Person> mapTo(ObjectMapper mapper) {
        List<Person> persons = new ArrayList<>();
        phone.elements().forEachRemaining(phone -> {
            persons.add(map(mapper, phone));
        });

        return persons;
    }

    private Person map(ObjectMapper mapper, JsonNode p) {
        Person person = new Person();
        person.setId(id);
        person.setName(name);
        try {
            person.setPhone(mapper.writeValueAsString(p));
        } catch (JsonProcessingException e) {
            throw new IllegalStateException(e);
        }

        return person;
    }

    // getters, setters, toString
}

class Person {

    private Integer id;
    private String name;
    private String phone;

    // getters, setters, toString
}

Above code prints:

Person{id=1, name='John Doe', phone='{"type":"home","ref":"111-111-1234"}'}
Person{id=1, name='John Doe', phone='{"type":"work","ref":"222-222-2222"}'}
Person{id=2, name='Jane Doe', phone='{"type":"home","ref":"111-111-1234"}'}
Person{id=2, name='Jane Doe', phone='{"type":"work","ref":"222-222-2222"}'}

Above code separates parsing JSON from other parts. Also, do not create ObjectMapper in each POJO. POJO should not know anything about ObjectMapper and Jackson.

Update

Because name is JSON Object you can create new POJO - Name with first and last properties or treat it similarly to phone and deserialise to JsonNode:

class JsonPerson {

    private Integer id;
    private JsonNode name;
    private ArrayNode phone;

    public List<Person> mapTo(ObjectMapper mapper) {
        List<Person> persons = new ArrayList<>();
        phone.elements().forEachRemaining(phone -> {
            persons.add(map(mapper, phone));
        });

        return persons;
    }

    private Person map(ObjectMapper mapper, JsonNode p) {
        Person person = new Person();
        person.setId(id);
        person.setName(getNameAsString());
        try {
            person.setPhone(mapper.writeValueAsString(p));
        } catch (JsonProcessingException e) {
            throw new IllegalStateException(e);
        }

        return person;
    }

    private String getNameAsString() {
        if (name == null) {
            return null;
        }
        StringBuilder builder = new StringBuilder();
        if (name.isObject()) {
            ObjectNode nameObject = (ObjectNode) name;
            builder.append("[");
            builder.append("{").append(nameObject.get("first")).append("}");
            builder.append(",");
            builder.append("{").append(nameObject.get("last")).append("}");
            builder.append("]");
        }
        return builder.toString();
    }

    // getters, setters, toString
}

After change above code should print:

Person{id=1, name='[{"John"},{"Doe"}]', phone='{"type":"home","ref":1111111234}'}
Person{id=1, name='[{"John"},{"Doe"}]', phone='{"type":"work","ref":2222222222}'}
Person{id=2, name='[{"Jane"},{"Doe"}]', phone='{"type":"home","ref":1111111234}'}
Person{id=2, name='[{"Jane"},{"Doe"}]', phone='{"type":"work","ref":2222222222}'}

getNameAsString method is simplified, you need to handle all corner cases and create String representation better for null, empty and semi-empty nodes.

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you Michal, I have updated my question as I am having multiple json columns but only phone column needs to be saved in different rows. Also, while reading the value {List<JsonPerson> jsonPersons = mapper.readValue(jsonFile, personsType);} How do i capture the incoming json request values? I used mapper.readtree in the modal class to convert it before saving to the database.
@404or505, in case other properties are complex objects you can always deserialise them to POJO classes or *Node class. Take a look on my answer after update.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.