-
Notifications
You must be signed in to change notification settings - Fork 29.3k
[SPARK-19666][SQL] Skip a property without getter in Java schema inference and allow empty bean in encoder creation #17013
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
Closed
Closed
Changes from 2 commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
9ad4789
Improve error message for invalid JavaBean
HyukjinKwon ae4c9aa
Address comments
HyukjinKwon 91cee26
Allow setter only bean in java schema inference and empty bean in enc…
HyukjinKwon 5808d71
Cleaner and comments
HyukjinKwon ed686fa
Cleaner tests
HyukjinKwon 3604855
Address comments
HyukjinKwon ac5cc7d
Cleaner
HyukjinKwon File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -117,13 +117,18 @@ object JavaTypeInference { | |
| val (valueDataType, nullable) = inferDataType(valueType) | ||
| (MapType(keyDataType, valueDataType, nullable), true) | ||
|
|
||
| case _ => | ||
| case c => | ||
| // TODO: we should only collect properties that have getter and setter. However, some tests | ||
| // pass in scala case class as java bean class which doesn't have getter and setter. | ||
| val beanInfo = Introspector.getBeanInfo(typeToken.getRawType) | ||
| val properties = beanInfo.getPropertyDescriptors.filterNot(_.getName == "class") | ||
| val fields = properties.map { property => | ||
| val returnType = typeToken.method(property.getReadMethod).getReturnType | ||
| val readMethod = Option(property.getReadMethod).getOrElse { | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This
|
||
| throw new UnsupportedOperationException( | ||
| s"Cannot infer type for class ${c.getName} " + | ||
| s"because property ${property.getName} does not have the getter") | ||
| } | ||
| val returnType = typeToken.method(readMethod).getReturnType | ||
| val (dataType, nullable) = inferDataType(returnType) | ||
| new StructField(property.getName, dataType, nullable) | ||
| } | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
We don't need to guard an empty
properties? InJavaTypeInference#serializerForhttps://github.com/apache/spark/blob/master/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/JavaTypeInference.scala#L421, it takes the case into account.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.
Yes, It seems loosely related with the JIRA here. I am fine with changing it if any committer could confirm. Otherwise, I would like to avoid a behaviour change here.
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 like behavior should be the same in this case, in this same file. I think you could also improve that error handling.
Is there anywhere else in the code that checks the getter? is the error message consistent with that?
Uh oh!
There was an error while loading. Please reload this page.
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.
The check he pointed out is related only with
Encoders.bean(...)API as it seems only used indeserializerFor/serializerForvia ExpressionEncoder.scala#L85, which seems always executed after the codes I proposed to fix here.The below codes just do not allow a bean with empty property after the properties without getters are filtered in JavaTypeInference.scala#L137 and it checks if they are empty in JavaTypeInference.scala#L421.
it throws an exception as below:
If we do not use
Encoders.bean(...), then it allows empty schema as below:For the sake of consistency, I guess we might have to consider removing the checks there , JavaTypeInference.scala#L421, and allowing this empty case because this seems possible in Scala API too as below:
It seems there are several places
JavaTypeInference.scala#L137 in the
Encoders.bean(...)code path where these are being filtered out.JavaTypeInference.inferDataTypeis being called ahead. (The same checking seems not being applied inJavaTypeInference.inferDataTypedue to [SPARK-19666][SQL] Skip a property without getter in Java schema inference and allow empty bean in encoder creation #17013 (comment).)SparkSession.scala#L345-L354 uses
SQLContext.beansToRowsbutJavaTypeInference.inferDataTypeis being called ahead ingetSchema.SparkSession.scala#L375-L380 uses
SQLContext.beansToRowsbutJavaTypeInference.inferDataTypeis being called ahead ingetSchema.It seems the error message is consistent with this because the change I proposed here seems executed first before these places.
Java
Scala
prints
Uh oh!
There was an error while loading. Please reload this page.
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.
Honestly, I would like to fix the empty property change and sweep all related tests if there are (I guess this relates to #17013 (comment)) or avoid this change here because it seems loosely related.
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 editted the comments above for more details and preventing ambiguity.)
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.
ideally a property without a getter is not a bean property, let's fix the empty property problem.
Uh oh!
There was an error while loading. Please reload this page.
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 am sorry for the long comment that maybe a bit messed around. So, there are two code paths
JavaTypeInference.serializerFor/deserializerFor: non-empty required & getter/setter requiredJavaTypeInference.inferDataType: empty one OK & getter only OKCould I please ask which case you want just to double check?
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 mean
JavaTypeInference. Why we throw exception for a bean property without getter instead of not treating it as a property?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.
Ah, sure. Then, let me ignore a property without the getter in
JavaTypeInference.inferDataType, and allow empty property inJavaTypeInference.serializerFor/deserializerFor.