-
Notifications
You must be signed in to change notification settings - Fork 29
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
Refactor processor to make extension easier #53
base: master
Are you sure you want to change the base?
Conversation
This delegates most of the field-specific processing to `FieldProcessor`, which can be implemented to customize handling of different types. Collections are handled by `CollectionProcessor`, optionals by `OptionalProcessor`. Everything else is handled by `DefaultProcessor`. A data-driven approach was taken, with `FieldProcessor` taking the descriptor and field as input and outputting Javapoet specs or statements. However, in this patch `CollectionProcessor` is dependent on `AutoMatterProcessor` for the implementation of `singular`. There is also some duplication and inefficiencies in the processor as a result of this refactor. Since doing away with them would change text order in some places and thus require edits to most of the test files, I prefer leaving that work to a followup commit to reduce review burden. Other notes: * It's not clear where common code should live. For now most of it is in default methods on `FieldProcessor`, but I'm open to suggestions. * Due to the above use of default, source level 1.8 is now required * I wasn't sure how to organize the classes, so I've left them all at top level. It might become clearer once common code is centralized and other processors are added. * Not sure if this is feasible, but it could be interesting to allow users to supply their own processors via some annotation, or to register them somehow with AutoMatter. This would allow extensions to live in separate packages.
@@ -123,6 +124,11 @@ private void process(final Element element) throws IOException, AutoMatterProces | |||
javaFile.writeTo(filer); | |||
} | |||
|
|||
private FieldProcessor processorForField(Descriptor d, ExecutableElement field) throws AutoMatterProcessorException { | |||
String prefix = fieldType(d, field).toString().split("<")[0]; |
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.
Use guava Splitter
instead of compiling a regex for every invocation.
@@ -86,6 +74,8 @@ | |||
private Elements elements; | |||
private Messager messager; | |||
private Types types; | |||
private Map<String, FieldProcessor> processors; | |||
private DefaultProcessor defaultProcessor = new DefaultProcessor(); |
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.
final
@@ -86,6 +74,8 @@ | |||
private Elements elements; | |||
private Messager messager; | |||
private Types types; | |||
private Map<String, FieldProcessor> processors; |
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.
Would it make sense for this to be a Map<Class, FieldProcessor>
instead?
OptionalProcessor optionalProcessor = new OptionalProcessor(); | ||
|
||
processors = ImmutableMap.of( | ||
"java.util.Map", collectionProcessor, |
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.
Would be nice if we could avoid these handcrafted strings.
@@ -950,7 +491,7 @@ private void assertNotNull(MethodSpec.Builder spec, String name, String msg) { | |||
.endControlFlow(); | |||
} | |||
|
|||
private TypeName builderType(final Descriptor d) { | |||
public static TypeName builderType(final Descriptor d) { |
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.
Move to a separate class and avoid circular imports?
@@ -0,0 +1,11 @@ | |||
package io.norberg.automatter.processor; | |||
|
|||
public class BuildStatements { |
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.
package-private
package io.norberg.automatter.processor; | ||
|
||
public class BuildStatements { | ||
Iterable<Statement> statements; |
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.
final
} else { | ||
parameters.add(fieldName(field)); | ||
BuildStatements buildStatements = processorForField(d, field).build(d, field); | ||
for (Statement s: buildStatements.statements) { |
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.
Whitespace around :
import static javax.lang.model.element.Modifier.PUBLIC; | ||
import static javax.lang.model.type.TypeKind.DECLARED; | ||
|
||
public class CollectionProcessor implements FieldProcessor { |
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.
package-private
public class CollectionProcessor implements FieldProcessor { | ||
private final AutoMatterProcessor processor; | ||
|
||
public CollectionProcessor(AutoMatterProcessor processor) { |
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 we factor things to avoid this circular dependency of passing in the AutoMatterProcessor
into field processors?
BuildStatements build(Descriptor d, ExecutableElement field) throws AutoMatterProcessorException; | ||
Iterable<Statement> valueConstructor(Descriptor d, ExecutableElement field) throws AutoMatterProcessorException; | ||
|
||
default TypeName fieldType(final Descriptor d, final ExecutableElement field) throws AutoMatterProcessorException { |
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 guess these methods aren't actually part of the FieldProcessor
interface. I.e., FieldProcessor
users aren't expected to call them.
How about grouping and moving them to separate classes based on functionality? E.g. put the field introspection methods into e.g. a Fields
class etc.
import static io.norberg.automatter.processor.AutoMatterProcessor.builderType; | ||
import static javax.lang.model.element.Modifier.PUBLIC; | ||
|
||
public class OptionalProcessor extends DefaultProcessor { |
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.
package-private
@@ -0,0 +1,11 @@ | |||
package io.norberg.automatter.processor; | |||
|
|||
public class Statement { |
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.
package-private
package io.norberg.automatter.processor; | ||
|
||
public class Statement { | ||
String statement; |
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.
final
This is a much-needed refactoring. Kudos! Looks great overall, just a few small comments.
Allowing extensions in separate packages at sounds great. AutoMatterProcessor can use |
Re: using |
This delegates most of the field-specific processing to
FieldProcessor
,which can be implemented to customize handling of different types.
Collections are handled by
CollectionProcessor
, optionals byOptionalProcessor
. Everything else is handled byDefaultProcessor
.A data-driven approach was taken, with
FieldProcessor
taking thedescriptor and field as input and outputting Javapoet specs or
statements. However, in this patch
CollectionProcessor
is dependent onAutoMatterProcessor
for the implementation ofsingular
.There is also some duplication and inefficiencies in the processor as a
result of this refactor. Since doing away with them would change text
order in some places and thus require edits to most of the test files,
I prefer leaving that work to a followup commit to reduce review burden.
Other notes:
It's not clear where common code should live. For now most of it is
in default methods on
FieldProcessor
, but I'm open to suggestions.Due to the above use of default, source level 1.8 is now required
I wasn't sure how to organize the classes, so I've left them all at
top level. It might become clearer once common code is centralized
and other processors are added.
Not sure if this is feasible, but it could be interesting to allow
users to supply their own processors via some annotation, or to
register them somehow with AutoMatter. This would allow extensions to
live in separate packages.