简体   繁体   中英

How to copy data from one list of objects to another in java?

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: 在此处输入图片说明

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

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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM