[
https://issues.apache.org/jira/browse/BEAM-6240?focusedWorklogId=182358&page=com.atlassian.jira.plugin.system.issuetabpanels:worklog-tabpanel#worklog-182358
]
ASF GitHub Bot logged work on BEAM-6240:
----------------------------------------
Author: ASF GitHub Bot
Created on: 08/Jan/19 12:26
Start Date: 08/Jan/19 12:26
Worklog Time Spent: 10m
Work Description: kanterov commented on pull request #7289: [BEAM-6240]
Add a library of schema annotations for POJO and JavaBeans
URL: https://github.com/apache/beam/pull/7289#discussion_r245977416
##########
File path:
sdks/java/core/src/main/java/org/apache/beam/sdk/schemas/JavaBeanSchema.java
##########
@@ -47,70 +51,103 @@
/** {@link FieldValueTypeSupplier} that's based on getter methods. */
@VisibleForTesting
public static class GetterTypeSupplier implements FieldValueTypeSupplier {
+ public static final GetterTypeSupplier INSTANCE = new GetterTypeSupplier();
+
@Override
- public List<FieldValueTypeInformation> get(Class<?> clazz, Schema schema) {
- Map<String, FieldValueTypeInformation> types =
+ public List<FieldValueTypeInformation> get(Class<?> clazz, @Nullable
Schema schema) {
+ List<FieldValueTypeInformation> types =
ReflectUtils.getMethods(clazz)
.stream()
.filter(ReflectUtils::isGetter)
+ .filter(m -> !m.isAnnotationPresent(SchemaIgnore.class))
.map(FieldValueTypeInformation::forGetter)
- .collect(Collectors.toMap(FieldValueTypeInformation::getName,
Function.identity()));
- // Return the list ordered by the schema fields.
- return schema
- .getFields()
- .stream()
- .map(f -> types.get(f.getName()))
- .collect(Collectors.toList());
+ .map(
+ t -> {
+ FieldName fieldName =
t.getMethod().getAnnotation(FieldName.class);
+ return (fieldName != null) ? t.withName(fieldName.value())
: t;
+ })
+ .collect(Collectors.toList());
+ return (schema != null) ? StaticSchemaInference.sortBySchema(types,
schema) : types;
}
}
/** {@link FieldValueTypeSupplier} that's based on setter methods. */
@VisibleForTesting
public static class SetterTypeSupplier implements FieldValueTypeSupplier {
+ private static final SetterTypeSupplier INSTANCE = new
SetterTypeSupplier();
+
@Override
public List<FieldValueTypeInformation> get(Class<?> clazz, Schema schema) {
- Map<String, FieldValueTypeInformation> types =
+ List<FieldValueTypeInformation> types =
ReflectUtils.getMethods(clazz)
.stream()
.filter(ReflectUtils::isSetter)
+ .filter(m -> !m.isAnnotationPresent(SchemaIgnore.class))
.map(FieldValueTypeInformation::forSetter)
- .collect(Collectors.toMap(FieldValueTypeInformation::getName,
Function.identity()));
- // Return the list ordered by the schema fields.
- return schema
- .getFields()
- .stream()
- .map(f -> types.get(f.getName()))
- .collect(Collectors.toList());
+ .collect(Collectors.toList());
+
+ return (schema != null) ? StaticSchemaInference.sortBySchema(types,
schema) : types;
}
}
@Override
public <T> Schema schemaFor(TypeDescriptor<T> typeDescriptor) {
- return JavaBeanUtils.schemaFromJavaBeanClass(typeDescriptor.getRawType());
+ Schema schema =
+ JavaBeanUtils.schemaFromJavaBeanClass(
+ typeDescriptor.getRawType(), GetterTypeSupplier.INSTANCE);
+
+ // If there are no creator methods, then validate that we have setters for
every field.
+ // Otherwise, we will have not way of creating the class.
+ if (ReflectUtils.getAnnotatedCreateMethod(typeDescriptor.getRawType()) ==
null
+ && ReflectUtils.getAnnotatedConstructor(typeDescriptor.getRawType())
== null) {
+ JavaBeanUtils.validateJavaBean(
+ GetterTypeSupplier.INSTANCE.get(typeDescriptor.getRawType(), schema),
+ SetterTypeSupplier.INSTANCE.get(typeDescriptor.getRawType(),
schema));
+ }
+ return schema;
}
@Override
public FieldValueGetterFactory fieldValueGetterFactory() {
return (Class<?> targetClass, Schema schema) ->
- JavaBeanUtils.getGetters(targetClass, schema, new
GetterTypeSupplier());
+ JavaBeanUtils.getGetters(targetClass, schema,
GetterTypeSupplier.INSTANCE);
}
@Override
UserTypeCreatorFactory schemaTypeCreatorFactory() {
- return new SetterBasedCreatorFactory(new JavaBeanSetterFactory());
+ UserTypeCreatorFactory setterBasedFactory =
+ new SetterBasedCreatorFactory(new JavaBeanSetterFactory());
+
+ return (Class<?> targetClass, Schema schema) -> {
+ // If a static method is marked with @SchemaCreate, use that.
+ Method annotated = ReflectUtils.getAnnotatedCreateMethod(targetClass);
+ if (annotated != null) {
+ return JavaBeanUtils.getStaticCreator(
+ targetClass, annotated, schema, GetterTypeSupplier.INSTANCE);
+ }
+
+ // If a Constructor was tagged with @SchemaCreate, invoke that
constructor.
Review comment:
After sleeping over it I agree that it shouldn't matter. What can happen is
due to non-determinism in reflection we would get different methods
time-to-time, that could potentially raise an exception, or have different
behavior. But I find this more like a corner case.
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
[email protected]
Issue Time Tracking
-------------------
Worklog Id: (was: 182358)
Time Spent: 6h (was: 5h 50m)
> Allow users to annotate POJOs and JavaBeans for richer functionality
> --------------------------------------------------------------------
>
> Key: BEAM-6240
> URL: https://issues.apache.org/jira/browse/BEAM-6240
> Project: Beam
> Issue Type: Sub-task
> Components: sdk-java-core
> Reporter: Reuven Lax
> Assignee: Reuven Lax
> Priority: Major
> Time Spent: 6h
> Remaining Estimate: 0h
>
> Desired annotations:
> * SchemaIgnore - ignore this field
> * FieldName - allow the user to explicitly specify a field name
> * SchemaCreate - register a function to be used to create an object (so
> fields can be final, and no default constructor need be assumed).
--
This message was sent by Atlassian JIRA
(v7.6.3#76005)