-
Notifications
You must be signed in to change notification settings - Fork 3.6k
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-18693 Hibernate Processor does not handle inner types #9098
HHH-18693 Hibernate Processor does not handle inner types #9098
Conversation
Some existing test classes were changed to make inner classes non-private. Otherwise such class could not be referenced from meta model class. |
Thanks for working on this @cigaly ! |
965c5f0
to
c20fa62
Compare
I think the Processor is still going to have to be able to elegantly handle So I'm not quite sure what "elegantly" means here ... perhaps it just means "skip them". |
c20fa62
to
a8fb6dd
Compare
Other than disallowing private classes (either inner or top-level) , excluding them from metamodel generation is only solution that will not cause Java compilation errors. And, of course, there is always possibility that private static class could be referenced by either top level class containing private class or other inner class contained by same top level class. Now only one test class has to be changed to avoid compilation errors is
will result in
which is definitely something Java is happy with. Perhaps some mechanism can be added to prevent such duplications, but until then this class should be slightly changed to let tests to run. |
Hurm.... so that's actually a hole in the algorithm defined by the spec, isn't it? We should fix that, in both Processor, and in the spec. For example, we could say that |
This is more like one of those "tricky" questions for entertainment pages of some Java magazine. Something like "how are named getters and setters in a class with int property named abc and String property named Abc". It seems that in current code only problematic are properties with name consisting of single uppercase letter. To fix that (at least, until some other solution) I will change method
(or, maybe, to use underscore as a suffix?) If nothing else, this will allow implement metamodel class generation for inner classes, without touching any core (main or test) code. |
a8fb6dd
to
83e4d1e
Compare
Yeah but you can just use |
Yes, you are right. It seems that I am still sleepy :-) |
83e4d1e
to
3d9520b
Compare
f920687
to
c650224
Compare
@cigaly can you give me permission to push to your branch? |
Or, whatever, don't worry, I can open a new PR myself, I guess. |
Of course ... only I hope that I did not done something completely different :-) |
Heh, I actually typed these comments on the wrong PR. I was meaning to post on the MySQL PR. |
c650224
to
99774e7
Compare
...odel-generator/src/main/java/org/hibernate/processor/validation/ProcessorSessionFactory.java
Fixed
Show fixed
Hide fixed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, @cigaly, looks pretty reasonable, but see my comments.
if ( !included( element ) | ||
|| hasAnnotation( element, Constants.EXCLUDE ) | ||
|| hasPackageAnnotation( element, Constants.EXCLUDE ) ) { | ||
// skip it completely | ||
} | ||
else if ( isEntityOrEmbeddable( element ) && !element.getModifiers().contains( Modifier.PRIVATE )) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we could just say that the processor completely skips private
inner types. WDYT of this @cigaly:
if ( !included( element ) | |
|| hasAnnotation( element, Constants.EXCLUDE ) | |
|| hasPackageAnnotation( element, Constants.EXCLUDE ) ) { | |
// skip it completely | |
} | |
else if ( isEntityOrEmbeddable( element ) && !element.getModifiers().contains( Modifier.PRIVATE )) { | |
if ( !included( element ) | |
|| hasAnnotation( element, Constants.EXCLUDE ) | |
|| hasPackageAnnotation( element, Constants.EXCLUDE ) | |
|| element.getModifiers().contains( Modifier.PRIVATE ) ) { | |
// skip it completely | |
} | |
else if ( isEntityOrEmbeddable( element ) ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree. And for maybe will be good idea to keep access modifier for non private classes?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And for maybe will be good idea to keep access modifier for non private classes?
You mean generate the metamodel with the same visibility? Yeah, that makes sense I suppose...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One more thing ... in PR #9220 id class is generated as inner class of parent meta model class. Here meta model class for each inner class is generated as separate class. I guess that now is good time to decide if this should stay that way or will be better idea to generate them as inner classes as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I would prefer it to be an inner class.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree, I will try to refactor this to make things that way some time next week.
@@ -714,7 +728,7 @@ private void writeIndex() { | |||
.createResource( | |||
StandardLocation.SOURCE_OUTPUT, | |||
ENTITY_INDEX, | |||
entityName, | |||
URLEncoder.encode(entityName, UTF_8), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this necessary?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Take look at the Person
in org.hibernate.orm.test.hql.QuotedIdentifierTest
. There entity name is The Person
(guess that this is not forbidden by the specification) and processing (and/or compilation) is crashing with message:
java.lang.IllegalArgumentException: Invalid relative name: The Person
If you like, I can write similar test for Hibernate Processor. Of course, if such entity name is allowed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, I see. But then I think we need to make the same change in ProcessorSessionFactory.findEntityByUnqualifiedName()
?
if such entity name is allowed.
Well that is a great question. It looks like the JPA spec is silent on the format of entity names, except to say that they are case-sensitive, and unique in a PU.
I think, however, that we can infer that they are not supposed to have spaces in them, because then we would not be able to parse the query language.
I think I should open an issue against the spec.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, ProcessorSessionFactory.findEntityByUnqualifiedName()
will work fine, since entity name is key for entityNameMappings
. And such entity can be, despite its really 'ugly' name, used in HQL queries if properly quoted. QuotedIdentifierTest
is testing exactly that. I've just tried to name class 'The Person?', and it is working fine.
But, I guess that spec should be changes anyway. Although, I guess that some hardcore Star Trek fans will be disappointed if not able to name entites using Klingon alphabet :-) [It is working now, BTW]
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've removed that change and excluded all "troublemakers". Unfortunately, I can not find wither where this entity index is specified or used, Problem with such "ugly" entity names can not be solved in Hibernate, because finally it is used in com.sun.tools.javac.file.JavacFileManager#getFileForOutput
. That name must be encoded to pass as constructor parameter for java.net.URI
, but must not be encoded to allow file to be created with proper entity name. Something that Joseph Keller called "Catch 22" :-)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we need to worry about indexing such pathological entity names. They can't be used in queries anyway (since the query can't be parsed).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For the record.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can be used if quoted. But I agree that that such names should not be used. Maybe only to put some disclaimer about that for those who like to sue company for mot specifically saying that cat can not be put in microwave oven to dry? :-)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems that Hibernate will happily accept non-ASCII letters in entity (and/or class) names (PostgreSQL even in column names), so only it should be not big "sacrifice" to not allow special characters
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can be used if quoted.
Ahhh uuhmmm, yeah, OK sure. I forgot HQL has quoted identifiers (JPQL doesn't).
tooling/metamodel-generator/src/main/java/org/hibernate/processor/util/StringUtil.java
Outdated
Show resolved
Hide resolved
...odel-generator/src/main/java/org/hibernate/processor/validation/ProcessorSessionFactory.java
Show resolved
Hide resolved
255abee
to
68552a8
Compare
Code changes to generate metadata for inner class inside other metadata class instead of new metadata class file for each managed class. Note: This code will surely need some (beauty and other) changes. |
b9a0bcf
to
3a5dd6b
Compare
11a8adc
to
b481c7f
Compare
78e1fce
to
121c85e
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, I've tried this out and it looks like it's working great!
@cigaly could you do me the favor of squashing it down to two or three commits so that I can merge it?
Thanks!!!
...etamodel-generator/src/main/java/org/hibernate/processor/annotation/NonManagedMetamodel.java
Show resolved
Hide resolved
Test case for Jakarta Data processing with inner classes Changed existing test class to properly check generated metamodel class @Exclude-ing "troublemakers" with illegal URI character(s) in entity name
Generated metadata for inner class A.B is A_.B_ Path source for inner class is identical to path source for enclosing class
… non-private classes Generaed metadate class for inner class A.B is A_.B_
121c85e
to
5a6ab87
Compare
Thanks so much @cigaly, this is great! |
See Jira Issue HHH-18693
This is still work in progress, not to be merged with main branch, at least not immediately.
For each (static) inner non-private class one meta-model class will be generated.
Naming is as follows. If we have:
Generated class will be named
A_B_
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license
and can be relicensed under the terms of the LGPL v2.1 license in the future at the maintainers' discretion.
For more information on licensing, please check here.