From 8e64a131f79f1fe66a7cf29fa4a4014296b1b55e Mon Sep 17 00:00:00 2001 From: Artem Bilan Date: Wed, 3 Jan 2024 14:46:20 -0500 Subject: [PATCH] Add `updateCopyrights` Gradle task * Fix Checkstyle violations for `spring-config-common` and `spring-aggregator-function` --- build.gradle | 73 +++++++++++++------ .../SpelExpressionConverterConfiguration.java | 42 ++++++----- .../cloud/fn/common/config/package-info.java | 4 + .../AggregatorFunctionConfiguration.java | 6 +- .../aggregator/MessageStoreConfiguration.java | 10 +-- .../cloud/fn/aggregator/package-info.java | 4 + .../fn/aggregator/DefaultAggregatorTests.java | 18 ++--- 7 files changed, 100 insertions(+), 57 deletions(-) create mode 100644 common/spring-config-common/src/main/java/org/springframework/cloud/fn/common/config/package-info.java create mode 100644 function/spring-aggregator-function/src/main/java/org/springframework/cloud/fn/aggregator/package-info.java diff --git a/build.gradle b/build.gradle index 0404859f..56deccf2 100644 --- a/build.gradle +++ b/build.gradle @@ -9,6 +9,7 @@ plugins { id 'io.spring.javaformat' version "${javaFormatVersion}" id 'com.github.spotbugs' version '6.0.4' id 'com.google.protobuf' version '0.9.4' apply false + id 'org.ajoberstar.grgit' version '5.2.1' } description = 'Spring Functions Catlog' @@ -19,6 +20,18 @@ ext { apply from: 'dependencies.gradle' +ext { + modifiedFiles = files().from { files(grgit.status().unstaged.modified).filter { f -> f.name.endsWith('.java') } } + modifiedFiles.finalizeValueOnRead() + + javadocLinks = [ + 'https://docs.oracle.com/en/java/javase/17/docs/api/', + 'https://jakarta.ee/specifications/platform/10/apidocs/', + 'https://docs.spring.io/spring-framework/docs/current/javadoc-api', + 'https://docs.spring.io/spring-integration/docs/current/api/' + ] as String[] +} + allprojects { group = 'org.springframework.cloud.fn' @@ -31,13 +44,6 @@ allprojects { // maven { url 'https://repo.spring.io/libs-staging-local' } } - ext.javadocLinks = [ - 'https://docs.oracle.com/en/java/javase/17/docs/api/', - 'https://jakarta.ee/specifications/platform/10/apidocs/', - 'https://docs.spring.io/spring-framework/docs/current/javadoc-api', - 'https://docs.spring.io/spring-integration/docs/current/api/' - ] as String[] - apply plugin: 'io.spring.dependency-management' dependencyManagement { @@ -55,13 +61,9 @@ allprojects { mavenBom "org.springframework.boot:spring-boot-dependencies:$springBootVersion" mavenBom "org.springframework.cloud:spring-cloud-dependencies:$springCloudVersion" } - } - } - - configure(javaProjects) { subproject -> apply plugin: 'java-library' apply plugin: 'eclipse' @@ -110,6 +112,12 @@ configure(javaProjects) { subproject -> } } + checkstyle { + toolVersion = '10.3' + configDirectory = rootProject.file('etc/checkstyle') + ignoreFailures = true + } + // dependencies that are common across all java projects dependencies { annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor' @@ -135,17 +143,7 @@ configure(javaProjects) { subproject -> testRuntimeOnly 'org.apache.logging.log4j:log4j-core' testRuntimeOnly 'org.apache.logging.log4j:log4j-jcl' - } - [compileJava, compileTestJava]*.options*.compilerArgs = ['-Xlint:all,-options,-processing', '-parameters'] - - checkstyle { - toolVersion = '10.3' - configDirectory = rootProject.file('etc/checkstyle') - ignoreFailures = true - } - - dependencies { // NOTE: We explicitly specify checkstyle dep before javaformat checkstyle due to antlr class mismatch checkstyle("com.puppycrawl.tools:checkstyle:${checkstyle.toolVersion}") checkstyle("io.spring.javaformat:spring-javaformat-checkstyle:${javaFormatVersion}") @@ -155,6 +153,8 @@ configure(javaProjects) { subproject -> exclude 'org/springframework/cloud/fn/object/detection/protos' } + [compileJava, compileTestJava]*.options*.compilerArgs = ['-Xlint:all,-options,-processing', '-parameters'] + test { maxHeapSize = '2g' jvmArgs '-XX:+HeapDumpOnOutOfMemoryError' @@ -165,6 +165,37 @@ configure(javaProjects) { subproject -> logging.captureStandardOutput(LogLevel.INFO) } + tasks.register('updateCopyrights') { + onlyIf { !isCI } + inputs.files(modifiedFiles.filter { f -> f.path.contains(subproject.name) }) + outputs.dir('build/classes') + + doLast { + def now = Calendar.instance.get(Calendar.YEAR) as String + inputs.files.each { file -> + def line + file.withReader { reader -> + while (line = reader.readLine()) { + def matcher = line =~ /Copyright (20\d\d)-?(20\d\d)?/ + if (matcher.count) { + def beginningYear = matcher[0][1] + if (now != beginningYear && now != matcher[0][2]) { + def years = "$beginningYear-$now" + def sourceCode = file.text + sourceCode = sourceCode.replaceFirst(/20\d\d(-20\d\d)?/, years) + file.text = sourceCode + println "Copyright updated for file: $file" + } + break + } + } + } + } + } + } + + compileJava.dependsOn updateCopyrights + jar { manifest { attributes( diff --git a/common/spring-config-common/src/main/java/org/springframework/cloud/fn/common/config/SpelExpressionConverterConfiguration.java b/common/spring-config-common/src/main/java/org/springframework/cloud/fn/common/config/SpelExpressionConverterConfiguration.java index 28e910b2..bf38bc11 100644 --- a/common/spring-config-common/src/main/java/org/springframework/cloud/fn/common/config/SpelExpressionConverterConfiguration.java +++ b/common/spring-config-common/src/main/java/org/springframework/cloud/fn/common/config/SpelExpressionConverterConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2020-2020 the original author or authors. + * Copyright 2020-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,14 +18,12 @@ package org.springframework.cloud.fn.common.config; import java.beans.Introspector; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass; import org.springframework.boot.context.properties.ConfigurationPropertiesBinding; import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Lazy; import org.springframework.core.convert.converter.Converter; import org.springframework.expression.EvaluationContext; import org.springframework.expression.Expression; @@ -33,20 +31,24 @@ import org.springframework.expression.ParseException; import org.springframework.expression.spel.standard.SpelExpression; import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.integration.config.IntegrationConverter; +import org.springframework.integration.context.IntegrationContextUtils; import org.springframework.integration.expression.SpelPropertyAccessorRegistrar; import org.springframework.integration.json.JsonPropertyAccessor; +/** + * The auto-configuration to register a {@link SpelConverter} for configuration + * properties. + * + * @author David Turanski + * @author Christian Tzolov + * @author Chris Bono + * @author Artem Bilan + */ @AutoConfiguration @AutoConfigureAfter(name = "org.springframework.cloud.stream.config.SpelExpressionConverterConfiguration") @ConditionalOnMissingClass("org.springframework.cloud.stream.config.SpelExpressionConverterConfiguration") public class SpelExpressionConverterConfiguration { - /** - * Specific Application Context name to be used as Bean qualifier when the - * {@link EvaluationContext} is injected. - */ - public static final String INTEGRATION_EVALUATION_CONTEXT = "integrationEvaluationContext"; - @Bean public static SpelPropertyAccessorRegistrar spelPropertyAccessorRegistrar() { return (new SpelPropertyAccessorRegistrar()) @@ -56,27 +58,27 @@ public class SpelExpressionConverterConfiguration { @Bean @ConfigurationPropertiesBinding @IntegrationConverter - public Converter spelConverter() { - return new SpelExpressionConverterConfiguration.SpelConverter(); + public Converter spelConverter( + @Qualifier(IntegrationContextUtils.INTEGRATION_EVALUATION_CONTEXT_BEAN_NAME) EvaluationContext evaluationContext) { + + return new SpelExpressionConverterConfiguration.SpelConverter(evaluationContext); } public static class SpelConverter implements Converter { - private SpelExpressionParser parser = new SpelExpressionParser(); + private static final SpelExpressionParser SPEL_EXPRESSION_PARSER = new SpelExpressionParser(); - @Autowired - @Qualifier(INTEGRATION_EVALUATION_CONTEXT) - @Lazy - private EvaluationContext evaluationContext; + private final EvaluationContext evaluationContext; - public SpelConverter() { + public SpelConverter(EvaluationContext evaluationContext) { + this.evaluationContext = evaluationContext; } public Expression convert(String source) { try { - Expression expression = this.parser.parseExpression(source); - if (expression instanceof SpelExpression) { - ((SpelExpression) expression).setEvaluationContext(this.evaluationContext); + Expression expression = SPEL_EXPRESSION_PARSER.parseExpression(source); + if (expression instanceof SpelExpression spelExpression) { + spelExpression.setEvaluationContext(this.evaluationContext); } return expression; diff --git a/common/spring-config-common/src/main/java/org/springframework/cloud/fn/common/config/package-info.java b/common/spring-config-common/src/main/java/org/springframework/cloud/fn/common/config/package-info.java new file mode 100644 index 00000000..5412929c --- /dev/null +++ b/common/spring-config-common/src/main/java/org/springframework/cloud/fn/common/config/package-info.java @@ -0,0 +1,4 @@ +/** + * The common classes for all functions. + */ +package org.springframework.cloud.fn.common.config; diff --git a/function/spring-aggregator-function/src/main/java/org/springframework/cloud/fn/aggregator/AggregatorFunctionConfiguration.java b/function/spring-aggregator-function/src/main/java/org/springframework/cloud/fn/aggregator/AggregatorFunctionConfiguration.java index d296da4c..70becbfc 100644 --- a/function/spring-aggregator-function/src/main/java/org/springframework/cloud/fn/aggregator/AggregatorFunctionConfiguration.java +++ b/function/spring-aggregator-function/src/main/java/org/springframework/cloud/fn/aggregator/AggregatorFunctionConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2020-2023 the original author or authors. + * Copyright 2020-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -49,6 +49,8 @@ import org.springframework.messaging.Message; import org.springframework.messaging.MessageChannel; /** + * The auto-configuration for aggregator function. + * * @author Artem Bilan * @author Corneil du Plessis */ @@ -65,7 +67,7 @@ public class AggregatorFunctionConfiguration { @Bean public Function>, Flux>> aggregatorFunction(FluxMessageChannel inputChannel, FluxMessageChannel outputChannel) { - return input -> Flux.from(outputChannel) + return (input) -> Flux.from(outputChannel) .doOnRequest((request) -> inputChannel.subscribeTo(input.map(( inputMessage) -> MessageBuilder.fromMessage(inputMessage).removeHeader("kafka_consumer").build()))); } diff --git a/function/spring-aggregator-function/src/main/java/org/springframework/cloud/fn/aggregator/MessageStoreConfiguration.java b/function/spring-aggregator-function/src/main/java/org/springframework/cloud/fn/aggregator/MessageStoreConfiguration.java index ea0587a9..7b718e7e 100644 --- a/function/spring-aggregator-function/src/main/java/org/springframework/cloud/fn/aggregator/MessageStoreConfiguration.java +++ b/function/spring-aggregator-function/src/main/java/org/springframework/cloud/fn/aggregator/MessageStoreConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2020-2020 the original author or authors. + * Copyright 2020-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -57,7 +57,7 @@ class MessageStoreConfiguration { static class Mongo { @Bean - public MessageGroupStore messageStore(MongoTemplate mongoTemplate, AggregatorFunctionProperties properties) { + MessageGroupStore messageStore(MongoTemplate mongoTemplate, AggregatorFunctionProperties properties) { if (StringUtils.hasText(properties.getMessageStoreEntity())) { return new ConfigurableMongoDbMessageStore(mongoTemplate, properties.getMessageStoreEntity()); } @@ -68,7 +68,7 @@ class MessageStoreConfiguration { @Bean @Primary - public MongoCustomConversions mongoDbCustomConversions() { + MongoCustomConversions mongoDbCustomConversions() { return new MongoCustomConversions( Arrays.asList(new MessageToBinaryConverter(), new BinaryToMessageConverter())); } @@ -82,7 +82,7 @@ class MessageStoreConfiguration { static class Redis { @Bean - public MessageGroupStore messageStore(RedisTemplate redisTemplate) { + MessageGroupStore messageStore(RedisTemplate redisTemplate) { return new RedisMessageStore(redisTemplate.getConnectionFactory()); } @@ -95,7 +95,7 @@ class MessageStoreConfiguration { static class Jdbc { @Bean - public MessageGroupStore messageStore(JdbcTemplate jdbcTemplate, AggregatorFunctionProperties properties) { + MessageGroupStore messageStore(JdbcTemplate jdbcTemplate, AggregatorFunctionProperties properties) { JdbcMessageStore messageStore = new JdbcMessageStore(jdbcTemplate); if (StringUtils.hasText(properties.getMessageStoreEntity())) { messageStore.setTablePrefix(properties.getMessageStoreEntity()); diff --git a/function/spring-aggregator-function/src/main/java/org/springframework/cloud/fn/aggregator/package-info.java b/function/spring-aggregator-function/src/main/java/org/springframework/cloud/fn/aggregator/package-info.java new file mode 100644 index 00000000..3d35f6fb --- /dev/null +++ b/function/spring-aggregator-function/src/main/java/org/springframework/cloud/fn/aggregator/package-info.java @@ -0,0 +1,4 @@ +/** + * The aggregator function support classes. + */ +package org.springframework.cloud.fn.aggregator; diff --git a/function/spring-aggregator-function/src/test/java/org/springframework/cloud/fn/aggregator/DefaultAggregatorTests.java b/function/spring-aggregator-function/src/test/java/org/springframework/cloud/fn/aggregator/DefaultAggregatorTests.java index a2f5eae8..efcc7eb0 100644 --- a/function/spring-aggregator-function/src/test/java/org/springframework/cloud/fn/aggregator/DefaultAggregatorTests.java +++ b/function/spring-aggregator-function/src/test/java/org/springframework/cloud/fn/aggregator/DefaultAggregatorTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2020-2022 the original author or authors. + * Copyright 2020-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,8 +20,6 @@ import java.time.Duration; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import reactor.core.publisher.Flux; import reactor.test.StepVerifier; @@ -41,8 +39,6 @@ import static org.assertj.core.api.Assertions.assertThat; @TestPropertySource(properties = "aggregator.message-store-type=simple") public class DefaultAggregatorTests extends AbstractAggregatorFunctionTests { - private static final Logger logger = LoggerFactory.getLogger(DefaultAggregatorTests.class); - @Test public void test() { Flux> input = Flux.just( @@ -58,13 +54,17 @@ public class DefaultAggregatorTests extends AbstractAggregatorFunctionTests { .build()); Flux> output = this.aggregatorFunction.apply(input.log("DefaultAggregatorTests:input")); - output.log("DefaultAggregatorTests:output").as(StepVerifier::create).assertNext((message) -> { - assertThat(message).extracting(Message::getPayload).asList().hasSize(2).contains("1", "2"); - }).thenCancel().verify(Duration.ofSeconds(30)); + output.log("DefaultAggregatorTests:output") + .as(StepVerifier::create) + .assertNext((message) -> assertThat(message).extracting(Message::getPayload) + .asList() + .hasSize(2) + .contains("1", "2")) + .thenCancel() + .verify(Duration.ofSeconds(30)); assertThat(this.messageGroupStore).isNull(); assertThat(this.aggregatingMessageHandler.getMessageStore()).isInstanceOf(SimpleMessageStore.class); - } }