0

Simplifying the problem to only focus on the portion relevant to the question.

  • My program has two classes - Contact, PhoneNumber.
  • Contact has the usual fields - name, company, etc. and Phone Number too has fields such as phoneNumber, type, etc. Both have the usual get/set methods.
  • Contact class has a addPhoneNumber method to add a phone number to the phoneNumber ArrayList so it is missing the corresponding set method.
  • A Contact includes an ArrayList of Phone Numbers and my program contains a ArrayList of Contacts.
  • I am using Jackson parser with Snakeyaml.
package testYaml;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.List;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;

public class testYaml {
    public static void main(String[] args) {
        // Define our array
        List<Contact> contacts = new ArrayList<Contact>();
        Contact contact;
        PhoneNumber phoneNumber;
        // Contact 1
        contact = new Contact();
        contact.setName("John Johny");
        contact.setCompany("ABC Corp");
        contact.setPriority(1);
        phoneNumber = new PhoneNumber();
        phoneNumber.setNumber("+111111");
        phoneNumber.setType("home");
        contact.addNumber(phoneNumber);
        phoneNumber.setNumber("+222222");
        phoneNumber.setType("work");
        contact.addNumber(phoneNumber);
        contacts.add(contact);
        // Contact 2
        contact = new Contact();
        contact.setName("Janes Bond");
        contact.setCompany("Dept X");
        contact.setPriority(3);
        phoneNumber = new PhoneNumber();
        phoneNumber.setNumber("+007007");
        phoneNumber.setType("secret");
        contact.addNumber(phoneNumber);
        contacts.add(contact);
        // Contact 3
        contact = new Contact();
        contact.setName("The Gentelman");
        contact.setCompany("XYZ Corp");
        contact.setPriority(1);
        phoneNumber = new PhoneNumber();
        phoneNumber.setNumber("+111222");
        phoneNumber.setType("mobile");
        contact.addNumber(phoneNumber);
        phoneNumber = new PhoneNumber();
        phoneNumber.setNumber("+222111");
        phoneNumber.setType("work");
        contact.addNumber(phoneNumber);
        contacts.add(contact);
        // Write yaml file
        ObjectMapper yamlMapper = new ObjectMapper(new YAMLFactory());
        try {
            yamlMapper.writeValue(new FileOutputStream("C:/Temp/contacts.yaml"), contacts);
        } catch (Exception e) {
            e.printStackTrace();
        }
        // Read yamlFIle and populate contacts
        List<Contact> contacts1 = new ArrayList<Contact>();
        List<Contact> contacts2 = new ArrayList<Contact>();
        ObjectMapper yamlMapper1 = new ObjectMapper(new YAMLFactory());
        try {
            contacts1 = yamlMapper1.readValue(new FileInputStream("C:/Temp/contacts.yaml"),
                    (Class<List<Contact>>) contacts1.getClass());
            contacts2 = yamlMapper1.readValue(new FileInputStream("C:/Temp/contacts.yaml"), contacts2.getClass());
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("Done");
    }
}

class Contact {
    String name;
    String company;
    int priority;
    ArrayList<PhoneNumber> numbers = new ArrayList<PhoneNumber>();
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getCompany() {
        return company;
    }
    public void setCompany(String company) {
        this.company = company;
    }
    public int getPriority() {
        return priority;
    }
    public void setPriority(int priority) {
        this.priority = priority;
    }
    public ArrayList<PhoneNumber> getNumbers() {
        return numbers;
    }
    public void addNumber(PhoneNumber number) {
        numbers.add(number);
    }
}

class PhoneNumber {
    String number;
    String type;
    public String getNumber() {
        return number;
    }
    public void setNumber(String number) {
        this.number = number;
    }
    public String getType() {
        return type;
    }
    public void setType(String type) {
        this.type = type;
    }
}

contacts1 and contacts2 are both an array of LinkedHashMap instead of array of Contact type.

Update - Working Code This is what finally worked (enclosing ArrayList in a new class Contacts. Don't know if it is the most optimal solution though.

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.ArrayList;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;

public class testYaml {
    public static void main(String[] args) {
        // Define our array
        Contacts contacts = new Contacts();
        Contact contact;
        PhoneNumber phoneNumber;
        // Contact 1
        contact = new Contact();
        contact.setName("John Johny");
        contact.setCompany("ABC Corp");
        contact.setPriority(1);
        phoneNumber = new PhoneNumber();
        phoneNumber.setNumber("+111111");
        phoneNumber.setType("home");
        contact.addNumber(phoneNumber);
        phoneNumber.setNumber("+222222");
        phoneNumber.setType("work");
        contact.addNumber(phoneNumber);
        contacts.addContact(contact);
        // Contact 2
        contact = new Contact();
        contact.setName("Janes Bond");
        contact.setCompany("Dept X");
        contact.setPriority(3);
        phoneNumber = new PhoneNumber();
        phoneNumber.setNumber("+007007");
        phoneNumber.setType("secret");
        contact.addNumber(phoneNumber);
        contacts.addContact(contact);
        // Contact 3
        contact = new Contact();
        contact.setName("The Gentelman");
        contact.setCompany("XYZ Corp");
        contact.setPriority(1);
        phoneNumber = new PhoneNumber();
        phoneNumber.setNumber("+111222");
        phoneNumber.setType("mobile");
        contact.addNumber(phoneNumber);
        phoneNumber = new PhoneNumber();
        phoneNumber.setNumber("+222111");
        phoneNumber.setType("work");
        contact.addNumber(phoneNumber);
        contacts.addContact(contact);
        // Write yaml file
        ObjectMapper yamlMapper = new ObjectMapper(new YAMLFactory());
        try {
            yamlMapper.writeValue(new FileOutputStream("C:/Temp/contacts.yaml"),contacts);
        } catch (Exception e) {
            e.printStackTrace();
        }
        // Read yamlFIle and populate contacts
        Contacts contacts1 = new Contacts();
        ObjectMapper yamlMapper1 = new ObjectMapper(new YAMLFactory());
        try {
            contacts1 = yamlMapper1.readValue(new FileInputStream("C:/Temp/contacts.yaml"),Contacts.class);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

class Contacts {
    private ArrayList<Contact> contacts = new ArrayList<Contact>();
    public void addContact (Contact contact) {
        contacts.add(contact);
    }
    public ArrayList<Contact> getContacts() {
        return contacts;
    }
}

class Contact {
    private String name;
    private String company;
    private int priority;
    private ArrayList<PhoneNumber> numbers = new ArrayList<PhoneNumber>();
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getCompany() {
        return company;
    }
    public void setCompany(String company) {
        this.company = company;
    }
    public int getPriority() {
        return priority;
    }
    public void setPriority(int priority) {
        this.priority = priority;
    }
    public ArrayList<PhoneNumber> getNumbers() {
        return numbers;
    }
    public void addNumber(PhoneNumber number) {
        numbers.add(number);
    }
}

class PhoneNumber {
    private String number;
    private String type;
    public String getNumber() {
        return number;
    }
    public void setNumber(String number) {
        this.number = number;
    }
    public String getType() {
        return type;
    }
    public void setType(String type) {
        this.type = type;
    }
}
tusht
  • 11
  • 3
  • You have more than two classes. What about Employee? Please show the file and the Employee class definition – OneCricketeer Apr 26 '21 at 06:42
  • Also, you're using `employees.getClass()`, but never adding anything to the list, so why are you expecting it to have data? – OneCricketeer Apr 26 '21 at 06:44
  • „*Both the methods are not populating the employee ArrayList*“ hardly surprising if you discard their result. Try `employees = yamlMapper.readValue(…)`. – flyx Apr 26 '21 at 10:07
  • Sorry, I wrote incorrectly in the code portion. I have corrected the code above (Employee should be Contact). – tusht Apr 26 '21 at 19:33
  • @flyx I corrected teh code to assign the variable: contacts = yamlMapper.readValue(...); The returned array is a ArrayList of LinkedHashMap with key as the name of the element (name, company, ...) and value as the type (String, String, ...) – tusht Apr 26 '21 at 20:01
  • Is using Jackson a requirement? SnakeYAML (which is used by Jackson under the hood) is able to handle this correctly and there is little reason for using Jackson's API instead if not for the annotations (which you do not seem to use)? – flyx Apr 26 '21 at 20:26
  • @flyx I have posted the code above (extracted and then independently compiled from the code I am working on). The only reason I used Jackson was it seemed to be a multi standard serializer. – tusht Apr 26 '21 at 20:54
  • I tried using snakeyaml directly: ``` Yaml yaml = new Yaml(); List contacts3 = (ArrayList) yaml.load(new FileInputStream("C:/Temp/contacts.yaml")); ``` Same issue. In the debugger, contacts3 is of the type ArrayList> instead of ArrayList. – tusht Apr 27 '21 at 05:59
  • I have posted the test code that finally worked. It changes the yaml file by adding a high level contacts array that now contains all the individual contacts. Trying to decide between this approach and the approach to code a specific serializer. – tusht Apr 27 '21 at 07:18
  • This one sounds similar to my query, let me try solutions given there. https://stackoverflow.com/questions/6349421/how-to-use-jackson-to-deserialise-an-array-of-objects – tusht Apr 27 '21 at 08:04
  • The suggestions given in worked. I don't need to define the define the enclosing class Contacts anymore: This is how the readValue line looks like: ArrayList contacts1 = yamlMapper1.readValue(new FileInputStream("C:/Temp/contacts.yaml"),new TypeReference>(){}); – tusht Apr 27 '21 at 20:41

0 Answers0