2

I have the following 2 objects Team and Group. I have standard getters setters and toString methods in each of these classes and not allowed to modify them.

public class Team { 
  private List<Team> teams;
  private List<TeamMember> members;
  private String teamId;    
}

public class Group {    
  private List<GroupMember> groupMember;
  private List<Group> groups;
  private String groupId;
}

Team can have a List<Team> type of a list as an attribute where List<Group> can have a List<Group> as an attribute.

example list of Teams look like follows: enter image description here

I want to create the list of Groups which reflects the same structure of TeamList.

This is what I have got so far.

@Service
public class GroupService {

@Autowired
TeamService teamService;

public List<Group> createGroupList(){

    List<Group> groups = Collections.emptyList();

    List<Team> teams = teamService.createTeamList();

    if (teams != null && !teams.isEmpty()) {

        groups = teams.stream().map(t -> {

            Group group = new Group();
            group.setGroupId(t.getTeamId());

            //this is to be modified
            group.setGroups(getSubgroups(teams, group.getGroupId()));

            return group;

        }).collect(Collectors.toList());

    }

    return groups;
}



private List<Group> getSubgroups(List<Team> teams, String parentGroupName) {

    Optional<Team> parentTeam = teams.stream()
            .filter(t -> t.getTeamId().equalsIgnoreCase(parentGroupName)).findFirst();

    if(parentTeam.isPresent()){

        List<Team> subTeams = new ArrayList<>();
        List<Group> lstOfGroups = new ArrayList<>();

        System.out.println("parentname " + parentTeam.get().getTeamId());


        if(parentTeam.get().getTeams() != null){
            parentTeam.get().getTeams().stream().forEach(r -> {
                subTeams.add(r);
            });
        }

        subTeams.stream().forEach(st -> {
            Group gr = new Group();
            gr.setGroupId(st.getTeamId());
            lstOfGroups.add(gr);    
        });

        return lstOfGroups;

    }
    return null;            

 }

}

My idea is to modify the getSubgroups method to set the subgroups correctly for each given path.(eg: getSubgroubs can return team2 with all it's subgroups set until team7) I know I have to use recursion but I am struggling to find the solution. How can I achieve this?

EDIT

I have updated my code and now I can access the first level of children and not the other levels yet

2
  • So one Team and one Group are essentially the same? Why don't you just introduce a common interface both implement, and clients won't care what class they're working on? And how are TeamMembers transformed into GroupMembers, I can't see that in your code. Commented Oct 14, 2018 at 7:07
  • This is an example I have created based on a real scenario which I have Teams in one system and Groups in another and only solution I have is copying over to sync them. Commented Oct 14, 2018 at 7:11

2 Answers 2

3

You can just create a single method to copy one into the other and call it recursively:

public Group toGroup(Team team) {
    Group result = new Group(team.teamId());
    // this is missing in your sample code
    result.setGroupMembers(transform(team.getTeamMembers());
    List<Group> subGroups = team.getTeams().stream()
        .map(this::toGroup) // recursive call to this method
        .collect(toList());
    result.setSubgroups(subGroups);
    return result;
}

so you can do

List<Group> groups = teamService.getTeams()
                         // you should return an empty list if no elements are present
                         .stream()  
                         .map(this::toGroup) // initial call
                         .collect(toList());

You might also want to look into mapstruct which can automatically generate simple mappers.

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

2 Comments

Would Groups maintain the structure of it similar to Teams this way?
@BlueStar Looks like you tried it out ;) but yeah, that would recreate the Teams in the Group structure as you described..
2

To give you an idea how this would look in mapstruct:

@Mapper(componentModel="spring")
interface TeamGroupMapper {
    @Mappings({
        @Mapping(source="teamId", target="groupId"),
        @Mapping(source="teams", target="groups"),
        @Mapping(source="teamMembers", target="groupMembers")
    })
    Group toGroup(Team team);

    List<Group> toGroups(List<Team> teams);
    GroupMember toGroupMember(TeamMember teamMember);
}

The actual code will be generated. If the classes have properties with the same name (eg if the ids were called id for both Team and Group?), a @Mapping annotation is not needed for it.

Then, you can @Autowire this as a component and use it.

@Component
class YourGroupService implements GroupService {
    @Autowired TeamGroupMapper mapper;
    @Autowired TeamService teamService;

    public List<Group> getGroups() {
        return mapper.toGroups(teamService.getTeams());
    }
}

I'm sure this code won't actually work, but it should give you an idea of what mapstruct does. I really like it to avoid boilerplate mapping code.

Comments

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.