[BEAM-4453] Add schema support for Java POJOs and Java Beans#5873
[BEAM-4453] Add schema support for Java POJOs and Java Beans#5873reuvenlax merged 18 commits intoapache:masterfrom
Conversation
* Recursive POJOs and collection/map fields still not support. * getter/setter generation still needs to be moved into helper class. * Still missing optimized Row -> POJO conversion when the Row is a wrapper around a POJO.
…e[] parameter (as that's what Row.getBytes vends), so make sure we wrap it before assiging.
…s. This also allows a fast path for Row -> T conversion for the case of RowWithGetters.
Make setters and getters work for array types. Row.getArray always returns a Java List type, but we support POJOs that contain Java array; what's more, the POJO array might contain either the primitive or the boxed type. Detect these cases, and insert bytecode to do the appropriate conversions. Make setters/getters work for other types as well.
…ns up the code, and makes these utilities reusable for other types of getters (e.g. JavaBean getters).
…d for other class types.
…ictable field order.
apilloud
left a comment
There was a problem hiding this comment.
Found a bug, a few cleanup items, and a bunch of nits. Didn't review the tests too carefully.
| + type | ||
| + " has a @DefaultSchemaProvider annotation " | ||
| + " with a null argument."); | ||
| "Type " + type + " has a @DefaultSchema annotation " + " with a null argument."); |
There was a problem hiding this comment.
Looks like spotless messed up your string. (Unnecessary " + " in the middle.)
|
|
||
| // Iterate over the row, and set (possibly recursively) each field in the underlying object | ||
| // using the setter. | ||
| Schema schema = row.getSchema(); |
There was a problem hiding this comment.
You are also calling row.getSchema() a few lines up. If getSchema is expensive it makes sense to move this before createSetters() and use it there.
| private List<Field> fields; | ||
| // Cache the hashCode, so it doesn't have to be recomputed. Schema objects are immutable, so this | ||
| // is correct. | ||
| private int hashCode; |
There was a problem hiding this comment.
All of these fields are immutable. Add final?
| */ | ||
| static class ConvertValueForGetter extends TypeConversion<StackManipulation> { | ||
| // The code that reads the value. | ||
| private StackManipulation readValue; |
| readValue, | ||
| TypeCasting.to(READABLE_INSTANT_TYPE), | ||
| // Call ReadableInstant.getMillis to extract the millis since the epoch. | ||
| MethodInvocation.invoke( |
There was a problem hiding this comment.
Thanks for the comments calling out what each of these do!
nit: I still think this particular block is still somewhat difficult to follow. It might be slightly easier to read if you pulled the MethodInvocaitons each into it's own Compound like convertArray above? (I'm not sure that would make it easier to read, so no strong opinion here.)
There was a problem hiding this comment.
not sure it would improve the readability
| break; | ||
| case SETTER: | ||
| if (method.getName().startsWith("set")) { | ||
| this.name = ReflectUtils.stripPrefix(method.getName(), "get"); |
There was a problem hiding this comment.
s/get/set/
You must be missing some tests for setters?
| }, | ||
| values -> Row.withSchema(schema).addValues(values).build()); | ||
| } | ||
| private Schema schema; |
| } | ||
|
|
||
| /** | ||
| * Get a {@link TypeName#INT16 16} value by field index, {@link ClassCastException} is thrown if |
There was a problem hiding this comment.
Looks like there is an extra 16? (This line should be unchanged.)
| * the appropriate fields from the POJO. | ||
| */ | ||
| public class RowWithGetters extends Row { | ||
| private FieldValueGetterFactory fieldValueGetterFactory; |
There was a problem hiding this comment.
All these things appear to be final?
|
|
||
| /** Concrete subclass of {@link Row} that explicitly stores all fields of the row. */ | ||
| public class RowWithStorage extends Row { | ||
| private List<Object> values; |
apilloud
left a comment
There was a problem hiding this comment.
Thanks for the cleanup. LGTM
Adds automatic schema support for these types of classes. ByteBuddy is use to generate automatic connectors, so that Row objects can transparently delegate to the underlying storage in user objects.
While this PR is large, splitting it up didn't seem to help much. Also, much of the line count is in unit tests.
R: @apilloud