Skip to content

Commit

Permalink
Merge pull request quarkusio#44352 from aloubyansky/unique-resource-list
Browse files Browse the repository at this point in the history
Make sure the result from QCL.getElementsWithResource(name) does not include duplicates
  • Loading branch information
gsmet authored Nov 7, 2024
2 parents f8d0e77 + 70e2f17 commit 5d09f38
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -356,9 +356,7 @@ public QuarkusClassLoader createDeploymentClassLoader() {
if (configuredClassLoading.isRemovedArtifact(dependency.getKey())) {
continue;
}
if (dependency.isRuntimeCp() && dependency.isJar() &&
(dependency.isReloadable() && appModel.getReloadableWorkspaceDependencies().contains(dependency.getKey()) ||
configuredClassLoading.isReloadableArtifact(dependency.getKey()))) {
if (isReloadableRuntimeDependency(dependency)) {
processCpElement(dependency, element -> addCpElement(builder, dependency, element));
}
}
Expand All @@ -368,6 +366,12 @@ public QuarkusClassLoader createDeploymentClassLoader() {
return builder.build();
}

private boolean isReloadableRuntimeDependency(ResolvedDependency dependency) {
return dependency.isRuntimeCp() && dependency.isJar() &&
(dependency.isReloadable() && appModel.getReloadableWorkspaceDependencies().contains(dependency.getKey()) ||
configuredClassLoading.isReloadableArtifact(dependency.getKey()));
}

public String getClassLoaderNameSuffix() {
return quarkusBootstrap.getBaseName() != null ? " for " + quarkusBootstrap.getBaseName() : "";
}
Expand Down Expand Up @@ -405,9 +409,7 @@ public QuarkusClassLoader createRuntimeClassLoader(ClassLoader base, Map<String,
if (configuredClassLoading.isRemovedArtifact(dependency.getKey())) {
continue;
}
if (dependency.isRuntimeCp() && dependency.isJar() &&
(dependency.isReloadable() && appModel.getReloadableWorkspaceDependencies().contains(dependency.getKey()) ||
configuredClassLoading.isReloadableArtifact(dependency.getKey()))) {
if (isReloadableRuntimeDependency(dependency)) {
processCpElement(dependency, element -> addCpElement(builder, dependency, element));
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -625,22 +625,77 @@ public List<ClassPathElement> getElementsWithResource(String name) {
public List<ClassPathElement> getElementsWithResource(String name, boolean localOnly) {
ensureOpen(name);

boolean parentFirst = parentFirst(name, getClassPathResourceIndex());
final boolean parentFirst = parentFirst(name, getClassPathResourceIndex());

List<ClassPathElement> ret = new ArrayList<>();
List<ClassPathElement> result = List.of();

if (parentFirst && !localOnly && parent instanceof QuarkusClassLoader) {
ret.addAll(((QuarkusClassLoader) parent).getElementsWithResource(name));
if (parentFirst && !localOnly && parent instanceof QuarkusClassLoader parentQcl) {
result = parentQcl.getElementsWithResource(name);
}

List<ClassPathElement> classPathElements = getClassPathResourceIndex().getClassPathElements(name);
ret.addAll(classPathElements);
result = joinAndDedupe(result, getClassPathResourceIndex().getClassPathElements(name));

if (!parentFirst && !localOnly && parent instanceof QuarkusClassLoader) {
ret.addAll(((QuarkusClassLoader) parent).getElementsWithResource(name));
if (!parentFirst && !localOnly && parent instanceof QuarkusClassLoader parentQcl) {
result = joinAndDedupe(result, parentQcl.getElementsWithResource(name));
}

return ret;
return result;
}

/**
* Returns a list containing elements from two lists eliminating duplicates. Elements from the first list
* will appear in the result before elements from the second list.
* <p>
* The current implementation assumes that none of the lists contains duplicates on their own but some elements
* may be present in both lists.
*
* @param list1 first list
* @param list2 second list
* @return resulting list
*/
private static <T> List<T> joinAndDedupe(List<T> list1, List<T> list2) {
// it appears, in the vast majority of cases at least one of the lists will be empty
if (list1.isEmpty()) {
return list2;
}
if (list2.isEmpty()) {
return list1;
}
final List<T> result = new ArrayList<>(list1.size() + list2.size());
// it looks like in most cases at this point list1 (representing elements from the parent cl) will contain only one element
if (list1.size() == 1) {
final T firstCpe = list1.get(0);
result.add(firstCpe);
for (var cpe : list2) {
if (cpe != firstCpe) {
result.add(cpe);
}
}
return result;
}
result.addAll(list1);
for (var cpe : list2) {
if (!containsReference(list1, cpe)) {
result.add(cpe);
}
}
return result;
}

/**
* Checks whether a list contains an element that references the other argument.
*
* @param list list of elements
* @param e element to look for
* @return true if the list contains an element referencing {@code e}, otherwise - false
*/
private static <T> boolean containsReference(List<T> list, T e) {
for (int i = list.size() - 1; i >= 0; --i) {
if (e == list.get(i)) {
return true;
}
}
return false;
}

public Set<String> getReloadableClassNames() {
Expand Down Expand Up @@ -902,6 +957,10 @@ public QuarkusClassLoader build() {
return new QuarkusClassLoader(this);
}

@Override
public String toString() {
return "QuarkusClassLoader.Builder:" + name + "@" + Integer.toHexString(hashCode());
}
}

public ClassLoader parent() {
Expand Down

0 comments on commit 5d09f38

Please sign in to comment.