Java 8 Threads: Creating Layered / Compound Objects

I am starting to use the java 8 stream API. I would like to convert the list of "sql result set" to domain objects, i.e. Compound structure.

Domain objects: the user has a set of permissions, each permission has a collection of year applications. For example, John has 2 permissions (MODERATOR and DEV). his moderator permission is only applicable for 2014 and 2015; his developer permission is only applicable to 2014.

class User { // some primitives attributes List<Permission> permission; } class Permission { // some primitives attributes List<Integer> years; } 

Now I make a query and get a list of flat results, for example:

 [1, "moderator", 2014] [1, "moderator", 2015] [1, "dev", 2014] [2, "dev", 2010] [2, "dev", 2011] [2, "dev", 2012] 

1 and 2 are userId.

I tried a different construction, but in the end it is more complicated than fluent. And it didn’t work :)
I read in a Java 8 book that it is “simple” to create dompain objects with collectors.
I cried a little when I read: "(

I tried

 sb.collect( collectingAndThen( groupingBy( Mybean::getUserId, collectingAndThen( groupingBy(Monbean::getPermissionId, mapping(convertPermission, toList())), finisherFonction) ), convertUser) ); 

and got one hell of a generic compilation failure.

  • What is the best way to create layered composite domain objects using java 8 threads?
  • Is this AndThen / finisher collection a good idea?
  • or are you only using groupingBy followed by the display function?
  • You convert the classifier to an object (how is the first level display function?)

Because in the end I want to get rid of the Map and get the result of the List<User> (I think I can add a map call to the entrySet to finish the conversion).

+5
source share
2 answers

Let me offer you several options, and you decide which views you most understand. I assume that the constructor of the user is User(int userId, List<Permission> permissions) , and the constructor of Permission is Permission(String permissionId, List<Integer> years)

Option 1: direct approach. Group by user ID, create a list of permissions for each userid, and create User objects. Personally, I think that this many breeding in collectors is difficult to succumb to.

 List<User> users = beans.stream() .collect( groupingBy( MyBean::getUserid, collectingAndThen( groupingBy( MyBean::getPermission, mapping(MyBean::getYear, toList()) ), t -> t.entrySet().stream() .map(e -> new Permission(e.getKey(), e.getValue())) .collect(toList()) ) ) ).entrySet().stream() .map(e -> new User(e.getKey(), e.getValue())) .collect(toList()); 

Option 2: Same as above, but make the permission collector separately for clarity.

 Collector<MyBean, ?, List<Permission>> collectPermissions = collectingAndThen( groupingBy(MyBean::getPermission, mapping(MyBean::getYear, toList())), t -> t.entrySet().stream() .map(e -> new Permission(e.getKey(), e.getValue())) .collect(toList()) ); List<User> users = beans.stream() .collect(groupingBy(MyBean::getUserid, collectPermissions)) .entrySet().stream() .map(e -> new User(e.getKey(), e.getValue())) .collect(toList()); 

Option 3: first move the beans to the userid map to map the allowed list to the list of years ( Map<Integer, Map<String, List<Integer>> ). Then build the domain objects off the map

 List<User> users = beans.stream().collect( groupingBy( MyBean::getUserid, groupingBy( MyBean::getPermission, mapping(MyBean::getYear, toList()) ) ) ).entrySet().stream() .map(u -> new User( u.getKey(), u.getValue().entrySet().stream() .map(p -> new Permission(p.getKey(), p.getValue())) .collect(toList()) ) ).collect(toList()); 
+4
source

The collectingAndThen combinator is designed to make the intermediate accumulation form different from the desired final form. This is the case for the joining() collector (where the intermediate form is StringBuilder but the final form is String ), and can also be used to wrap volatile collections with immutable wrappers after the collection is complete. Therefore, I do not think this is the tool you are looking for.

If you are looking for “user permissions” this will do the trick:

 Map<UserId, List<Permission>> queryResults.stream() .collect(qr -> qr.getId(), mapping(qr -> qr.getPermission() + ":" + qr.getDate(), toList())); 

This will lead to:

 1 -> [ moderator:2014, moderator:2015, dev:2014 ] 2 -> [ dev:2010, dev:2011, dev:2012 ] 

The idea is this: - You are grouped by "id" (the first field of your request) - For each entry, you select a function from the remaining fields (here I use the string concat for clarity, but you can create an object with permission and year) and send him into a downstream collector - Use Collectors.toList () as the downstream collector, which will then be the "value" of the Map created by groupingBy .

+2
source

Source: https://habr.com/ru/post/1209007/


All Articles