Skip to content

Commit

Permalink
Code cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
charphi committed Jan 31, 2024
1 parent 98b239c commit 273a567
Show file tree
Hide file tree
Showing 4 changed files with 249 additions and 57 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -88,12 +88,18 @@ public TypeSpec generateLoader(boolean nested) {

TypeName quantifierType = getQuantifierType();

FieldSpec sourceField = newSourceField();
Optional<FieldSpec> idPatternField = newIdPatternField();
Optional<FieldSpec> batchField = newBatchField();
MethodSpec doLoadMethod = newDoLoadMethod(sourceField, idPatternField, batchField, quantifierType);
FieldSpec resourceField = newResourceField(doLoadMethod, quantifierType);
MethodSpec getMethod = newGetMethod(resourceField, quantifierType);
FieldSpec sourceField = getSourceField();
Optional<FieldSpec> batchField = getBatchField();

Optional<FieldSpec> idPatternField = getIdPatternField();
Optional<FieldSpec> filterField = getFilterField(idPatternField);
Optional<FieldSpec> sorterField = getSorterField();

CodeBlock rawStreamCode = getRawStreamCode(sourceField, batchField);

MethodSpec doLoadMethod = getDoLoadMethod(rawStreamCode, filterField, sorterField, quantifierType);
FieldSpec resourceField = getResourceField(doLoadMethod, quantifierType);
MethodSpec getMethod = getGetMethod(resourceField, quantifierType);

TypeSpec.Builder result = TypeSpec
.classBuilder(className)
Expand All @@ -102,8 +108,9 @@ public TypeSpec generateLoader(boolean nested) {
.addField(sourceField);

idPatternField.ifPresent(result::addField);

batchField.ifPresent(result::addField);
filterField.ifPresent(result::addField);
sorterField.ifPresent(result::addField);

result
.addMethod(doLoadMethod)
Expand Down Expand Up @@ -196,7 +203,13 @@ private String getBasicPreprocessingJavadoc() {
return "null";
}

private MethodSpec newDoLoadMethod(FieldSpec sourceField, Optional<FieldSpec> idPatternField, Optional<FieldSpec> batchField, TypeName quantifierType) {
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
private MethodSpec getDoLoadMethod(
CodeBlock rawStreamCode,
Optional<FieldSpec> filterField,
Optional<FieldSpec> sorterField,
TypeName quantifierType
) {
return MethodSpec
.methodBuilder("doLoad")
.addModifiers(PRIVATE)
Expand All @@ -206,72 +219,87 @@ private MethodSpec newDoLoadMethod(FieldSpec sourceField, Optional<FieldSpec> id
.addStatement(CodeBlock
.builder()
.add("return ")
.add(getPreprocessingCode(sourceField, idPatternField, batchField))
.add(getPreprocessingCode(rawStreamCode, filterField, sorterField))
.add(getQuantifierCode())
.build())
.build();
}

private CodeBlock getPreprocessingCode(FieldSpec sourceField, Optional<FieldSpec> idPatternField, Optional<FieldSpec> batchField) {
final CodeBlock stream = iterableToStream(sourceField);
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
private CodeBlock getPreprocessingCode(
CodeBlock rawStreamCode,
Optional<FieldSpec> filterField,
Optional<FieldSpec> sorterField
) {
return definition.getPreprocessor().isPresent()
? getAdvancedPreprocessingCode(rawStreamCode, filterField, sorterField, definition.getPreprocessor().get())
: getBasicPreprocessingCode(rawStreamCode, filterField, sorterField);
}

final CodeBlock streamWithBatch = batchField
.map(field -> concatStreams(stream, getBatchStream(field)))
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
private CodeBlock getRawStreamCode(FieldSpec sourceField, Optional<FieldSpec> batchField) {
final CodeBlock stream = iterableToStream(sourceField);
return batchField
.map(field -> concatStreams(stream, getBatchStreamCode(field)))
.orElse(stream);

final CodeBlock streamWithBatchAndIdFilter = idPatternField
.map(field -> filterStream(streamWithBatch, getIdPredicate(field)))
.orElse(streamWithBatch);

return definition.getPreprocessor().isPresent()
? getAdvancedPreprocessingCode(streamWithBatchAndIdFilter, definition.getPreprocessor().get())
: getBasicPreprocessingCode(streamWithBatchAndIdFilter);
}

private CodeBlock getBatchStream(FieldSpec field) {
private CodeBlock getBatchStreamCode(FieldSpec field) {
return flatMapStream(iterableToStream(field), CodeBlock.of("o -> o.getProviders()"));
}

private CodeBlock getIdPredicate(FieldSpec field) {
private CodeBlock getIdPredicateCode(FieldSpec field) {
return CodeBlock.of("o -> $N.matcher(o.$L()).matches()", field, ids.get(0).getMethod().getSimpleName());
}

private CodeBlock getAdvancedPreprocessingCode(CodeBlock streamBlock, TypeInstantiator preprocessor) {
return CodeBlock.of("$L\n.apply($L)", getInstantiatorCode(preprocessor), streamBlock);
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
private CodeBlock getAdvancedPreprocessingCode(
CodeBlock streamBlock,
Optional<FieldSpec> filterField,
Optional<FieldSpec> sorterField,
TypeInstantiator preprocessor
) {
CodeBlock result = CodeBlock.of("$L\n.apply($L)", getInstantiatorCode(preprocessor), streamBlock);
return getBasicPreprocessingCode(result, filterField, sorterField);
}

private CodeBlock getBasicPreprocessingCode(CodeBlock streamBlock) {
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
private CodeBlock getBasicPreprocessingCode(
CodeBlock streamBlock,
Optional<FieldSpec> filterField,
Optional<FieldSpec> sorterField
) {
CodeBlock.Builder result = CodeBlock.builder();
result.add(streamBlock);
if (definition.getWrapper().isPresent()) {
result.add(NEW_LINE).add(".map($L)", getWrapperCode(definition.getWrapper().get()));
result.add(NEW_LINE).add(".map($T.class::cast)", definition.getServiceType());
}
if (!filters.isEmpty()) {
result.add(NEW_LINE).add(".filter($L)", getFiltersCode(filters));
}
if (!sorters.isEmpty()) {
result.add(NEW_LINE).add(".sorted($L)", getSortersCode(sorters));
}
filterField.ifPresent(field -> result.add(NEW_LINE).add(".filter($L)", field.name));
sorterField.ifPresent(field -> result.add(NEW_LINE).add(".sorted($L)", field.name));
return result.build();
}

private CodeBlock getFiltersCode(List<LoadFilter> filters) {
Iterator<CodeBlock> filterIter = filters.stream()
private CodeBlock getFiltersCode(Optional<FieldSpec> idPatternField) {
List<CodeBlock> blocks = new ArrayList<>();
idPatternField.map(this::getIdPredicateCode).ifPresent(blocks::add);
filters.stream()
.sorted(Comparator.comparingInt(LoadFilter::getPosition))
.map(this::getFilterCode)
.iterator();
.forEach(blocks::add);

Iterator<CodeBlock> iterator = blocks.iterator();

CodeBlock first = filterIter.next();
CodeBlock first = iterator.next();

if (!filterIter.hasNext()) {
if (!iterator.hasNext()) {
return first;
}

CodeBlock.Builder result = CodeBlock.builder();
result.add(casting(typeOf(Predicate.class, definition.getServiceType()), first));
while (filterIter.hasNext()) {
result.add(".and($L)", filterIter.next());
while (iterator.hasNext()) {
result.add(".and($L)", iterator.next());
}
return result.build();
}
Expand All @@ -283,7 +311,7 @@ private CodeBlock getFilterCode(LoadFilter filter) {
: result;
}

private CodeBlock getSortersCode(List<LoadSorter> sorters) {
private CodeBlock getSortersCode() {
Iterator<CodeBlock> iter = sorters.stream()
.sorted(Comparator.comparingInt(LoadSorter::getPosition))
.map(this::getSorterCode)
Expand Down Expand Up @@ -386,7 +414,7 @@ private List<TypeName> getQuantifierException() {
: emptyList();
}

private FieldSpec newSourceField() {
private FieldSpec getSourceField() {
return FieldSpec
.builder(typeOf(Iterable.class, definition.getServiceType()), fieldName("source"))
.addModifiers(PRIVATE, FINAL)
Expand All @@ -395,7 +423,7 @@ private FieldSpec newSourceField() {
.build();
}

private Optional<FieldSpec> newBatchField() {
private Optional<FieldSpec> getBatchField() {
return definition.isBatch()
? Optional.of(FieldSpec
.builder(typeOf(Iterable.class, definition.resolveBatchName()), fieldName("batch"))
Expand All @@ -406,6 +434,29 @@ private Optional<FieldSpec> newBatchField() {
: Optional.empty();
}

@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
private Optional<FieldSpec> getFilterField(Optional<FieldSpec> idPatternField) {
return !filters.isEmpty() || idPatternField.isPresent()
? Optional.of(FieldSpec
.builder(typeOf(Predicate.class, definition.getServiceType()), fieldName("filter"))
.addModifiers(PRIVATE, FINAL)
.addModifiers(getSingletonModifiers())
.initializer("$L", getFiltersCode(idPatternField))
.build())
: Optional.empty();
}

private Optional<FieldSpec> getSorterField() {
return !sorters.isEmpty()
? Optional.of(FieldSpec
.builder(typeOf(Comparator.class, definition.getServiceType()), fieldName("sorter"))
.addModifiers(PRIVATE, FINAL)
.addModifiers(getSingletonModifiers())
.initializer("$L", getSortersCode())
.build())
: Optional.empty();
}

private CodeBlock getBackendInitCode(ClassName serviceType) {
return definition.getBackend().isPresent()
? CodeBlock.of("$L.apply($T.class)", getInstantiatorCode(definition.getBackend().get()), serviceType)
Expand All @@ -427,7 +478,7 @@ private CodeBlock getCleanerInitCode() {
: CodeBlock.of("loader -> (($T)loader).reload()", ServiceLoader.class);
}

private FieldSpec newResourceField(MethodSpec doLoadMethod, TypeName quantifierType) {
private FieldSpec getResourceField(MethodSpec doLoadMethod, TypeName quantifierType) {
return getResourceFieldBuilder(quantifierType)
.addModifiers(getSingletonModifiers())
.initializer(getResourceInitializer(doLoadMethod))
Expand Down Expand Up @@ -457,7 +508,7 @@ private CodeBlock getResourceInitializer(MethodSpec doLoadMethod) {
: CodeBlock.of("$N()", doLoadMethod);
}

private MethodSpec newGetMethod(FieldSpec resourceField, TypeName quantifierType) {
private MethodSpec getGetMethod(FieldSpec resourceField, TypeName quantifierType) {
return MethodSpec
.methodBuilder("get")
.addJavadoc(CodeBlock
Expand Down Expand Up @@ -607,7 +658,7 @@ private MethodSpec newLoadMethod(String className, TypeName quantifierType, Meth
}


private Optional<FieldSpec> newIdPatternField() {
private Optional<FieldSpec> getIdPatternField() {
return ids.size() == 1 && !ids.get(0).getPattern().isEmpty()
? Optional.of(FieldSpec
.builder(Pattern.class, fieldName("ID_PATTERN"))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -311,14 +311,15 @@ public void testValidFilters() {
.has(sourceFileNamed("definition", "FiltersLoader.java"))
.extracting(Compilations::contentsAsUtf8String, STRING)
.contains(
".filter(filter)",
"private final Optional<Filters.SingleFilter> resource = doLoad();",
".filter(Filters.SingleFilter::isAvailable)",
"private final Predicate<Filters.SingleFilter> filter = Filters.SingleFilter::isAvailable",
"private final Optional<Filters.MultiFilter> resource = doLoad();",
".filter(((Predicate<Filters.MultiFilter>)Filters.MultiFilter::isAvailable).and(Filters.MultiFilter::isFastEnough))",
"private final Predicate<Filters.MultiFilter> filter = ((Predicate<Filters.MultiFilter>)Filters.MultiFilter::isAvailable).and(Filters.MultiFilter::isFastEnough)",
"private final Optional<Filters.ReversedFilter> resource = doLoad();",
".filter(((Predicate<Filters.ReversedFilter>)Filters.ReversedFilter::isAvailable).negate())",
"private final Predicate<Filters.ReversedFilter> filter = ((Predicate<Filters.ReversedFilter>)Filters.ReversedFilter::isAvailable).negate()",
"private final Optional<Filters.MultiFilterWithPosition> resource = doLoad();",
".filter(((Predicate<Filters.MultiFilterWithPosition>)Filters.MultiFilterWithPosition::isFastEnough).and(Filters.MultiFilterWithPosition::isAvailable))"
"private final Predicate<Filters.MultiFilterWithPosition> filter = ((Predicate<Filters.MultiFilterWithPosition>)Filters.MultiFilterWithPosition::isFastEnough).and(Filters.MultiFilterWithPosition::isAvailable)"
);
}

Expand Down Expand Up @@ -410,20 +411,21 @@ public void testValidSorters() {
.has(sourceFileNamed("definition", "SortersLoader.java"))
.extracting(Compilations::contentsAsUtf8String, STRING)
.contains(
".sorted(sorter)",
"private final Optional<Sorters.IntSorter> resource = doLoad();",
".sorted(Comparator.comparingInt(Sorters.IntSorter::getCost))",
"Comparator.comparingInt(Sorters.IntSorter::getCost)",
"private final Optional<Sorters.LongSorter> resource = doLoad();",
".sorted(Comparator.comparingLong(Sorters.LongSorter::getCost))",
"Comparator.comparingLong(Sorters.LongSorter::getCost)",
"private final Optional<Sorters.DoubleSorter> resource = doLoad();",
".sorted(Comparator.comparingDouble(Sorters.DoubleSorter::getCost))",
"Comparator.comparingDouble(Sorters.DoubleSorter::getCost)",
"private final Optional<Sorters.ComparableSorter> resource = doLoad();",
".sorted(Comparator.comparing(Sorters.ComparableSorter::getCost))",
"Comparator.comparing(Sorters.ComparableSorter::getCost)",
"private final Optional<Sorters.MultiSorter> resource = doLoad();",
".sorted(((Comparator<Sorters.MultiSorter>)Comparator.comparingInt(Sorters.MultiSorter::getCost)).thenComparing(Comparator.comparingDouble(Sorters.MultiSorter::getAccuracy)))",
"((Comparator<Sorters.MultiSorter>)Comparator.comparingInt(Sorters.MultiSorter::getCost)).thenComparing(Comparator.comparingDouble(Sorters.MultiSorter::getAccuracy))",
"private final Optional<Sorters.ReversedSorter> resource = doLoad();",
".sorted(Collections.reverseOrder(Comparator.comparingInt(Sorters.ReversedSorter::getCost)))",
"Collections.reverseOrder(Comparator.comparingInt(Sorters.ReversedSorter::getCost))",
"private final Optional<Sorters.MultiSorterWithPosition> resource = doLoad();",
".sorted(((Comparator<Sorters.MultiSorterWithPosition>)Comparator.comparingDouble(Sorters.MultiSorterWithPosition::getAccuracy)).thenComparing(Comparator.comparingInt(Sorters.MultiSorterWithPosition::getCost)))"
"((Comparator<Sorters.MultiSorterWithPosition>)Comparator.comparingDouble(Sorters.MultiSorterWithPosition::getAccuracy)).thenComparing(Comparator.comparingInt(Sorters.MultiSorterWithPosition::getCost))"
);
}

Expand Down Expand Up @@ -621,7 +623,8 @@ public void testWithValidPattern() {
.extracting(Compilations::contentsAsUtf8String, STRING)
.contains(
"public static final Pattern ID_PATTERN = Pattern.compile(\"^[A-Z0-9]+(?:_[A-Z0-9]+)*$\");",
".filter(o -> ID_PATTERN.matcher(o.getName()).matches())"
"private final Predicate<TestIdValidPattern> filter = o -> ID_PATTERN.matcher(o.getName()).matches()",
".filter(filter)"
);
}

Expand Down Expand Up @@ -849,6 +852,19 @@ public void testNoFallback() {
.has(sourceFileNamed("definition", "TestNoFallbackLoader.java"));
}

@Test
public void testAllOptions() {
JavaFileObject file = forResource("definition/TestAllOptions.java");

assertThat(compile(file))
.has(succeededWithoutWarnings())
.extracting(Compilation::generatedSourceFiles, JAVA_FILE_OBJECTS)
.filteredOn(sourceFileNamed("definition", "TestAllOptionsLoader.java"))
.singleElement()
.extracting(Compilations::contentsAsUtf8String, STRING)
.isEqualToIgnoringNewLines(contentsAsUtf8String(forResource("definition/expected/TestAllOptionsLoader.java")));
}

private static Compilation compile(JavaFileObject file) {
return Compiler.javac()
.withProcessors(new ServiceDefinitionProcessor(), new ServiceProviderProcessor())
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package definition;

import nbbrd.service.*;

@ServiceDefinition(
quantifier = Quantifier.MULTIPLE,
batch = true,
mutability = Mutability.CONCURRENT,
singleton = true
)
interface TestAllOptions {

@ServiceId( pattern = ServiceId.SCREAMING_SNAKE_CASE )
String getName();

@ServiceSorter(position = 1, reverse = false)
int getCost1();

@ServiceSorter(position = 2, reverse = true)
int getCost2();

@ServiceFilter(position = 1, negate = false)
boolean isAvailable();

@ServiceFilter(position = 2, negate = true)
boolean isDisabled();
}
Loading

0 comments on commit 273a567

Please sign in to comment.