CodingPandaBear
CodingPandaBear

Reputation: 15

Java SpringBoot: CRUD method returns value before called Service finishes

I have several Items that are linked together in ManyToMany relations like this:

In Technologies:

    @ManyToMany(mappedBy = "internalTechnologies")
private List<Project> internalProjects = new ArrayList<>();

In Projects

@ManyToMany(cascade = {CascadeType.MERGE})
@JoinTable(
        name = "project_technology",
        joinColumns = @JoinColumn(name = "project_id", referencedColumnName = "id"),
        inverseJoinColumns = @JoinColumn(name = "technology_id", referencedColumnName = "id")
)
private List<Technology> internalTechnologies = new ArrayList<>();

When editing the technology to add or remove the links between the technology and projects, I use helper classes that use the @Service notion and are @Autowired into the controller.

For removing the links:

    public void removeTechnologyFromProjects(Technology technologyToRemove, List<Project> projects){
    List<Project> projectsToEdit = new ArrayList<>(projects);
    for ( Project project: projectsToEdit) {
        List<Technology> internalTechnologies = project.getInternalTechnologies();
        internalTechnologies.remove(technologyToRemove);
        project.setInternalTechnologies(internalTechnologies);
        projectRepository.save(project);
    }
}

Note: I create a new ArrayList to avoid ConcurrentModificationException.

For adding Links:

public void linkTechnologyToProjects(Technology technologyToAdd, List<Long> ids) throws ResponseStatusException {
    for (Long id : ids) {
        Optional<Project> project = projectRepository.findById(id);
        if (project.isPresent()) {
            Project projectToEdit = project.get();
            List<Technology> technologyList = projectToEdit.getInternalTechnologies();

            technologyList.add(technologyToAdd);
            projectToEdit.setInternalTechnologies(technologyList);
            projectRepository.save(projectToEdit);
        } else {
            throw new ResponseStatusException(HttpStatus.NOT_FOUND,
                    String.format(PROJECT_NOT_FOUND, id));
        }
    }
}

In the Technology controller the following commands are executed:

 @PutMapping("/tech/{id}")
public TechReturnDTO updateTech(@PathVariable("id") long id, @Valid @RequestBody TechCreationDTO requestBody) {
    Technology techToUpdate = techRep.findById(id);
    (other fields edited)
        if (requestBody.getInternalProjects()!=null){
            linkRemover.removeTechnologyFromProjects(techToUpdate, techToUpdate.getInternalProjects());
            itemLinker.linkTechnologyToProjects(techToUpdate, requestBody.getInternalProjects());
        }else{
            linkRemover.removeTechnologyFromProjects(techToUpdate, techToUpdate.getInternalProjects());
        }

        (other lists edited)


        Technology savedTech = techRep.save(techToUpdate);
        return new TechReturnDTO(savedTech);
    }
    throw new ResponseStatusException(HttpStatus.NOT_FOUND,
            String.format("Technology with Id %s not found!", id));
}

For some reason, the method return the TechReturnDTO before the itemLinker does its job:

How do I 'force' the method to wait until the service has finished?

Edit: Additional details as requested:

The technologyRepository simply is an extension of the CrudRepository Class:

public interface TechnologyRepository extends CrudRepository<Technology, Long> { Technology findById(long id); }

It does return a fully Updated Object normally. When editing a Project the changes are immediately shown. Only when editing the tech to update the relation the error occurs.

Upvotes: 0

Views: 170

Answers (1)

CodingPandaBear
CodingPandaBear

Reputation: 15

For who ever reads this: I did solve the issue by not solving it:

Instead of using the "mappedBy" of the bi-directional relationship, I changed the relationship to be two one-directional manyToMany relations.

I then changed the Services to update the corresponding items to contain the link.

Upvotes: 1

Related Questions