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

HHH-18106 - @CheckHQL is reporting error when named query contains valid Java constant #8374

Conversation

cigaly
Copy link
Contributor

@cigaly cigaly commented May 14, 2024

See Jira issue HHH-18106

When named query in entity method annotated with @CheckHQL contains valid Java constant, processor should not report error

@cigaly cigaly force-pushed the HHH-18106-Find_by_constant_parameter_no_CheckHQL branch from 577f1c9 to bdd6e10 Compare May 14, 2024 16:09
@hibernate-github-bot
Copy link

hibernate-github-bot bot commented May 14, 2024

Thanks for your pull request!

This pull request appears to follow the contribution rules.

› This message was automatically generated.

@cigaly cigaly force-pushed the HHH-18106-Find_by_constant_parameter_no_CheckHQL branch 2 times, most recently from bdd6e10 to 0080bcf Compare May 14, 2024 16:13
@cigaly cigaly marked this pull request as ready for review May 14, 2024 17:29
import static org.junit.jupiter.api.Assertions.assertNotNull;

@TestForIssue(jiraKey = "HHH-No-Such-Key")
public class ConstantInNamedQueryTest {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently we're testing the query validation just as an integrated part of the code generation, with tests in /tooling/metamodel-generator/src/test/java. This isn't perfect by a long shot, but it's good enough until we sit down and come up with something much better. And, yes, It's true that it doesn't exercise @CheckHQL, but that annotation is essentially trivial.

I'm not at all a fan of the approach you're proposing here. This test is verbose and is going to be difficult to understand and maintain. I would prefer if you just follow the existing (admittedly imperfect) approach.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I absolutely agree that this test is more than ugly. I will be more than happy if I will be able to test it in the same way as the other tests. But the problem is that existing CompilationTest's are being executed with inherited class path. This results in all used classes to be present in class loader in BasicDotIdentifierConsumer.resolvePath. This way problem will never be visible in tests, but it will be still present in standalone example. That is the only reason why I've created such an ugly test case.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure what you mean.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry if my explanation is (little bit) messy :-(

The point is that, when processor if running standalone, class loader does know anything about classes that is processing. When BasicDotIdentifierConsumer.resolvePath is trying to resolve class using ClassLoaderService, ClassNotFoundException is thrown, caught and ignored, then next statement is throwing SemanticExpression with message "Could not interpret expression ...". Which is correct outcome when non existing class is referenced.

If testing is done with existing approach (test class that extends CompilationTest) ClassLoaderService already knows all classes under src/test/java, BasicDotIdentifierConsumer.resolvePath can find referenced class, and everything works like there is no problem present.

Below is simple test class that will pass. Normally, first two assertions should pass, but third and fourth not.

public class ConstantInNamedQueryTestv2 extends CompilationTest {

	@Test
	@WithClasses({ CookBook.class })
	public void testCase() {
		assertPresenceOfFieldInMetamodelFor( CookBookWithCheck.class, "QUERY_FIND_BAD_BOOKS" );
		assertPresenceOfFieldInMetamodelFor( CookBookWithCheck.class, "QUERY_FIND_GOOD_BOOKS" );

		assertPresenceOfMethodInMetamodelFor( CookBookWithCheck.class, "findBadBooks", EntityManager.class );
		assertPresenceOfMethodInMetamodelFor( CookBookWithCheck.class, "findGoodBooks", EntityManager.class );
	}
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If testing is done with existing approach (test class that extends CompilationTest) ClassLoaderService already knows all classes under src/test/java

That's weird and surely wrong. We must have something set up wrong.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, then I will check to see if there is some problem with current approach to testing. My assumption was that this is working as expected, so I've created all this "mess" to work differently.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome, thanks!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Every source file under tooling/metamodel-generator/src/main/java will be compiled and .class visible to class loader. Those that must not be visible should be placed elsewhere. Most logical place is tooling/metamodel-generator/src/main/resources.

Possible solutions to isolate some of sources used for testing are either to add new parameter to WithClasses annotation or to create new annotation (like existing WithMappingFiles or WithProcessorOption). I've implemented first option, but this can be easily changed.

The thing that I do not like in this draft solution is that I had to duplicate several methods (and only those needed for testing in this particular case) in org.hibernate.processor.test.util.TestUtil to accept class name instead of class itself.

Of two test methods in test class, one is accepting only one source which is placed in resources directory, and other where entity class is in sources directory, but class containing constants is in resources.

@cigaly cigaly force-pushed the HHH-18106-Find_by_constant_parameter_no_CheckHQL branch from 0080bcf to 2214901 Compare May 17, 2024 07:22
Copy link
Member

@gavinking gavinking left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thanks so much for this!

Comment on lines 653 to 655
return e.getKind() == ElementKind.FIELD &&
e.getModifiers().contains( Modifier.STATIC ) &&
e.getModifiers().contains( Modifier.FINAL );
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return e.getKind() == ElementKind.FIELD &&
e.getModifiers().contains( Modifier.STATIC ) &&
e.getModifiers().contains( Modifier.FINAL );
return e.getKind() == ElementKind.FIELD
&& e.getModifiers().contains( Modifier.STATIC )
&& e.getModifiers().contains( Modifier.FINAL );

@Override
public JavaType<?> getJavaConstantType(String className, String fieldName) {
final Class<?> fieldType = javaConstantType( className, fieldName );
return getTypeConfiguration()

Check warning

Code scanning / CodeQL

Subtle call to inherited method

A [method declared in a superclass](1) is called instead of a [method with the same signature in an enclosing class](2).
@cigaly cigaly force-pushed the HHH-18106-Find_by_constant_parameter_no_CheckHQL branch 2 times, most recently from c78c0e1 to a8effa2 Compare May 20, 2024 12:41
@gavinking
Copy link
Member

Are we done with this one? Shall we merge it?

@gavinking
Copy link
Member

Are we done with this one? Shall we merge it?

@cigaly? Status?

@cigaly
Copy link
Contributor Author

cigaly commented May 22, 2024

Yes, you can merge that.

@gavinking
Copy link
Member

Sorry, @cigaly I now notice there are conflicts, can you resolve them please and then I will merge?

@cigaly
Copy link
Contributor Author

cigaly commented May 22, 2024

OK

@cigaly cigaly force-pushed the HHH-18106-Find_by_constant_parameter_no_CheckHQL branch from a8effa2 to e575c8f Compare May 22, 2024 16:00
@cigaly
Copy link
Contributor Author

cigaly commented May 22, 2024

@gavinking I've resolved conflict and pushed commit.

@gavinking gavinking merged commit 00aad06 into hibernate:main May 22, 2024
20 of 21 checks passed
@gavinking
Copy link
Member

Excellent, thanks @cigaly!

@cigaly cigaly deleted the HHH-18106-Find_by_constant_parameter_no_CheckHQL branch May 22, 2024 16:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
2 participants