5

I have an Object 2D array (Object [][]) that is returned from querying a database. I now want to map it to Objects which can be returned in API call after grouping.

Here is my 2D Object array.

Object [][] dbResult = 
{
  {1, "a", 9, "Content1", "format1", false, true},
  {1, "a", 9, "Content1", "format2", true, false},
  {2, "b", 8, "Content2", "format3", true, false},
  {2, "b", 8, "Content2", "format4", false, false},
  {3, "c", 7, "Content3", "format5", true, true},
  {4, "d", 8, "Content2", "format6", false, true},
  {4, "d", 6, "Content3", "format7", true, true},
  {4, "d", 5, "Content4", "format8", false, false},
  {5, "e", 4, "Content5", "format9", false, true},
  {6, "f", 3, "Content6", "format10", true, false}
};

Here is the legend/key for the index.
[ID, Name, AnotherID, AnotherName, Format, Boolean, Boolean]

I want to return

List<IdName> idsNames;

Where each of the classes should be mapped like this.

class IdName {
    String id;
    String name;
    List<Another> anotherNameList;
}

class Another {
    String anotherId;
    String anotherName;
    List<Format> formatList;
}

class Format {
    String format;
    Boolean isEnabled;
    Boolean isManaged;
}

I tried using Java 8's groupingBy but I couldn't get to the state that I want.

Sample expected result:

[
      {
      "id": 1,
      "name": "a",
      "another": [
        {
          "anotherId": 9,
          "anotherName": "Content1",
          "format": [
            {
              "format": "format1",
              "isEnabled": true,
              "isManaged": false
            },
            {
              "format": "format2",
              "isEnabled": true,
              "isManaged": false
            }
          ]
        }
      ]
    }
]
4
  • Your String [][] dbResult is not java valid array Commented Jan 16, 2019 at 22:12
  • @LhoBen I have accepted your edit and added more info. Commented Jan 16, 2019 at 22:16
  • You have values in dbResult which are not String. Incompatible types.. Commented Jan 16, 2019 at 22:19
  • OK. I changed it to Object. My main question is on how to convert. I have changed the company-owned code/entities to an example for stackoverflow. Commented Jan 16, 2019 at 22:24

2 Answers 2

1

Looks like you should use Collectors.collectingAndThen.

First create the extractors (Assuming your classes have constructors & getters):

// The cast types are just an example. You can Cast/convert the array values to any type you want

IdName extractIdName(Object[] row) {
    return new IdName((String) row[0], (String) row[1], null);
}

Another extractAnother(Object[] row) {
    return new Another((String) row[2], (String) row[3], null);
}

Format extractFormat(Object[] row) {
    return new Format((String) row[4], (boolean) row[5], (boolean) row[6]);
}

Then you will need the merge functions:

List<Another> setFormats(Map<Another, List<Format>> map) {
    return map.entrySet()
              .stream()
              .map(e -> {
                  e.getKey().setFormatList(e.getValue());
                  return e.getKey();
              })
              .collect(toList());
}

List<IdName> setAnothers(Map<IdName, List<Another>> map) {
    return map.entrySet()
              .stream()
              .map(entry -> {
                  entry.getKey().setAnotherNameList(entry.getValue());
                  return entry.getKey();
              })
              .collect(toList());
}

Finally this will do the trick:

// Converting Object[][] to List<IdName>
List<IdName> list = 
      Arrays.stream(dbResult)
            .collect(
                collectingAndThen(
                    groupingBy(this::extractIdName,
                        collectingAndThen(
                            groupingBy(this::extractAnother,
                                mapping(this::extractFormat, toList())),
                            this::setFormats
                        )),                                                             
                    this::setAnothers));
Sign up to request clarification or add additional context in comments.

1 Comment

this is exactly what I wanted. Thank you @ETO
0

It can be done in several steps. Let all values be String for simplicity. Also you are supposed to have constructors and equals/hashcode methods implemented.

Map<IdName, Map<Another, List<String[]>>> map = Arrays.stream(dbResult)
    .collect(
        groupingBy(s -> new IdName(s[0], s[1], null),
            groupingBy(s -> new Another(s[2], s[3], null))));

Then we can create Format objects and put everything together.

for (Map.Entry<IdName, Map<Another, List<String[]>>> entry : map.entrySet()) {
    IdName idName = entry.getKey();        // main object
    Set<Another> anothers = entry.getValue().keySet();
    for (Another another : anothers) {        // create list<Format> for each Another
        List<Format> formatList = entry.getValue().get(another).stream()
            .map(format -> new Format(format[4], format[5], format[6]))
            .collect(Collectors.toList());

        another.setFormatList(formatList);
    }

    idName.setAnotherNameList(anothers);
}

Now we can get all assembled objects

Set<IdName> idNames = map.keySet();

1 Comment

thanks for the answer. I couldn't compile the code that creates the map

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.