javahashmapstringbuffer

Create a Java StringBuffer from a Map and Java Object


I am trying to create a csv file with the headers coming from a map and the values coming from an object. I have a Java object which stores different attribute data.

public class MyObject {
    private String name;
    private String email;
    private Integer id;
    private String phone;

   getters and setters...
}

I have a Map where the user has key value pair, where the key is the attribute name of MyObject and the value is column headers for a csv file. Ex:

Map<String, String> columnMap = new HashMap<>();
columnMap.put("id", "Id");
columnMap.put("name", "User Name");
columnMap.put("email", "User Email");
columnMap.put("phone", "User Phone");

My goal is to create a csv file from the data for which I first want to retrieve the values from the map to set as headers and then create rows based on what is stored in MyObject class. Ex:

public class CopyMapToSBForFile {

    public static void main(String[] args) {

        List<MyObject> myObjects = new ArrayList<>();
        MyObject myObject1 = new MyObject();
        myObject1.setId(1);
        myObject1.setName("Name 1");
        myObject1.setEmail("Email 1");
        myObject1.setPhone("111-121-2121");

        MyObject myObject2 = new MyObject();
        myObject2.setId(2);
        myObject2.setName("Name 2");
        myObject2.setEmail("Email 2");
        myObject2.setPhone("111-121-2121");

        MyObject myObject3 = new MyObject();
        myObject3.setId(3);
        myObject3.setName("Name 3");
        myObject3.setEmail("Email 3");
        myObject3.setPhone("111-121-2121");

        myObjects.add(myObject1);
        myObjects.add(myObject2);
        myObjects.add(myObject3);

        Map<String, String> columnMap = new HashMap<>();
        columnMap.put("id", "Id");
        columnMap.put("name", "User Name");
        columnMap.put("email", "User Email");
        columnMap.put("phone", "User Phone");

        Field[] fields = MyObject.class.getDeclaredFields();

        StringBuffer sb = new StringBuffer();
        for (Field field : fields) {
            System.out.println(field.getName());
            if (columnMap.containsKey(field.getName())) {
                sb.append(columnMap.get(field.getName()));
                sb.append(",");
            }
        }
        
    }

}

From the above example you can see using reflection utils I am able to create the header object but I am stuck on how to append the values from MyObject to the StringBuffer object to create something like the below output:

User Name,User Email,Id,User Phone
Name 1,Email 1,1,111-121-2121
Name 2,Email 2,2,111-121-2121
Name 3,Email 3,3,111-121-2121

I have a code which will conver the StringBuffer to CSV but I am stuck on how to create the above output once I create the header. Also, I want to make sure the program handles the row correctly incase the order of the columns are changed where the Id is first column instead of third column.


Solution

  • You don't need reflection to create the header. If, as per your comment, the map contains only fields which are available in your object, just grab the values from the map to create the header. Use a LinkedHashMap instead of HashMap, Since the first one guarantees the order while the second one does not. For the content, I would recomend to create a String array per row / object instead of using StringBuffer or StringBuilder and leave the rest to opencsv to take care of separators, quotes .. and so on.

    See the following example as a starting point. You could improve it by not doing everything in the main method as I did but extracting more methods for creating header, writing to file etc. and implementing a decent error handling.

    import java.io.FileWriter;
    import java.io.IOException;
    import java.lang.reflect.Field;
    import java.util.ArrayList;
    import java.util.LinkedHashMap;
    import java.util.List;
    import java.util.Map;
    
    import com.opencsv.CSVWriter;
    
    public class Example {
    
    
        public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException {
    
            List<MyObject> myObjects = createSampleList();
    
            Map<String, String> columnMap = new LinkedHashMap<>();
            columnMap.put("name", "User Name");
            columnMap.put("id", "Id");
            columnMap.put("email", "User Email");
            columnMap.put("phone", "User Phone");
    
    
            List<String[]> csvData = new ArrayList<>();
            String[] header = columnMap.values().toArray(String[]::new);
    
            csvData.add(header);
    
            for (MyObject myObject : myObjects) {
                List<String> row = new ArrayList<>();
                for (String key : columnMap.keySet()) {
                    Field field = MyObject.class.getDeclaredField(key);
                    field.setAccessible(true);
                    String value = String.valueOf(field.get(myObject));
                    row.add(value);
                }
                csvData.add(row.toArray(String[]::new));
            }
    
            // default separator is a comma, default all fields are enclosed in double quotes, you can change this by providing a boolean flag writer.writeAll(csvData, false);
            try (CSVWriter writer = new CSVWriter(new FileWriter("/path/to/your/csv/test.csv"))) {
                writer.writeAll(csvData);
            }
        }
    
        private static List<MyObject> createSampleList() {
            List<MyObject> myObjects = new ArrayList<>();
            MyObject myObject1 = new MyObject();
            myObject1.setId(1);
            myObject1.setName("Name 1");
            myObject1.setEmail("Email 1");
            myObject1.setPhone("111-121-2121");
    
            MyObject myObject2 = new MyObject();
            myObject2.setId(2);
            myObject2.setName("Name 2");
            myObject2.setEmail("Email 2");
            myObject2.setPhone("111-121-2121");
    
            MyObject myObject3 = new MyObject();
            myObject3.setId(3);
            myObject3.setName("Name 3");
            myObject3.setEmail("Email 3");
            myObject3.setPhone("111-121-2121");
    
            myObjects.add(myObject1);
            myObjects.add(myObject2);
            myObjects.add(myObject3);
    
            return myObjects;
        }
    
        public static class MyObject {
            private String name;
            private String email;
            private Integer id;
            private String phone;
    
            //getters and setters
        }
    }