diff --git a/src/main/java/org/owasp/dependencytrack/persistence/QueryManager.java b/src/main/java/org/owasp/dependencytrack/persistence/QueryManager.java index 0374442032..2848160448 100644 --- a/src/main/java/org/owasp/dependencytrack/persistence/QueryManager.java +++ b/src/main/java/org/owasp/dependencytrack/persistence/QueryManager.java @@ -891,6 +891,31 @@ public PaginatedResult getCwes() { * @return a Dependency object */ public Dependency createDependencyIfNotExist(Project project, Component component, String addedBy, String notes) { + List dependencies = getDependencies(project, component); + + // Holder for possible duplicate dependencies + List duplicates = new ArrayList<>(); + + // Holder for an existing Dependency (if present) + Dependency existingDependency = null; + + if (dependencies.size() > 0) { + // Ensure that only one dependency object exists + if (dependencies.size() > 1) { + // Iterate through the duplicates and add them to the list of dependencies to be deleted + for (int i = 1; i < dependencies.size(); i++) { + duplicates.add(dependencies.get(i)); + } + } + // Return the first dependency found - all others will be deleted + existingDependency = dependencies.get(0); + } + delete(duplicates); + + if (existingDependency != null) { + return existingDependency; + } + Dependency dependency = getDependency(project, component); if (dependency != null) { return dependency; @@ -1067,10 +1092,26 @@ public long getDependencyCount(Component component) { */ @SuppressWarnings("unchecked") public Dependency getDependency(Project project, Component component) { + final List result = getDependencies(project, component); + return result.size() == 0 ? null : result.get(0); + } + + /** + * Returns a List of Dependencies for the specified Project and Component. + * + * There should NEVER be duplicate dependencies. But this method is intended + * to check for them and return the list. This is a private method and should + * never be accessed outside the QueryManager. + * + * @param project the Project the component is part of + * @param component the Component + * @return a List of Dependency objects, or null if not found + */ + @SuppressWarnings("unchecked") + private List getDependencies(Project project, Component component) { final Query query = pm.newQuery(Dependency.class, "project == :project && component == :component"); query.getFetchPlan().addGroup(Dependency.FetchGroup.ALL.name()); - final List result = (List) query.execute(project, component); - return result.size() == 0 ? null : result.get(0); + return (List) query.execute(project, component); } /**