Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Class references in lambdas not found #992

Closed
wild8oar opened this issue Oct 26, 2022 · 3 comments · Fixed by #1004
Closed

Class references in lambdas not found #992

wild8oar opened this issue Oct 26, 2022 · 3 comments · Fixed by #1004
Labels
Milestone

Comments

@wild8oar
Copy link

wild8oar commented Oct 26, 2022

Since version 1.0.0, the method JavaClass#getDirectDependenciesFromSelf no longer finds classes referenced in lambdas.

Unit-Test to reproduce the problem:

import static org.assertj.core.api.Assertions.assertThat;

import java.util.Optional;

import org.junit.jupiter.api.Test;

import com.tngtech.archunit.core.domain.Dependency;
import com.tngtech.archunit.core.domain.JavaClass;
import com.tngtech.archunit.core.importer.ClassFileImporter;

class ClassReferencesTest {

	@Test
	void shouldFindAllClassReferences () {
                JavaClass testClass = new ClassFileImporter().importClasses(TestClass.class).get(TestClass.class);

		assertThat(testClass.getDirectDependenciesFromSelf())
			.extracting(Dependency::getTargetClass)
			.extracting(JavaClass::getName)
			.contains(Number.class.getName(), Optional.class.getName(), String.class.getName());
	}

	private static final class TestClass {

		public void doSomething () {
			Class<?> clz = Number.class;  // found
			analyzeClass(Optional.class);  // found
			Runnable runnable = () -> analyzeClass(String.class);  // NOT found
		}

		private void analyzeClass (Class<?> clazz) {
			// nothing
		}
	}
}

While the Number.class and Optional.class are found, the String.class referenced in a lambda is not found:

Expecting ArrayList:
  ["java.lang.Object",
    "java.lang.Object",
    "java.lang.Class",
    "java.lang.Class",
    "java.util.Optional",
    "java.lang.Number"]
to contain:
  ["java.lang.Number", "java.util.Optional", "java.lang.String"]
but could not find the following element(s):
  ["java.lang.String"]

This used to work as expected with version 0.23.1.
It could be related to #847, but I cannot see an obvious reason.

Thanks for looking into this!

@hankem
Copy link
Member

hankem commented Nov 2, 2022

I can confirm that

class LambdaTest {
    Runnable get() {
        return () -> System.out.println("Hello from `LambdaTest.lambda$get$0()`");
    }
}

assertThat(new ClassFileImporter().importClass(LambdaTest.class).getCodeUnits())
        .extracting(JavaCodeUnit::getFullName)
        .hasSize(3);  // LambdaTest.<init>, LambdaTest.get(), LambdaTest.lambda$get$0()

changed to hasSize(2) (without LambdaTest.lambda$get$0()) with a404fb4.

As JavaClass#getCodeUnits() does not include the lambda body anymore, the corresponding dependencies are missing in JavaClass#getDirectDependenciesFromSelf() as well.

@codecholeric
Copy link
Collaborator

Thanks for reporting this, this seems to be actually a bug 🙈 AFAIS referenced class objects (and also instanceof checks for that matter) are bypassing the lambda resolution logic. I'll try to fix that ASAP and release a bugfix version!

@codecholeric codecholeric added this to the 1.0.1 milestone Nov 9, 2022
@wild8oar
Copy link
Author

wild8oar commented Nov 9, 2022

Thanks for your effort, @codecholeric! I'm looking forward to the bugfix release.

codecholeric added a commit that referenced this issue Nov 21, 2022
When we improved importing lambdas in a404fb4 we overlooked that there
can also other dependencies than regular accesses be declared within the
body of a lambda, namely references to class objects and instanceof
checks. Since we completely removed the synthetic methods from the
import but didn't resolve the origin of those dependencies against the
correct (lambda-declaring) method these dependencies were now missing
completely from the import.
We now fix this by applying the same origin resolution mechanism to
those dependencies and associate them with the method that originally
declares the lambda.

Resolves: #992
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants