Skip to content

[BEAM-4453] Add schema support for Java POJOs and Java Beans#5873

Merged
reuvenlax merged 18 commits intoapache:masterfrom
reuvenlax:schemas_javabean_inference
Jul 9, 2018
Merged

[BEAM-4453] Add schema support for Java POJOs and Java Beans#5873
reuvenlax merged 18 commits intoapache:masterfrom
reuvenlax:schemas_javabean_inference

Conversation

@reuvenlax
Copy link
Contributor

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

Reuven Lax added 15 commits July 2, 2018 17:13
   * 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).
Copy link
Member

@apilloud apilloud left a comment

Choose a reason for hiding this comment

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

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.");
Copy link
Member

Choose a reason for hiding this comment

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

Looks like spotless messed up your string. (Unnecessary " + " in the middle.)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed


// Iterate over the row, and set (possibly recursively) each field in the underlying object
// using the setter.
Schema schema = row.getSchema();
Copy link
Member

Choose a reason for hiding this comment

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

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

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;
Copy link
Member

Choose a reason for hiding this comment

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

All of these fields are immutable. Add final?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

*/
static class ConvertValueForGetter extends TypeConversion<StackManipulation> {
// The code that reads the value.
private StackManipulation readValue;
Copy link
Member

@apilloud apilloud Jul 6, 2018

Choose a reason for hiding this comment

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

final?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

readValue,
TypeCasting.to(READABLE_INSTANT_TYPE),
// Call ReadableInstant.getMillis to extract the millis since the epoch.
MethodInvocation.invoke(
Copy link
Member

Choose a reason for hiding this comment

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

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.)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

not sure it would improve the readability

break;
case SETTER:
if (method.getName().startsWith("set")) {
this.name = ReflectUtils.stripPrefix(method.getName(), "get");
Copy link
Member

Choose a reason for hiding this comment

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

s/get/set/

You must be missing some tests for setters?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed

},
values -> Row.withSchema(schema).addValues(values).build());
}
private Schema schema;
Copy link
Member

Choose a reason for hiding this comment

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

final?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

}

/**
* Get a {@link TypeName#INT16 16} value by field index, {@link ClassCastException} is thrown if
Copy link
Member

Choose a reason for hiding this comment

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

Looks like there is an extra 16? (This line should be unchanged.)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

* the appropriate fields from the POJO.
*/
public class RowWithGetters extends Row {
private FieldValueGetterFactory fieldValueGetterFactory;
Copy link
Member

Choose a reason for hiding this comment

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

All these things appear to be final?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done


/** Concrete subclass of {@link Row} that explicitly stores all fields of the row. */
public class RowWithStorage extends Row {
private List<Object> values;
Copy link
Member

Choose a reason for hiding this comment

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

final?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

Copy link
Member

@apilloud apilloud left a comment

Choose a reason for hiding this comment

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

Thanks for the cleanup. LGTM

@reuvenlax reuvenlax merged commit 784f17e into apache:master Jul 9, 2018
@reuvenlax reuvenlax deleted the schemas_javabean_inference branch December 9, 2018 23:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants