diff --git a/spring-cloud-function-deployer/src/it/bootapp-multi/pom.xml b/spring-cloud-function-deployer/src/it/bootapp-multi/pom.xml
index c9a06966b..371ccae03 100644
--- a/spring-cloud-function-deployer/src/it/bootapp-multi/pom.xml
+++ b/spring-cloud-function-deployer/src/it/bootapp-multi/pom.xml
@@ -12,13 +12,13 @@
org.springframework.boot
spring-boot-starter-parent
- 3.4.0
+ 3.4.13
17
- 4.2.1-SNAPSHOT
+ 4.2.5-SNAPSHOT
1.0.27.RELEASE
diff --git a/spring-cloud-function-deployer/src/it/bootapp-with-javax/pom.xml b/spring-cloud-function-deployer/src/it/bootapp-with-javax/pom.xml
index a79fb8550..5cd299e9c 100644
--- a/spring-cloud-function-deployer/src/it/bootapp-with-javax/pom.xml
+++ b/spring-cloud-function-deployer/src/it/bootapp-with-javax/pom.xml
@@ -12,13 +12,13 @@
org.springframework.boot
spring-boot-starter-parent
- 3.4.0
+ 3.4.13
17
- 4.2.1-SNAPSHOT
+ 4.2.5-SNAPSHOT
1.0.27.RELEASE
diff --git a/spring-cloud-function-deployer/src/it/bootapp-with-scf/pom.xml b/spring-cloud-function-deployer/src/it/bootapp-with-scf/pom.xml
index f65b2be96..7edf8fcab 100644
--- a/spring-cloud-function-deployer/src/it/bootapp-with-scf/pom.xml
+++ b/spring-cloud-function-deployer/src/it/bootapp-with-scf/pom.xml
@@ -12,13 +12,13 @@
org.springframework.boot
spring-boot-starter-parent
- 3.4.0
+ 3.4.13
17
- 4.2.1-SNAPSHOT
+ 4.2.5-SNAPSHOT
1.0.27.RELEASE
diff --git a/spring-cloud-function-deployer/src/it/bootapp/pom.xml b/spring-cloud-function-deployer/src/it/bootapp/pom.xml
index 52d919901..2ae5ee050 100644
--- a/spring-cloud-function-deployer/src/it/bootapp/pom.xml
+++ b/spring-cloud-function-deployer/src/it/bootapp/pom.xml
@@ -12,13 +12,13 @@
org.springframework.boot
spring-boot-starter-parent
- 3.4.0
+ 3.4.13
17
- 4.2.1-SNAPSHOT
+ 4.2.5-SNAPSHOT
1.0.27.RELEASE
diff --git a/spring-cloud-function-deployer/src/it/bootjar-multi/pom.xml b/spring-cloud-function-deployer/src/it/bootjar-multi/pom.xml
index 7e23581f8..e62c32227 100644
--- a/spring-cloud-function-deployer/src/it/bootjar-multi/pom.xml
+++ b/spring-cloud-function-deployer/src/it/bootjar-multi/pom.xml
@@ -12,13 +12,13 @@
org.springframework.boot
spring-boot-starter-parent
- 3.4.0
+ 3.4.13
17
- 4.2.1-SNAPSHOT
+ 4.2.5-SNAPSHOT
1.0.27.RELEASE
diff --git a/spring-cloud-function-deployer/src/it/bootjar/pom.xml b/spring-cloud-function-deployer/src/it/bootjar/pom.xml
index 25b0c1250..a7a66cd0c 100644
--- a/spring-cloud-function-deployer/src/it/bootjar/pom.xml
+++ b/spring-cloud-function-deployer/src/it/bootjar/pom.xml
@@ -12,13 +12,13 @@
org.springframework.boot
spring-boot-starter-parent
- 3.4.0
+ 3.4.13
17
- 4.2.1-SNAPSHOT
+ 4.2.5-SNAPSHOT
1.0.27.RELEASE
diff --git a/spring-cloud-function-deployer/src/it/bootjarnostart/pom.xml b/spring-cloud-function-deployer/src/it/bootjarnostart/pom.xml
index 2d4771bfb..aec3cfe58 100644
--- a/spring-cloud-function-deployer/src/it/bootjarnostart/pom.xml
+++ b/spring-cloud-function-deployer/src/it/bootjarnostart/pom.xml
@@ -12,13 +12,13 @@
org.springframework.boot
spring-boot-starter-parent
- 3.4.0
+ 3.4.13
17
- 4.2.1-SNAPSHOT
+ 4.2.5-SNAPSHOT
1.0.27.RELEASE
diff --git a/spring-cloud-function-deployer/src/main/java/org/springframework/cloud/function/deployer/DeployerContextUtils.java b/spring-cloud-function-deployer/src/main/java/org/springframework/cloud/function/deployer/DeployerContextUtils.java
index 070328b0d..09836e495 100644
--- a/spring-cloud-function-deployer/src/main/java/org/springframework/cloud/function/deployer/DeployerContextUtils.java
+++ b/spring-cloud-function-deployer/src/main/java/org/springframework/cloud/function/deployer/DeployerContextUtils.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2019-2019 the original author or authors.
+ * Copyright 2019-present 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.
diff --git a/spring-cloud-function-deployer/src/main/java/org/springframework/cloud/function/deployer/FunctionArchiveDeployer.java b/spring-cloud-function-deployer/src/main/java/org/springframework/cloud/function/deployer/FunctionArchiveDeployer.java
index 2c96fdd64..98b94d569 100644
--- a/spring-cloud-function-deployer/src/main/java/org/springframework/cloud/function/deployer/FunctionArchiveDeployer.java
+++ b/spring-cloud-function-deployer/src/main/java/org/springframework/cloud/function/deployer/FunctionArchiveDeployer.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2019-2021 the original author or authors.
+ * Copyright 2019-present 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.
diff --git a/spring-cloud-function-deployer/src/main/java/org/springframework/cloud/function/deployer/FunctionDeployerConfiguration.java b/spring-cloud-function-deployer/src/main/java/org/springframework/cloud/function/deployer/FunctionDeployerConfiguration.java
index 2105c5b0d..275d3fafa 100644
--- a/spring-cloud-function-deployer/src/main/java/org/springframework/cloud/function/deployer/FunctionDeployerConfiguration.java
+++ b/spring-cloud-function-deployer/src/main/java/org/springframework/cloud/function/deployer/FunctionDeployerConfiguration.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2019-2021 the original author or authors.
+ * Copyright 2019-present 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.
@@ -34,10 +34,10 @@
import org.springframework.boot.loader.archive.Archive;
import org.springframework.boot.loader.archive.ExplodedArchive;
import org.springframework.boot.loader.archive.JarFileArchive;
-import org.springframework.cloud.deployer.resource.maven.MavenProperties;
-import org.springframework.cloud.deployer.resource.maven.MavenResourceLoader;
import org.springframework.cloud.function.context.FunctionProperties;
import org.springframework.cloud.function.context.FunctionRegistry;
+import org.springframework.cloud.function.deployer.utils.MavenProperties;
+import org.springframework.cloud.function.deployer.utils.MavenResourceLoader;
import org.springframework.context.ApplicationContext;
import org.springframework.context.SmartLifecycle;
import org.springframework.context.annotation.Bean;
diff --git a/spring-cloud-function-deployer/src/main/java/org/springframework/cloud/function/deployer/FunctionDeployerProperties.java b/spring-cloud-function-deployer/src/main/java/org/springframework/cloud/function/deployer/FunctionDeployerProperties.java
index e5e61c779..11a73c976 100644
--- a/spring-cloud-function-deployer/src/main/java/org/springframework/cloud/function/deployer/FunctionDeployerProperties.java
+++ b/spring-cloud-function-deployer/src/main/java/org/springframework/cloud/function/deployer/FunctionDeployerProperties.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2019 the original author or authors.
+ * Copyright 2017-present 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.
diff --git a/spring-cloud-function-deployer/src/main/java/org/springframework/cloud/function/deployer/utils/LoggingRepositoryListener.java b/spring-cloud-function-deployer/src/main/java/org/springframework/cloud/function/deployer/utils/LoggingRepositoryListener.java
new file mode 100644
index 000000000..e5d7d07a9
--- /dev/null
+++ b/spring-cloud-function-deployer/src/main/java/org/springframework/cloud/function/deployer/utils/LoggingRepositoryListener.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2019-present 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.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.cloud.function.deployer.utils;
+
+import org.eclipse.aether.AbstractRepositoryListener;
+import org.eclipse.aether.RepositoryEvent;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * @author Corneil du Plessis
+ */
+public class LoggingRepositoryListener extends AbstractRepositoryListener {
+
+ private static final Logger logger = LoggerFactory.getLogger(LoggingRepositoryListener.class);
+
+ public void artifactDeployed(RepositoryEvent event) {
+ println("artifactDeployed", event.getArtifact() + " to " + event.getRepository());
+ }
+
+ public void artifactDeploying(RepositoryEvent event) {
+ println("artifactDeploying", event.getArtifact() + " to " + event.getRepository());
+ }
+
+ public void artifactDescriptorInvalid(RepositoryEvent event) {
+ println("artifactDescriptorInvalid", "for " + event.getArtifact() + ": " + event.getException().getMessage());
+ }
+
+ public void artifactDescriptorMissing(RepositoryEvent event) {
+ println("artifactDescriptorMissing", "for " + event.getArtifact());
+ }
+
+ public void artifactInstalled(RepositoryEvent event) {
+ println("artifactInstalled", event.getArtifact() + " to " + event.getFile());
+ }
+
+ public void artifactInstalling(RepositoryEvent event) {
+ println("artifactInstalling", event.getArtifact() + " to " + event.getFile());
+ }
+
+ public void artifactResolved(RepositoryEvent event) {
+ println("artifactResolved", event.getArtifact() + " from " + event.getRepository());
+ }
+
+ public void artifactDownloading(RepositoryEvent event) {
+ println("artifactDownloading", event.getArtifact() + " from " + event.getRepository());
+ }
+
+ public void artifactDownloaded(RepositoryEvent event) {
+ println("artifactDownloaded", event.getArtifact() + " from " + event.getRepository());
+ }
+
+ public void artifactResolving(RepositoryEvent event) {
+ println("artifactResolving", event.getArtifact().toString());
+ }
+
+ public void metadataDeployed(RepositoryEvent event) {
+ println("metadataDeployed", event.getMetadata() + " to " + event.getRepository());
+ }
+
+ public void metadataDeploying(RepositoryEvent event) {
+ println("metadataDeploying", event.getMetadata() + " to " + event.getRepository());
+ }
+
+ public void metadataInstalled(RepositoryEvent event) {
+ println("metadataInstalled", event.getMetadata() + " to " + event.getFile());
+ }
+
+ public void metadataInstalling(RepositoryEvent event) {
+ println("metadataInstalling", event.getMetadata() + " to " + event.getFile());
+ }
+
+ public void metadataInvalid(RepositoryEvent event) {
+ println("metadataInvalid", event.getMetadata().toString());
+ }
+
+ public void metadataResolved(RepositoryEvent event) {
+ println("metadataResolved", event.getMetadata() + " from " + event.getRepository());
+ }
+
+ public void metadataResolving(RepositoryEvent event) {
+ println("metadataResolving", event.getMetadata() + " from " + event.getRepository());
+ }
+
+ private void println(String event, String message) {
+ logger.info("Aether Repository - " + event + ": " + message);
+ }
+}
diff --git a/spring-cloud-function-deployer/src/main/java/org/springframework/cloud/function/deployer/utils/MavenArtifactResolver.java b/spring-cloud-function-deployer/src/main/java/org/springframework/cloud/function/deployer/utils/MavenArtifactResolver.java
new file mode 100644
index 000000000..fccb4d7ab
--- /dev/null
+++ b/spring-cloud-function-deployer/src/main/java/org/springframework/cloud/function/deployer/utils/MavenArtifactResolver.java
@@ -0,0 +1,431 @@
+/*
+ * Copyright 2019-present 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.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.cloud.function.deployer.utils;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.stream.Collectors;
+
+import org.apache.maven.repository.internal.MavenRepositorySystemUtils;
+import org.eclipse.aether.ConfigurationProperties;
+import org.eclipse.aether.DefaultRepositorySystemSession;
+import org.eclipse.aether.RepositorySystem;
+import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.artifact.Artifact;
+import org.eclipse.aether.artifact.DefaultArtifact;
+import org.eclipse.aether.connector.basic.BasicRepositoryConnectorFactory;
+import org.eclipse.aether.impl.DefaultServiceLocator;
+import org.eclipse.aether.repository.Authentication;
+import org.eclipse.aether.repository.AuthenticationContext;
+import org.eclipse.aether.repository.AuthenticationDigest;
+import org.eclipse.aether.repository.LocalRepository;
+import org.eclipse.aether.repository.Proxy;
+import org.eclipse.aether.repository.RemoteRepository;
+import org.eclipse.aether.repository.RepositoryPolicy;
+import org.eclipse.aether.resolution.ArtifactRequest;
+import org.eclipse.aether.resolution.ArtifactResolutionException;
+import org.eclipse.aether.resolution.ArtifactResult;
+import org.eclipse.aether.resolution.VersionRangeRequest;
+import org.eclipse.aether.resolution.VersionRangeResolutionException;
+import org.eclipse.aether.resolution.VersionRangeResult;
+import org.eclipse.aether.spi.connector.RepositoryConnectorFactory;
+import org.eclipse.aether.spi.connector.transport.TransporterFactory;
+import org.eclipse.aether.transport.file.FileTransporterFactory;
+import org.eclipse.aether.transport.http.HttpTransporterFactory;
+import org.eclipse.aether.util.artifact.JavaScopes;
+import org.eclipse.aether.util.repository.DefaultProxySelector;
+import org.eclipse.aether.version.Version;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.springframework.core.io.FileSystemResource;
+import org.springframework.core.io.Resource;
+import org.springframework.util.Assert;
+
+/**
+ * Resolves a {@link MavenResource} to
+ * locate the artifact (uber jar) in a local Maven repository, downloading the latest update from a
+ * remote repository if necessary.
+ * A set of default remote repos (Maven Central, Spring Snapshots, Spring Milestones) will be automatically added to
+ * the head of the list of remote repos. If the default repo is already explicitly configured (exact match on the repo url)
+ * then that particular default will be omitted. To skip the automatic default repos behavior altogether, set the
+ * {@link MavenProperties#isIncludeDefaultRemoteRepos()} property to {@code false}.
+ *
+ * @author David Turanski
+ * @author Mark Fisher
+ * @author Marius Bogoevici
+ * @author Ilayaperumal Gopinathan
+ * @author Donovan Muller
+ * @author Corneil du Plessis
+ * @author Chris Bono
+ */
+class MavenArtifactResolver {
+
+ private static final Logger logger = LoggerFactory.getLogger(MavenArtifactResolver.class);
+
+ private static final String DEFAULT_CONTENT_TYPE = "default";
+
+ private final RepositorySystem repositorySystem;
+
+ private final MavenProperties properties;
+
+ private final List remoteRepositories = new LinkedList<>();
+
+ private final Authentication proxyAuthentication;
+
+ /**
+ * Create an instance using the provided properties.
+ *
+ * @param properties the properties for the maven repositories, proxies, and authentication
+ */
+ MavenArtifactResolver(MavenProperties properties) {
+ Assert.notNull(properties, "MavenProperties must not be null");
+ Assert.notNull(properties.getLocalRepository(), "Local repository path cannot be null");
+ this.properties = properties;
+ if (logger.isDebugEnabled()) {
+ logger.debug("Configured local repository: " + properties.getLocalRepository());
+ logger.debug("Configured remote repositories: " + configuredRemoteRepositoriesDescription());
+ }
+ if (isProxyEnabled() && proxyHasCredentials()) {
+ final String username = this.properties.getProxy().getAuth().getUsername();
+ final String password = this.properties.getProxy().getAuth().getPassword();
+ this.proxyAuthentication = newAuthentication(username, password);
+ }
+ else {
+ this.proxyAuthentication = null;
+ }
+ File localRepository = new File(this.properties.getLocalRepository());
+ if (!localRepository.exists()) {
+ boolean created = localRepository.mkdirs();
+ // May have been created by another thread after above check. Double check.
+ Assert.isTrue(created || localRepository.exists(),
+ "Unable to create directory for local repository: " + localRepository);
+ }
+
+ Map defaultRepoUrlsToIds = defaultRemoteRepos();
+
+ for (Map.Entry entry : this.properties.getRemoteRepositories()
+ .entrySet()) {
+ MavenProperties.RemoteRepository remoteRepository = entry.getValue();
+ RemoteRepository.Builder remoteRepositoryBuilder = new RemoteRepository.Builder(
+ entry.getKey(), DEFAULT_CONTENT_TYPE, remoteRepository.getUrl());
+ // Update policies when set.
+ if (remoteRepository.getPolicy() != null) {
+ remoteRepositoryBuilder.setPolicy(new RepositoryPolicy(remoteRepository.getPolicy().isEnabled(),
+ remoteRepository.getPolicy().getUpdatePolicy(),
+ remoteRepository.getPolicy().getChecksumPolicy()));
+ }
+ if (remoteRepository.getReleasePolicy() != null) {
+ remoteRepositoryBuilder
+ .setReleasePolicy(new RepositoryPolicy(remoteRepository.getReleasePolicy().isEnabled(),
+ remoteRepository.getReleasePolicy().getUpdatePolicy(),
+ remoteRepository.getReleasePolicy().getChecksumPolicy()));
+ }
+ if (remoteRepository.getSnapshotPolicy() != null) {
+ remoteRepositoryBuilder
+ .setSnapshotPolicy(new RepositoryPolicy(remoteRepository.getSnapshotPolicy().isEnabled(),
+ remoteRepository.getSnapshotPolicy().getUpdatePolicy(),
+ remoteRepository.getSnapshotPolicy().getChecksumPolicy()));
+ }
+ if (remoteRepositoryHasCredentials(remoteRepository)) {
+ final String username = remoteRepository.getAuth().getUsername();
+ final String password = remoteRepository.getAuth().getPassword();
+ remoteRepositoryBuilder.setAuthentication(newAuthentication(username, password));
+ }
+ // do not add default repo if explicitly configured
+ defaultRepoUrlsToIds.remove(remoteRepository.getUrl());
+
+ RemoteRepository repo = proxyRepoIfProxyEnabled(remoteRepositoryBuilder.build());
+ this.remoteRepositories.add(repo);
+ }
+
+ if (!defaultRepoUrlsToIds.isEmpty() && this.properties.isIncludeDefaultRemoteRepos()) {
+ List defaultRepos = new ArrayList<>();
+ defaultRepoUrlsToIds.forEach((url, id) -> {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Adding {} ({}) to remote repositories list", id, url);
+ }
+ RemoteRepository defaultRepo = proxyRepoIfProxyEnabled(new RemoteRepository.Builder(id, DEFAULT_CONTENT_TYPE, url).build());
+ defaultRepos.add(defaultRepo);
+ });
+ this.remoteRepositories.addAll(0, defaultRepos);
+ }
+ if (logger.isDebugEnabled()) {
+ logger.debug("Using remote repositories: {}", actualRemoteRepositoriesDescription());
+ }
+ this.repositorySystem = newRepositorySystem();
+ }
+
+ /**
+ * Gets the default repos to automatically add.
+ * @return map of default repos (repo url to repo id)
+ */
+ protected Map defaultRemoteRepos() {
+ Map defaultRepos = new LinkedHashMap<>();
+ defaultRepos.put("https://repo.maven.apache.org/maven2", "mavenCentral-default");
+ defaultRepos.put("https://repo.spring.io/snapshot", "springSnapshot-default");
+ defaultRepos.put("https://repo.spring.io/milestone", "springMilestone-default");
+ return defaultRepos;
+ }
+
+ private RemoteRepository proxyRepoIfProxyEnabled(RemoteRepository remoteRepo) {
+ if (!isProxyEnabled()) {
+ return remoteRepo;
+ }
+ Proxy proxy;
+ MavenProperties.Proxy proxyProperties = this.properties.getProxy();
+ if (this.proxyAuthentication != null) {
+ proxy = new Proxy(
+ proxyProperties.getProtocol(),
+ proxyProperties.getHost(),
+ proxyProperties.getPort(),
+ this.proxyAuthentication);
+ }
+ else {
+ // if proxy does not require authentication
+ proxy = new Proxy(
+ proxyProperties.getProtocol(),
+ proxyProperties.getHost(),
+ proxyProperties.getPort());
+ }
+ DefaultProxySelector proxySelector = new DefaultProxySelector();
+ proxySelector.add(proxy, this.properties.getProxy().getNonProxyHosts());
+ proxy = proxySelector.getProxy(remoteRepo);
+
+ RemoteRepository.Builder remoteRepositoryBuilder = new RemoteRepository.Builder(remoteRepo);
+ remoteRepositoryBuilder.setProxy(proxy);
+ return remoteRepositoryBuilder.build();
+ }
+
+ /**
+ * Check if the proxy settings are provided.
+ *
+ * @return boolean true if the proxy settings are provided.
+ */
+ private boolean isProxyEnabled() {
+ return (this.properties.getProxy() != null &&
+ this.properties.getProxy().getHost() != null &&
+ this.properties.getProxy().getPort() > 0);
+ }
+
+ /**
+ * Check if the proxy setting has username/password set.
+ *
+ * @return boolean true if both the username/password are set
+ */
+ private boolean proxyHasCredentials() {
+ return (this.properties.getProxy() != null &&
+ this.properties.getProxy().getAuth() != null &&
+ this.properties.getProxy().getAuth().getUsername() != null &&
+ this.properties.getProxy().getAuth().getPassword() != null);
+ }
+
+ /**
+ * Check if the {@link MavenProperties.RemoteRepository} setting has username/password set.
+ *
+ * @return boolean true if both the username/password are set
+ */
+ private boolean remoteRepositoryHasCredentials(MavenProperties.RemoteRepository remoteRepository) {
+ return remoteRepository != null &&
+ remoteRepository.getAuth() != null &&
+ remoteRepository.getAuth().getUsername() != null &&
+ remoteRepository.getAuth().getPassword() != null;
+ }
+
+ /**
+ * Create an {@link Authentication} given a username/password.
+ *
+ * @param username the user
+ * @param password the password
+ * @return a configured {@link Authentication}
+ */
+ private Authentication newAuthentication(final String username, final String password) {
+ return new Authentication() {
+
+ @Override
+ public void fill(AuthenticationContext context, String key, Map data) {
+ context.put(AuthenticationContext.USERNAME, username);
+ context.put(AuthenticationContext.PASSWORD, password);
+ }
+
+ @Override
+ public void digest(AuthenticationDigest digest) {
+ digest.update(AuthenticationContext.USERNAME, username,
+ AuthenticationContext.PASSWORD, password);
+ }
+ };
+ }
+
+ DefaultRepositorySystemSession newRepositorySystemSession() {
+ return this.newRepositorySystemSession(this.repositorySystem, this.properties.getLocalRepository());
+ }
+
+ /*
+ * Create a session to manage remote and local synchronization.
+ */
+ private DefaultRepositorySystemSession newRepositorySystemSession(RepositorySystem system, String localRepoPath) {
+ DefaultRepositorySystemSession session = MavenRepositorySystemUtils.newSession();
+ LocalRepository localRepo = new LocalRepository(localRepoPath);
+ session.setLocalRepositoryManager(system.newLocalRepositoryManager(session, localRepo));
+ session.setOffline(this.properties.isOffline());
+ session.setUpdatePolicy(this.properties.getUpdatePolicy());
+ session.setChecksumPolicy(this.properties.getChecksumPolicy());
+ if (this.properties.isEnableRepositoryListener()) {
+ session.setRepositoryListener(new LoggingRepositoryListener());
+ }
+ if (this.properties.getConnectTimeout() != null) {
+ session.setConfigProperty(ConfigurationProperties.CONNECT_TIMEOUT, this.properties.getConnectTimeout());
+ }
+ if (this.properties.getRequestTimeout() != null) {
+ session.setConfigProperty(ConfigurationProperties.REQUEST_TIMEOUT, this.properties.getRequestTimeout());
+ }
+ if (isProxyEnabled()) {
+ DefaultProxySelector proxySelector = new DefaultProxySelector();
+ Proxy proxy = new Proxy(this.properties.getProxy().getProtocol(),
+ this.properties.getProxy().getHost(),
+ this.properties.getProxy().getPort(),
+ this.proxyAuthentication);
+ proxySelector.add(proxy, this.properties.getProxy().getNonProxyHosts());
+ session.setProxySelector(proxySelector);
+ }
+ // wagon configs
+ for (Entry entry : this.properties.getRemoteRepositories().entrySet()) {
+ session.setConfigProperty("aether.connector.wagon.config." + entry.getKey(), entry.getValue().getWagon());
+ }
+ return session;
+ }
+
+ /*
+ * Aether's components implement {@link org.eclipse.aether.spi.locator.Service} to ease manual wiring.
+ * Using the prepopulated {@link DefaultServiceLocator}, we need to register the repository connector
+ * and transporter factories
+ */
+ private RepositorySystem newRepositorySystem() {
+ DefaultServiceLocator locator = MavenRepositorySystemUtils.newServiceLocator();
+ locator.addService(RepositoryConnectorFactory.class, BasicRepositoryConnectorFactory.class);
+ locator.addService(TransporterFactory.class, FileTransporterFactory.class);
+
+ locator.addService(TransporterFactory.class, HttpTransporterFactory.class);
+
+ locator.setErrorHandler(new DefaultServiceLocator.ErrorHandler() {
+ @Override
+ public void serviceCreationFailed(Class> type, Class> impl, Throwable exception) {
+ throw new RuntimeException(exception);
+ }
+ });
+ return locator.getService(RepositorySystem.class);
+ }
+
+ /**
+ * Gets the list of configured remote repositories.
+ * @return unmodifiable list of configured remote repositories.
+ */
+ List remoteRepositories() {
+ return Collections.unmodifiableList(this.remoteRepositories);
+ }
+
+ private String actualRemoteRepositoriesDescription() {
+ return this.remoteRepositories.stream().map((repo) -> String.format("%s (%s)", repo.getId(), repo.getUrl()))
+ .collect(Collectors.joining(", ", "[", "]"));
+ }
+
+ private String configuredRemoteRepositoriesDescription() {
+ return this.properties.getRemoteRepositories().entrySet().stream()
+ .map((e) -> String.format("%s (%s)", e.getKey(), e.getValue().getUrl()))
+ .collect(Collectors.joining(", ", "[", "]"));
+ }
+
+ List getVersions(String coordinates) {
+ Artifact artifact = new DefaultArtifact(coordinates);
+ VersionRangeRequest rangeRequest = new VersionRangeRequest();
+ rangeRequest.setArtifact(artifact);
+ rangeRequest.setRepositories(this.remoteRepositories);
+ try {
+ VersionRangeResult versionResult = this.repositorySystem.resolveVersionRange(newRepositorySystemSession(), rangeRequest);
+ List versions = new ArrayList<>();
+ for (Version version: versionResult.getVersions()) {
+ versions.add(version.toString());
+ }
+ return versions;
+ }
+ catch (VersionRangeResolutionException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ /**
+ * Resolve an artifact and return its location in the local repository. Aether performs the normal
+ * Maven resolution process ensuring that the latest update is cached to the local repository.
+ * In addition, if the {@code MavenProperties.resolvePom} flag is true,
+ * the POM is also resolved and cached.
+ * @param resource the {@link MavenResource} representing the artifact
+ * @return a {@link FileSystemResource} representing the resolved artifact in the local repository
+ * @throws IllegalStateException if the artifact does not exist or the resolution fails
+ */
+ Resource resolve(MavenResource resource) {
+ Assert.notNull(resource, "MavenResource must not be null");
+ validateCoordinates(resource);
+ RepositorySystemSession session = newRepositorySystemSession(this.repositorySystem, this.properties.getLocalRepository());
+ try {
+ List artifactRequests = new ArrayList<>(2);
+ if (properties.isResolvePom()) {
+ artifactRequests.add(new ArtifactRequest(toPomArtifact(resource), this.remoteRepositories, JavaScopes.RUNTIME));
+ }
+ artifactRequests.add(new ArtifactRequest(toJarArtifact(resource), this.remoteRepositories, JavaScopes.RUNTIME));
+ List results = this.repositorySystem.resolveArtifacts(session, artifactRequests);
+ return toResource(results.get(results.size() - 1));
+ }
+ catch (ArtifactResolutionException ex) {
+ String errorMsg = String.format("Failed to resolve %s using remote repo(s): %s",
+ resource, actualRemoteRepositoriesDescription());
+ throw new IllegalStateException(errorMsg, ex);
+ }
+ }
+
+ private void validateCoordinates(MavenResource resource) {
+ Assert.hasText(resource.getGroupId(), "groupId must not be blank.");
+ Assert.hasText(resource.getArtifactId(), "artifactId must not be blank.");
+ Assert.hasText(resource.getExtension(), "extension must not be blank.");
+ Assert.hasText(resource.getVersion(), "version must not be blank.");
+ }
+
+ public FileSystemResource toResource(ArtifactResult resolvedArtifact) {
+ return new FileSystemResource(resolvedArtifact.getArtifact().getFile());
+ }
+
+ private Artifact toJarArtifact(MavenResource resource) {
+ return toArtifact(resource, resource.getExtension());
+ }
+
+ private Artifact toPomArtifact(MavenResource resource) {
+ return toArtifact(resource, "pom");
+ }
+
+ private Artifact toArtifact(MavenResource resource, String extension) {
+ return new DefaultArtifact(resource.getGroupId(),
+ resource.getArtifactId(),
+ resource.getClassifier() != null ? resource.getClassifier() : "",
+ extension,
+ resource.getVersion());
+ }
+}
diff --git a/spring-cloud-function-deployer/src/main/java/org/springframework/cloud/function/deployer/utils/MavenProperties.java b/spring-cloud-function-deployer/src/main/java/org/springframework/cloud/function/deployer/utils/MavenProperties.java
new file mode 100644
index 000000000..c161ecdc5
--- /dev/null
+++ b/spring-cloud-function-deployer/src/main/java/org/springframework/cloud/function/deployer/utils/MavenProperties.java
@@ -0,0 +1,491 @@
+/*
+ * Copyright 2019-present 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.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.cloud.function.deployer.utils;
+
+import java.io.File;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.TreeMap;
+
+/**
+ * Configuration Properties for Maven.
+ *
+ * @author Ilayaperumal Gopinathan
+ * @author Eric Bottard
+ * @author Mark Fisher
+ * @author Donovan Muller
+ */
+public class MavenProperties {
+
+ /**
+ * Default file path to a locally available maven repository.
+ */
+ private static String DEFAULT_LOCAL_REPO = System.getProperty("user.home") +
+ File.separator + ".m2" + File.separator + "repository";
+
+ /**
+ * Whether default remote repositories should be automatically included in the list of remote repositories.
+ */
+ private boolean includeDefaultRemoteRepos = true;
+
+ /**
+ * File path to a locally available maven repository, where artifacts will be downloaded.
+ */
+ private String localRepository = DEFAULT_LOCAL_REPO;
+
+ /**
+ * Locations of remote maven repositories from which artifacts will be downloaded, if not available locally.
+ */
+ private Map remoteRepositories = new TreeMap<>();
+
+ /**
+ * Whether the resolver should operate in offline mode.
+ */
+ private boolean offline;
+
+ /**
+ * Proxy configuration properties.
+ */
+ private Proxy proxy;
+
+ /**
+ * The connect timeout. If null, the underlying default will be used.
+ */
+ private Integer connectTimeout;
+
+ /**
+ * The request timeout. If null, the underlying default will be used.
+ */
+ private Integer requestTimeout;
+
+ /**
+ * In addition to resolving the JAR artifact, if true, resolve the POM artifact.
+ * This is consistent with the way that Maven resolves artifacts.
+ */
+ private boolean resolvePom;
+
+ private String updatePolicy;
+
+ private String checksumPolicy;
+
+ /**
+ * Add the ConsoleRepositoryListener to the session for debugging of artifact resolution.
+ */
+ private boolean enableRepositoryListener = false;
+
+ boolean isIncludeDefaultRemoteRepos() {
+ return includeDefaultRemoteRepos;
+ }
+
+ void setIncludeDefaultRemoteRepos(boolean includeDefaultRemoteRepos) {
+ this.includeDefaultRemoteRepos = includeDefaultRemoteRepos;
+ }
+
+ /**
+ * Use maven wagon based transport for http based artifacts.
+ */
+ private boolean useWagon;
+
+ public void setUseWagon(boolean useWagon) {
+ this.useWagon = useWagon;
+ }
+
+ public boolean isUseWagon() {
+ return useWagon;
+ }
+
+ public boolean isEnableRepositoryListener() {
+ return enableRepositoryListener;
+ }
+
+ public void setEnableRepositoryListener(boolean enableRepositoryListener) {
+ this.enableRepositoryListener = enableRepositoryListener;
+ }
+
+ public String getUpdatePolicy() {
+ return updatePolicy;
+ }
+
+ public void setUpdatePolicy(String updatePolicy) {
+ this.updatePolicy = updatePolicy;
+ }
+
+ public String getChecksumPolicy() {
+ return checksumPolicy;
+ }
+
+ public void setChecksumPolicy(String checksumPolicy) {
+ this.checksumPolicy = checksumPolicy;
+ }
+
+ public Map getRemoteRepositories() {
+ return remoteRepositories;
+ }
+
+ public void setRemoteRepositories(final Map remoteRepositories) {
+ this.remoteRepositories = new TreeMap<>(remoteRepositories);
+ }
+
+ public void setLocalRepository(String localRepository) {
+ this.localRepository = localRepository;
+ }
+
+ public String getLocalRepository() {
+ return localRepository;
+ }
+
+ public boolean isOffline() {
+ return offline;
+ }
+
+ public void setOffline(Boolean offline) {
+ this.offline = offline;
+ }
+
+ public Integer getConnectTimeout() {
+ return this.connectTimeout;
+ }
+
+ public void setConnectTimeout(Integer connectTimeout) {
+ this.connectTimeout = connectTimeout;
+ }
+
+ public Integer getRequestTimeout() {
+ return this.requestTimeout;
+ }
+
+ public void setRequestTimeout(Integer requestTimeout) {
+ this.requestTimeout = requestTimeout;
+ }
+
+ public Proxy getProxy() {
+ return this.proxy;
+ }
+
+ public void setProxy(Proxy proxy) {
+ this.proxy = proxy;
+ }
+
+ public boolean isResolvePom() {
+ return resolvePom;
+ }
+
+ public void setResolvePom(final boolean resolvePom) {
+ this.resolvePom = resolvePom;
+ }
+
+ public static class Proxy {
+
+ /**
+ * Protocol to use for proxy settings.
+ */
+ private String protocol = "http";
+
+ /**
+ * Host for the proxy.
+ */
+ private String host;
+
+ /**
+ * Port for the proxy.
+ */
+ private int port;
+
+ /**
+ * List of non proxy hosts.
+ */
+ private String nonProxyHosts;
+
+ private Authentication auth;
+
+ public String getProtocol() {
+ return this.protocol;
+ }
+
+ public void setProtocol(String protocol) {
+ this.protocol = protocol;
+ }
+
+ public String getHost() {
+ return this.host;
+ }
+
+ public void setHost(String host) {
+ this.host = host;
+ }
+
+ public int getPort() {
+ return this.port;
+ }
+
+ public void setPort(int port) {
+ this.port = port;
+ }
+
+ public String getNonProxyHosts() {
+ return this.nonProxyHosts;
+ }
+
+ public void setNonProxyHosts(String nonProxyHosts) {
+ this.nonProxyHosts = nonProxyHosts;
+ }
+
+ public Authentication getAuth() {
+ return this.auth;
+ }
+
+ public void setAuth(Authentication auth) {
+ this.auth = auth;
+ }
+ }
+
+ public enum WagonHttpMethod {
+ // directly maps to http methods in org.apache.maven.wagon.shared.http.HttpConfiguration
+ /**
+ * All methods.
+ */
+ all,
+ /**
+ * GET method.
+ */
+ get,
+ /**
+ * PUT method.
+ */
+ put,
+ /**
+ * HEAD method.
+ */
+ head;
+ }
+
+ public static class WagonHttpMethodProperties {
+ // directly maps to settings in org.apache.maven.wagon.shared.http.HttpMethodConfiguration
+ private boolean usePreemptive;
+ private boolean useDefaultHeaders;
+ private Integer connectionTimeout;
+ private Integer readTimeout;
+ private Map headers = new HashMap<>();
+ private Map params = new HashMap<>();
+
+ public boolean isUsePreemptive() {
+ return usePreemptive;
+ }
+
+ public void setUsePreemptive(boolean usePreemptive) {
+ this.usePreemptive = usePreemptive;
+ }
+
+ public boolean isUseDefaultHeaders() {
+ return useDefaultHeaders;
+ }
+
+ public void setUseDefaultHeaders(boolean useDefaultHeaders) {
+ this.useDefaultHeaders = useDefaultHeaders;
+ }
+
+ public Integer getConnectionTimeout() {
+ return connectionTimeout;
+ }
+
+ public void setConnectionTimeout(Integer connectionTimeout) {
+ this.connectionTimeout = connectionTimeout;
+ }
+
+ public Integer getReadTimeout() {
+ return readTimeout;
+ }
+
+ public void setReadTimeout(Integer readTimeout) {
+ this.readTimeout = readTimeout;
+ }
+
+ public Map getHeaders() {
+ return headers;
+ }
+
+ public void setHeaders(Map headers) {
+ this.headers = headers;
+ }
+
+ public Map getParams() {
+ return params;
+ }
+
+ public void setParams(Map params) {
+ this.params = params;
+ }
+ }
+
+ public static class Wagon {
+
+ private Map http = new HashMap<>();
+
+ public Map getHttp() {
+ return http;
+ }
+
+ public void setHttp(Map http) {
+ this.http = http;
+ }
+ }
+
+ public static class RemoteRepository {
+
+ /**
+ * URL of the remote maven repository. E.g. https://my.repo.com
+ */
+ private String url;
+
+ private Authentication auth;
+
+ private RepositoryPolicy policy;
+
+ private RepositoryPolicy snapshotPolicy;
+
+ private RepositoryPolicy releasePolicy;
+
+ private Wagon wagon = new Wagon();
+
+ public RemoteRepository() {
+ }
+
+ public RemoteRepository(final String url) {
+ this.url = url;
+ }
+
+ public RemoteRepository(final String url, final Authentication auth) {
+ this.url = url;
+ this.auth = auth;
+ }
+
+ public Wagon getWagon() {
+ return wagon;
+ }
+
+ public void setWagon(Wagon wagon) {
+ this.wagon = wagon;
+ }
+
+ public String getUrl() {
+ return url;
+ }
+
+ public void setUrl(final String url) {
+ this.url = url;
+ }
+
+ public Authentication getAuth() {
+ return auth;
+ }
+
+ public void setAuth(final Authentication auth) {
+ this.auth = auth;
+ }
+
+ public RepositoryPolicy getPolicy() {
+ return policy;
+ }
+
+ public void setPolicy(RepositoryPolicy policy) {
+ this.policy = policy;
+ }
+
+ public RepositoryPolicy getSnapshotPolicy() {
+ return snapshotPolicy;
+ }
+
+ public void setSnapshotPolicy(RepositoryPolicy snapshotPolicy) {
+ this.snapshotPolicy = snapshotPolicy;
+ }
+
+ public RepositoryPolicy getReleasePolicy() {
+ return releasePolicy;
+ }
+
+ public void setReleasePolicy(RepositoryPolicy releasePolicy) {
+ this.releasePolicy = releasePolicy;
+ }
+ }
+
+ public static class RepositoryPolicy {
+
+ private boolean enabled = true;
+
+ private String updatePolicy = "always";
+
+ private String checksumPolicy = "warn";
+
+ public boolean isEnabled() {
+ return enabled;
+ }
+
+ public void setEnabled(boolean enabled) {
+ this.enabled = enabled;
+ }
+
+ public String getUpdatePolicy() {
+ return updatePolicy;
+ }
+
+ public void setUpdatePolicy(String updatePolicy) {
+ this.updatePolicy = updatePolicy;
+ }
+
+ public String getChecksumPolicy() {
+ return checksumPolicy;
+ }
+
+ public void setChecksumPolicy(String checksumPolicy) {
+ this.checksumPolicy = checksumPolicy;
+ }
+
+ }
+
+ public static class Authentication {
+
+ private String username;
+
+ private String password;
+
+ public Authentication() {
+ }
+
+ public Authentication(String username, String password) {
+ this.username = username;
+ this.password = password;
+ }
+
+ public String getUsername() {
+ return this.username;
+ }
+
+ public void setUsername(String username) {
+ this.username = username;
+ }
+
+ public String getPassword() {
+ return this.password;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ }
+}
+
diff --git a/spring-cloud-function-deployer/src/main/java/org/springframework/cloud/function/deployer/utils/MavenResource.java b/spring-cloud-function-deployer/src/main/java/org/springframework/cloud/function/deployer/utils/MavenResource.java
new file mode 100644
index 000000000..cb396513e
--- /dev/null
+++ b/spring-cloud-function-deployer/src/main/java/org/springframework/cloud/function/deployer/utils/MavenResource.java
@@ -0,0 +1,324 @@
+/*
+ * Copyright 2019-present 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.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.springframework.cloud.function.deployer.utils;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.springframework.core.io.AbstractResource;
+import org.springframework.core.io.Resource;
+import org.springframework.util.Assert;
+import org.springframework.util.StringUtils;
+
+/**
+ * A {@link Resource} implementation for resolving an artifact via maven coordinates.
+ *
+ * The {@code MavenResource} class contains
+ * Maven coordinates for a jar file containing an app/library, or a Bill of Materials pom.
+ *
+ * To create a new instance, either use {@link Builder} to set the individual fields:
+ *
+ * new MavenResource.Builder()
+ * .setGroupId("org.springframework.sample")
+ * .setArtifactId("some-app")
+ * .setExtension("jar") //optional
+ * .setClassifier("exec") //optional
+ * .setVersion("2.0.0")
+ * .build()
+ *
+ * ...or use {@link #parse(String)} to parse the coordinates as a colon delimited string:
+ * <groupId>:<artifactId>[:<extension>[:<classifier>]]:<version>
+ *
+ * MavenResource.parse("org.springframework.sample:some-app:2.0.0);
+ * MavenResource.parse("org.springframework.sample:some-app:jar:exec:2.0.0);
+ *
+ * @author David Turanski
+ * @author Mark Fisher
+ * @author Patrick Peralta
+ * @author Venil Noronha
+ * @author Ilayaperumal Gopinathan
+ */
+public final class MavenResource extends AbstractResource {
+
+ /**
+ * URI Scheme.
+ */
+ public static String URI_SCHEME = "maven";
+
+ /**
+ * The default extension for the artifact.
+ */
+ final static String DEFAULT_EXTENSION = "jar";
+
+ /**
+ * String representing an empty classifier.
+ */
+ final static String EMPTY_CLASSIFIER = "";
+
+ /**
+ * Group ID for artifact; generally this includes the name of the
+ * organization that generated the artifact.
+ */
+ private final String groupId;
+
+ /**
+ * Artifact ID; generally this includes the name of the app or library.
+ */
+ private final String artifactId;
+
+ /**
+ * Extension of the artifact.
+ */
+ private final String extension;
+
+ /**
+ * Classifier of the artifact.
+ */
+ private final String classifier;
+
+ /**
+ * Version of the artifact.
+ */
+ private final String version;
+
+ private final MavenArtifactResolver resolver;
+
+ /**
+ * Construct a {@code MavenResource} object.
+ *
+ * @param groupId group ID for artifact
+ * @param artifactId artifact ID
+ * @param extension the file extension
+ * @param classifier artifact classifier - can be null
+ * @param version artifact version
+ * @param properties Maven configuration properties
+ */
+ private MavenResource(String groupId, String artifactId, String extension, String classifier,
+ String version, MavenProperties properties) {
+ Assert.hasText(groupId, "groupId must not be blank");
+ Assert.hasText(artifactId, "artifactId must not be blank");
+ Assert.hasText(extension, "extension must not be blank");
+ Assert.hasText(version, "version must not be blank");
+ this.groupId = groupId;
+ this.artifactId = artifactId;
+ this.extension = extension;
+ this.classifier = classifier == null ? EMPTY_CLASSIFIER : classifier;
+ this.version = version;
+ this.resolver = new MavenArtifactResolver(properties != null ? properties : new MavenProperties());
+ }
+
+
+ public String getGroupId() {
+ return groupId;
+ }
+
+ public String getArtifactId() {
+ return artifactId;
+ }
+
+ public String getExtension() {
+ return extension;
+ }
+
+ public String getClassifier() {
+ return classifier;
+ }
+
+ public String getVersion() {
+ return version;
+ }
+
+ @Override
+ public String getDescription() {
+ return this.toString();
+ }
+
+ @Override
+ public InputStream getInputStream() throws IOException {
+ return resolver.resolve(this).getInputStream();
+ }
+
+ @Override
+ public File getFile() throws IOException {
+ return resolver.resolve(this).getFile();
+ }
+
+ @Override
+ public String getFilename() {
+ return StringUtils.hasLength(classifier) ?
+ String.format("%s-%s-%s.%s", artifactId, version, classifier, extension) :
+ String.format("%s-%s.%s", artifactId, version, extension);
+ }
+
+ @Override
+ public boolean exists() {
+ try {
+ return super.exists();
+ }
+ catch (Exception e) {
+ // Resource.exists() has no throws clause, so return false
+ return false;
+ }
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof MavenResource)) {
+ return false;
+ }
+ MavenResource that = (MavenResource) o;
+ return this.groupId.equals(that.groupId) &&
+ this.artifactId.equals(that.artifactId) &&
+ this.extension.equals(that.extension) &&
+ this.classifier.equals(that.classifier) &&
+ this.version.equals(that.version);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = groupId.hashCode();
+ result = 31 * result + artifactId.hashCode();
+ result = 31 * result + extension.hashCode();
+ if (StringUtils.hasLength(classifier)) {
+ result = 31 * result + classifier.hashCode();
+ }
+ result = 31 * result + version.hashCode();
+ return result;
+ }
+
+ /**
+ * Returns the coordinates encoded as
+ * <groupId>:<artifactId>[:<extension>[:<classifier>]]:<version>,
+ * conforming to the Aether convention.
+ */
+ @Override
+ public String toString() {
+ return StringUtils.hasLength(classifier) ?
+ String.format("%s:%s:%s:%s:%s", groupId, artifactId, extension, classifier, version) :
+ String.format("%s:%s:%s:%s", groupId, artifactId, extension, version);
+ }
+
+ @Override
+ public URI getURI() throws IOException {
+ return URI.create(URI_SCHEME + "://" + toString());
+ }
+
+ /**
+ * Create a {@link MavenResource} for the provided coordinates and default properties.
+ *
+ * @param coordinates coordinates encoded as <groupId>:<artifactId>[:<extension>[:<classifier>]]:<version>,
+ * conforming to the Aether convention.
+ * @return the {@link MavenResource}
+ */
+ public static MavenResource parse(String coordinates) {
+ return parse(coordinates, null);
+ }
+
+ /**
+ * Create a {@link MavenResource} for the provided coordinates and properties.
+ *
+ * @param coordinates coordinates encoded as <groupId>:<artifactId>[:<extension>[:<classifier>]]:<version>,
+ * conforming to the Aether convention.
+ * @param properties the properties for the repositories, proxies, and authentication
+ * @return the {@link MavenResource}
+ */
+ public static MavenResource parse(String coordinates, MavenProperties properties) {
+ Assert.hasText(coordinates, "coordinates are required");
+ Pattern p = Pattern.compile("([^: ]+):([^: ]+)(:([^: ]*)(:([^: ]+))?)?:([^: ]+)");
+ Matcher m = p.matcher(coordinates);
+ Assert.isTrue(m.matches(), "Bad artifact coordinates " + coordinates
+ + ", expected format is :[:[:]]:");
+ String groupId = m.group(1);
+ String artifactId = m.group(2);
+ String extension = StringUtils.hasLength(m.group(4)) ? m.group(4) : DEFAULT_EXTENSION;
+ String classifier = StringUtils.hasLength(m.group(6)) ? m.group(6) : EMPTY_CLASSIFIER;
+ String version = m.group(7);
+ return new MavenResource(groupId, artifactId, extension, classifier, version, properties);
+ }
+
+ /**
+ * Get all the available versions on this maven co-ordinate.
+ * @param coordinates the co-ordinate with the version constraint added.
+ * Example: org.springframework.cloud.stream.app:http-source-rabbit:[0,)
+ * @return the list of all the available versions
+ */
+ public List getVersions(String coordinates) {
+ return this.resolver.getVersions(coordinates);
+ }
+
+ public static class Builder {
+
+ private String groupId;
+
+ private String artifactId;
+
+ private String extension = DEFAULT_EXTENSION;
+
+ private String classifier = EMPTY_CLASSIFIER;
+
+ private String version;
+
+ private final MavenProperties properties;
+
+ public Builder() {
+ this(null);
+ }
+
+ public Builder(MavenProperties properties) {
+ this.properties = properties;
+ }
+
+ public Builder groupId(String groupId) {
+ this.groupId = groupId;
+ return this;
+ }
+
+ public Builder artifactId(String artifactId) {
+ this.artifactId = artifactId;
+ return this;
+ }
+
+ public Builder extension(String extension) {
+ this.extension = extension;
+ return this;
+ }
+
+ public Builder classifier(String classifier) {
+ this.classifier = classifier;
+ return this;
+ }
+
+ public Builder version(String version) {
+ this.version = version;
+ return this;
+ }
+
+ public MavenResource build() {
+ return new MavenResource(groupId, artifactId, extension, classifier, version, properties);
+ }
+ }
+}
+
diff --git a/spring-cloud-function-deployer/src/main/java/org/springframework/cloud/function/deployer/utils/MavenResourceLoader.java b/spring-cloud-function-deployer/src/main/java/org/springframework/cloud/function/deployer/utils/MavenResourceLoader.java
new file mode 100644
index 000000000..846576adc
--- /dev/null
+++ b/spring-cloud-function-deployer/src/main/java/org/springframework/cloud/function/deployer/utils/MavenResourceLoader.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2019-present 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.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.cloud.function.deployer.utils;
+
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.ResourceLoader;
+import org.springframework.util.Assert;
+import org.springframework.util.ClassUtils;
+
+/**
+ * A {@link ResourceLoader} that loads {@link MavenResource}s from locations of the format
+ * {@literal maven://} where the value for "coordinates" conforms to the rules
+ * described on {@link MavenResource#parse(String)} .
+ *
+ * @author Mark Fisher
+ */
+public class MavenResourceLoader implements ResourceLoader {
+
+ private static final String URI_SCHEME = "maven";
+
+ private final MavenProperties properties;
+
+ private final ClassLoader classLoader = ClassUtils.getDefaultClassLoader();
+
+ /**
+ * Create a {@link MavenResourceLoader} that uses the provided {@link MavenProperties}.
+ *
+ * @param properties the {@link MavenProperties} to use when instantiating {@link MavenResource}s
+ */
+ public MavenResourceLoader(MavenProperties properties) {
+ Assert.notNull(properties, "MavenProperties must not be null");
+ this.properties = properties;
+ }
+
+ /**
+ * Returns a {@link MavenResource} for the provided location.
+ *
+ * @param location the coordinates conforming to the rules described on
+ * {@link MavenResource#parse(String)}. May optionally be preceded by {@value #URI_SCHEME}
+ * followed by a colon and zero or more forward slashes, e.g.
+ * {@literal maven://group:artifact:version}
+ * @return the {@link MavenResource}
+ */
+ @Override
+ public Resource getResource(String location) {
+ Assert.hasText(location, "location is required");
+ String coordinates = location.replaceFirst(URI_SCHEME + ":\\/*", "");
+ return MavenResource.parse(coordinates, this.properties);
+ }
+
+ /**
+ * Returns the {@link ClassLoader} for this ResourceLoader.
+ */
+ @Override
+ public ClassLoader getClassLoader() {
+ return this.classLoader;
+ }
+
+}
diff --git a/spring-cloud-function-deployer/src/test/java/org/springframework/cloud/function/deployer/FunctionDeployerTests.java b/spring-cloud-function-deployer/src/test/java/org/springframework/cloud/function/deployer/FunctionDeployerTests.java
index e3317a4d0..daacedc14 100644
--- a/spring-cloud-function-deployer/src/test/java/org/springframework/cloud/function/deployer/FunctionDeployerTests.java
+++ b/spring-cloud-function-deployer/src/test/java/org/springframework/cloud/function/deployer/FunctionDeployerTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2020 the original author or authors.
+ * Copyright 2017-present 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.
@@ -32,9 +32,9 @@
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
-import org.springframework.cloud.deployer.resource.maven.MavenProperties;
import org.springframework.cloud.function.cloudevent.CloudEventMessageBuilder;
import org.springframework.cloud.function.context.FunctionCatalog;
+import org.springframework.cloud.function.deployer.utils.MavenProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.messaging.Message;
diff --git a/spring-cloud-function-integration/pom.xml b/spring-cloud-function-integration/pom.xml
index 41a45d7f2..cb609d396 100644
--- a/spring-cloud-function-integration/pom.xml
+++ b/spring-cloud-function-integration/pom.xml
@@ -12,7 +12,7 @@
spring-cloud-function-parent
org.springframework.cloud
- 4.2.1-SNAPSHOT
+ 4.2.5-SNAPSHOT
diff --git a/spring-cloud-function-integration/src/main/java/org/springframework/cloud/function/integration/dsl/FunctionFlowAutoConfiguration.java b/spring-cloud-function-integration/src/main/java/org/springframework/cloud/function/integration/dsl/FunctionFlowAutoConfiguration.java
index 03d3848ae..dcf90bfbe 100644
--- a/spring-cloud-function-integration/src/main/java/org/springframework/cloud/function/integration/dsl/FunctionFlowAutoConfiguration.java
+++ b/spring-cloud-function-integration/src/main/java/org/springframework/cloud/function/integration/dsl/FunctionFlowAutoConfiguration.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2023-2023 the original author or authors.
+ * Copyright 2023-present 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.
diff --git a/spring-cloud-function-integration/src/main/java/org/springframework/cloud/function/integration/dsl/FunctionFlowBuilder.java b/spring-cloud-function-integration/src/main/java/org/springframework/cloud/function/integration/dsl/FunctionFlowBuilder.java
index 1ad83a440..158780ecf 100644
--- a/spring-cloud-function-integration/src/main/java/org/springframework/cloud/function/integration/dsl/FunctionFlowBuilder.java
+++ b/spring-cloud-function-integration/src/main/java/org/springframework/cloud/function/integration/dsl/FunctionFlowBuilder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2023-2023 the original author or authors.
+ * Copyright 2023-present 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.
diff --git a/spring-cloud-function-integration/src/main/java/org/springframework/cloud/function/integration/dsl/FunctionFlowDefinition.java b/spring-cloud-function-integration/src/main/java/org/springframework/cloud/function/integration/dsl/FunctionFlowDefinition.java
index cc8b84553..833866d68 100644
--- a/spring-cloud-function-integration/src/main/java/org/springframework/cloud/function/integration/dsl/FunctionFlowDefinition.java
+++ b/spring-cloud-function-integration/src/main/java/org/springframework/cloud/function/integration/dsl/FunctionFlowDefinition.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2023-2023 the original author or authors.
+ * Copyright 2023-present 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.
diff --git a/spring-cloud-function-integration/src/main/java/org/springframework/cloud/function/integration/dsl/FunctionLookupHelper.java b/spring-cloud-function-integration/src/main/java/org/springframework/cloud/function/integration/dsl/FunctionLookupHelper.java
index f4a9637b4..94b871b29 100644
--- a/spring-cloud-function-integration/src/main/java/org/springframework/cloud/function/integration/dsl/FunctionLookupHelper.java
+++ b/spring-cloud-function-integration/src/main/java/org/springframework/cloud/function/integration/dsl/FunctionLookupHelper.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2023-2024 the original author or authors.
+ * Copyright 2023-present 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.
diff --git a/spring-cloud-function-integration/src/test/java/org/springframework/cloud/function/integration/dsl/FunctionFlowTests.java b/spring-cloud-function-integration/src/test/java/org/springframework/cloud/function/integration/dsl/FunctionFlowTests.java
index e4ee38a2b..b7a0bce0e 100644
--- a/spring-cloud-function-integration/src/test/java/org/springframework/cloud/function/integration/dsl/FunctionFlowTests.java
+++ b/spring-cloud-function-integration/src/test/java/org/springframework/cloud/function/integration/dsl/FunctionFlowTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2023-2023 the original author or authors.
+ * Copyright 2023-present 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.
diff --git a/spring-cloud-function-kotlin/pom.xml b/spring-cloud-function-kotlin/pom.xml
index e0eff9085..90673a5b7 100644
--- a/spring-cloud-function-kotlin/pom.xml
+++ b/spring-cloud-function-kotlin/pom.xml
@@ -12,7 +12,7 @@
org.springframework.cloud
spring-cloud-function-parent
- 4.2.1-SNAPSHOT
+ 4.2.5-SNAPSHOT
diff --git a/spring-cloud-function-kotlin/src/test/java/org/springframework/cloud/function/kotlin/ContextFunctionCatalogAutoConfigurationKotlinSuspendTests.java b/spring-cloud-function-kotlin/src/test/java/org/springframework/cloud/function/kotlin/ContextFunctionCatalogAutoConfigurationKotlinSuspendTests.java
index 874de12a4..7274f311b 100644
--- a/spring-cloud-function-kotlin/src/test/java/org/springframework/cloud/function/kotlin/ContextFunctionCatalogAutoConfigurationKotlinSuspendTests.java
+++ b/spring-cloud-function-kotlin/src/test/java/org/springframework/cloud/function/kotlin/ContextFunctionCatalogAutoConfigurationKotlinSuspendTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2019-2021 the original author or authors.
+ * Copyright 2019-present 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.
diff --git a/spring-cloud-function-kotlin/src/test/java/org/springframework/cloud/function/kotlin/ContextFunctionCatalogAutoConfigurationKotlinTests.java b/spring-cloud-function-kotlin/src/test/java/org/springframework/cloud/function/kotlin/ContextFunctionCatalogAutoConfigurationKotlinTests.java
index ae28d985d..68b0186df 100644
--- a/spring-cloud-function-kotlin/src/test/java/org/springframework/cloud/function/kotlin/ContextFunctionCatalogAutoConfigurationKotlinTests.java
+++ b/spring-cloud-function-kotlin/src/test/java/org/springframework/cloud/function/kotlin/ContextFunctionCatalogAutoConfigurationKotlinTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2019-2021 the original author or authors.
+ * Copyright 2019-present 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.
diff --git a/spring-cloud-function-kotlin/src/test/java/org/springframework/cloud/function/kotlin/KotlinTypeDiscoveryTests.java b/spring-cloud-function-kotlin/src/test/java/org/springframework/cloud/function/kotlin/KotlinTypeDiscoveryTests.java
new file mode 100644
index 000000000..b384b17b3
--- /dev/null
+++ b/spring-cloud-function-kotlin/src/test/java/org/springframework/cloud/function/kotlin/KotlinTypeDiscoveryTests.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2019-present 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.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.cloud.function.kotlin;
+
+
+
+import java.lang.reflect.Type;
+
+import org.junit.jupiter.api.Test;
+
+import org.springframework.cloud.function.context.catalog.FunctionTypeUtils;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class KotlinTypeDiscoveryTests {
+
+ @Test
+ public void testOutputInputTypes() {
+ Type functionType = FunctionTypeUtils.discoverFunctionTypeFromClass(KotlinComponentMessageFunction.class);
+ Type outputType = FunctionTypeUtils.getOutputType(functionType);
+ assertThat(FunctionTypeUtils.isMessage(outputType)).isTrue();
+
+ Type inputType = FunctionTypeUtils.getInputType(functionType);
+ assertThat(FunctionTypeUtils.isMessage(inputType)).isTrue();
+ }
+}
diff --git a/spring-cloud-function-kotlin/src/test/kotlin/org/springframework/cloud/function/kotlin/KotlinComponentMessageFunction.kt b/spring-cloud-function-kotlin/src/test/kotlin/org/springframework/cloud/function/kotlin/KotlinComponentMessageFunction.kt
new file mode 100644
index 000000000..7f04cc57c
--- /dev/null
+++ b/spring-cloud-function-kotlin/src/test/kotlin/org/springframework/cloud/function/kotlin/KotlinComponentMessageFunction.kt
@@ -0,0 +1,15 @@
+package org.springframework.cloud.function.kotlin
+
+import org.springframework.messaging.Message
+import org.springframework.messaging.MessageHeaders
+import org.springframework.messaging.support.MessageBuilder
+import org.springframework.stereotype.Component
+
+import java.util.function.Function
+
+@Component
+class KotlinComponentMessageFunction : (List>) -> List> {
+ override fun invoke(input: List>): List> {
+ return input
+ }
+}
diff --git a/spring-cloud-function-kotlin/src/test/kotlin/org/springframework/cloud/function/kotlin/KotlinLambdasConfiguration.kt b/spring-cloud-function-kotlin/src/test/kotlin/org/springframework/cloud/function/kotlin/KotlinLambdasConfiguration.kt
index a324131fc..97c96e519 100644
--- a/spring-cloud-function-kotlin/src/test/kotlin/org/springframework/cloud/function/kotlin/KotlinLambdasConfiguration.kt
+++ b/spring-cloud-function-kotlin/src/test/kotlin/org/springframework/cloud/function/kotlin/KotlinLambdasConfiguration.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2020-2021 the original author or authors.
+ * Copyright 2020-present 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.
diff --git a/spring-cloud-function-kotlin/src/test/kotlin/org/springframework/cloud/function/kotlin/KotlinSuspendFlowLambdasConfiguration.kt b/spring-cloud-function-kotlin/src/test/kotlin/org/springframework/cloud/function/kotlin/KotlinSuspendFlowLambdasConfiguration.kt
index bfa7e3102..20af8ce6b 100644
--- a/spring-cloud-function-kotlin/src/test/kotlin/org/springframework/cloud/function/kotlin/KotlinSuspendFlowLambdasConfiguration.kt
+++ b/spring-cloud-function-kotlin/src/test/kotlin/org/springframework/cloud/function/kotlin/KotlinSuspendFlowLambdasConfiguration.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2021-2021 the original author or authors.
+ * Copyright 2021-present 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.
diff --git a/spring-cloud-function-kotlin/src/test/kotlin/org/springframework/cloud/function/kotlin/KotlinSuspendLambdasConfiguration.kt b/spring-cloud-function-kotlin/src/test/kotlin/org/springframework/cloud/function/kotlin/KotlinSuspendLambdasConfiguration.kt
index 68e985550..d9a4aef2c 100644
--- a/spring-cloud-function-kotlin/src/test/kotlin/org/springframework/cloud/function/kotlin/KotlinSuspendLambdasConfiguration.kt
+++ b/spring-cloud-function-kotlin/src/test/kotlin/org/springframework/cloud/function/kotlin/KotlinSuspendLambdasConfiguration.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2021-2021 the original author or authors.
+ * Copyright 2021-present 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.
diff --git a/spring-cloud-function-kotlin/src/test/kotlin/org/springframework/cloud/function/kotlin/Person.kt b/spring-cloud-function-kotlin/src/test/kotlin/org/springframework/cloud/function/kotlin/Person.kt
index f46fb3278..fd27360d5 100644
--- a/spring-cloud-function-kotlin/src/test/kotlin/org/springframework/cloud/function/kotlin/Person.kt
+++ b/spring-cloud-function-kotlin/src/test/kotlin/org/springframework/cloud/function/kotlin/Person.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2020-2021 the original author or authors.
+ * Copyright 2020-present 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.
diff --git a/spring-cloud-function-kotlin/src/test/kotlin/org/springframework/cloud/function/kotlin/aws/AwsKotlinTestsTests.kt b/spring-cloud-function-kotlin/src/test/kotlin/org/springframework/cloud/function/kotlin/aws/AwsKotlinTestsTests.kt
index 36eafbbe3..d33f3f3ee 100644
--- a/spring-cloud-function-kotlin/src/test/kotlin/org/springframework/cloud/function/kotlin/aws/AwsKotlinTestsTests.kt
+++ b/spring-cloud-function-kotlin/src/test/kotlin/org/springframework/cloud/function/kotlin/aws/AwsKotlinTestsTests.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2020-2021 the original author or authors.
+ * Copyright 2020-present 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.
diff --git a/spring-cloud-function-kotlin/src/test/kotlin/org/springframework/cloud/function/kotlin/aws/KotlinAwsLambdasConfiguration.kt b/spring-cloud-function-kotlin/src/test/kotlin/org/springframework/cloud/function/kotlin/aws/KotlinAwsLambdasConfiguration.kt
index 315c1b63a..fe17f2fff 100644
--- a/spring-cloud-function-kotlin/src/test/kotlin/org/springframework/cloud/function/kotlin/aws/KotlinAwsLambdasConfiguration.kt
+++ b/spring-cloud-function-kotlin/src/test/kotlin/org/springframework/cloud/function/kotlin/aws/KotlinAwsLambdasConfiguration.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2021-2021 the original author or authors.
+ * Copyright 2021-present 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.
diff --git a/spring-cloud-function-kotlin/src/test/kotlin/org/springframework/cloud/function/kotlin/web/HeadersToMessageSuspendTests.kt b/spring-cloud-function-kotlin/src/test/kotlin/org/springframework/cloud/function/kotlin/web/HeadersToMessageSuspendTests.kt
index 85ad7f68f..0ecf182e0 100644
--- a/spring-cloud-function-kotlin/src/test/kotlin/org/springframework/cloud/function/kotlin/web/HeadersToMessageSuspendTests.kt
+++ b/spring-cloud-function-kotlin/src/test/kotlin/org/springframework/cloud/function/kotlin/web/HeadersToMessageSuspendTests.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2021-2021 the original author or authors.
+ * Copyright 2021-present 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.
diff --git a/spring-cloud-function-kotlin/src/test/kotlin/org/springframework/cloud/function/kotlin/web/HeadersToMessageTests.kt b/spring-cloud-function-kotlin/src/test/kotlin/org/springframework/cloud/function/kotlin/web/HeadersToMessageTests.kt
index 02f1c170d..ec7b80e8c 100644
--- a/spring-cloud-function-kotlin/src/test/kotlin/org/springframework/cloud/function/kotlin/web/HeadersToMessageTests.kt
+++ b/spring-cloud-function-kotlin/src/test/kotlin/org/springframework/cloud/function/kotlin/web/HeadersToMessageTests.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2020-2021 the original author or authors.
+ * Copyright 2020-present 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.
diff --git a/spring-cloud-function-rsocket/pom.xml b/spring-cloud-function-rsocket/pom.xml
index 2b22bfbc0..7dbfde09f 100644
--- a/spring-cloud-function-rsocket/pom.xml
+++ b/spring-cloud-function-rsocket/pom.xml
@@ -12,7 +12,7 @@
org.springframework.cloud
spring-cloud-function-parent
- 4.2.1-SNAPSHOT
+ 4.2.5-SNAPSHOT
diff --git a/spring-cloud-function-rsocket/src/main/java/org/springframework/cloud/function/rsocket/FunctionRSocketMessageHandler.java b/spring-cloud-function-rsocket/src/main/java/org/springframework/cloud/function/rsocket/FunctionRSocketMessageHandler.java
index a61e006f0..c2d670bb1 100644
--- a/spring-cloud-function-rsocket/src/main/java/org/springframework/cloud/function/rsocket/FunctionRSocketMessageHandler.java
+++ b/spring-cloud-function-rsocket/src/main/java/org/springframework/cloud/function/rsocket/FunctionRSocketMessageHandler.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2020-2021 the original author or authors.
+ * Copyright 2020-present 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.
diff --git a/spring-cloud-function-rsocket/src/main/java/org/springframework/cloud/function/rsocket/FunctionRSocketUtils.java b/spring-cloud-function-rsocket/src/main/java/org/springframework/cloud/function/rsocket/FunctionRSocketUtils.java
index a46e482f4..be16954ae 100644
--- a/spring-cloud-function-rsocket/src/main/java/org/springframework/cloud/function/rsocket/FunctionRSocketUtils.java
+++ b/spring-cloud-function-rsocket/src/main/java/org/springframework/cloud/function/rsocket/FunctionRSocketUtils.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2020-2021 the original author or authors.
+ * Copyright 2020-present 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.
diff --git a/spring-cloud-function-rsocket/src/main/java/org/springframework/cloud/function/rsocket/MessageAwareJsonDecoder.java b/spring-cloud-function-rsocket/src/main/java/org/springframework/cloud/function/rsocket/MessageAwareJsonDecoder.java
index 1398d3958..99ac44e6f 100644
--- a/spring-cloud-function-rsocket/src/main/java/org/springframework/cloud/function/rsocket/MessageAwareJsonDecoder.java
+++ b/spring-cloud-function-rsocket/src/main/java/org/springframework/cloud/function/rsocket/MessageAwareJsonDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2021-2021 the original author or authors.
+ * Copyright 2021-present 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.
diff --git a/spring-cloud-function-rsocket/src/main/java/org/springframework/cloud/function/rsocket/MessageAwareJsonEncoder.java b/spring-cloud-function-rsocket/src/main/java/org/springframework/cloud/function/rsocket/MessageAwareJsonEncoder.java
index 02aa41045..ec27d2c96 100644
--- a/spring-cloud-function-rsocket/src/main/java/org/springframework/cloud/function/rsocket/MessageAwareJsonEncoder.java
+++ b/spring-cloud-function-rsocket/src/main/java/org/springframework/cloud/function/rsocket/MessageAwareJsonEncoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2021-2021 the original author or authors.
+ * Copyright 2021-present 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.
diff --git a/spring-cloud-function-rsocket/src/main/java/org/springframework/cloud/function/rsocket/RSocketAutoConfiguration.java b/spring-cloud-function-rsocket/src/main/java/org/springframework/cloud/function/rsocket/RSocketAutoConfiguration.java
index e7cc2b28a..991172a2f 100644
--- a/spring-cloud-function-rsocket/src/main/java/org/springframework/cloud/function/rsocket/RSocketAutoConfiguration.java
+++ b/spring-cloud-function-rsocket/src/main/java/org/springframework/cloud/function/rsocket/RSocketAutoConfiguration.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2020-2021 the original author or authors.
+ * Copyright 2020-present 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.
diff --git a/spring-cloud-function-rsocket/src/main/java/org/springframework/cloud/function/rsocket/RSocketCustomizerConfiguration.java b/spring-cloud-function-rsocket/src/main/java/org/springframework/cloud/function/rsocket/RSocketCustomizerConfiguration.java
index 82628e186..a12971db9 100644
--- a/spring-cloud-function-rsocket/src/main/java/org/springframework/cloud/function/rsocket/RSocketCustomizerConfiguration.java
+++ b/spring-cloud-function-rsocket/src/main/java/org/springframework/cloud/function/rsocket/RSocketCustomizerConfiguration.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2021-2021 the original author or authors.
+ * Copyright 2021-present 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.
diff --git a/spring-cloud-function-rsocket/src/main/java/org/springframework/cloud/function/rsocket/RSocketForwardingFunction.java b/spring-cloud-function-rsocket/src/main/java/org/springframework/cloud/function/rsocket/RSocketForwardingFunction.java
index 8da7e76e4..40496c074 100644
--- a/spring-cloud-function-rsocket/src/main/java/org/springframework/cloud/function/rsocket/RSocketForwardingFunction.java
+++ b/spring-cloud-function-rsocket/src/main/java/org/springframework/cloud/function/rsocket/RSocketForwardingFunction.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2020-2020 the original author or authors.
+ * Copyright 2020-present 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.
diff --git a/spring-cloud-function-rsocket/src/main/java/org/springframework/cloud/function/rsocket/RSocketFunctionProperties.java b/spring-cloud-function-rsocket/src/main/java/org/springframework/cloud/function/rsocket/RSocketFunctionProperties.java
index f6c137ccc..f365ae4b2 100644
--- a/spring-cloud-function-rsocket/src/main/java/org/springframework/cloud/function/rsocket/RSocketFunctionProperties.java
+++ b/spring-cloud-function-rsocket/src/main/java/org/springframework/cloud/function/rsocket/RSocketFunctionProperties.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2020-2020 the original author or authors.
+ * Copyright 2020-present 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.
diff --git a/spring-cloud-function-rsocket/src/main/java/org/springframework/cloud/function/rsocket/RSocketListenerFunction.java b/spring-cloud-function-rsocket/src/main/java/org/springframework/cloud/function/rsocket/RSocketListenerFunction.java
index 53f81e688..9811d53f6 100644
--- a/spring-cloud-function-rsocket/src/main/java/org/springframework/cloud/function/rsocket/RSocketListenerFunction.java
+++ b/spring-cloud-function-rsocket/src/main/java/org/springframework/cloud/function/rsocket/RSocketListenerFunction.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2020-2021 the original author or authors.
+ * Copyright 2020-present 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.
diff --git a/spring-cloud-function-rsocket/src/main/java/org/springframework/cloud/function/rsocket/RSocketRoutingAutoConfiguration.java b/spring-cloud-function-rsocket/src/main/java/org/springframework/cloud/function/rsocket/RSocketRoutingAutoConfiguration.java
index abf37dbd2..1a358ae92 100644
--- a/spring-cloud-function-rsocket/src/main/java/org/springframework/cloud/function/rsocket/RSocketRoutingAutoConfiguration.java
+++ b/spring-cloud-function-rsocket/src/main/java/org/springframework/cloud/function/rsocket/RSocketRoutingAutoConfiguration.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2020-2021 the original author or authors.
+ * Copyright 2020-present 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.
diff --git a/spring-cloud-function-rsocket/src/test/java/org/springframework/cloud/function/rsocket/MessageRoutingCallbackRSocketTests.java b/spring-cloud-function-rsocket/src/test/java/org/springframework/cloud/function/rsocket/MessageRoutingCallbackRSocketTests.java
index fcf26adb9..98eeb41fe 100644
--- a/spring-cloud-function-rsocket/src/test/java/org/springframework/cloud/function/rsocket/MessageRoutingCallbackRSocketTests.java
+++ b/spring-cloud-function-rsocket/src/test/java/org/springframework/cloud/function/rsocket/MessageRoutingCallbackRSocketTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2021-2022 the original author or authors.
+ * Copyright 2021-present 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.
diff --git a/spring-cloud-function-rsocket/src/test/java/org/springframework/cloud/function/rsocket/MessagingTests.java b/spring-cloud-function-rsocket/src/test/java/org/springframework/cloud/function/rsocket/MessagingTests.java
index 726ae7a7a..2e18546b4 100644
--- a/spring-cloud-function-rsocket/src/test/java/org/springframework/cloud/function/rsocket/MessagingTests.java
+++ b/spring-cloud-function-rsocket/src/test/java/org/springframework/cloud/function/rsocket/MessagingTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2021-2022 the original author or authors.
+ * Copyright 2021-present 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.
diff --git a/spring-cloud-function-rsocket/src/test/java/org/springframework/cloud/function/rsocket/RSocketAutoConfigurationRoutingTests.java b/spring-cloud-function-rsocket/src/test/java/org/springframework/cloud/function/rsocket/RSocketAutoConfigurationRoutingTests.java
index 0afa56200..fd3dfc49b 100644
--- a/spring-cloud-function-rsocket/src/test/java/org/springframework/cloud/function/rsocket/RSocketAutoConfigurationRoutingTests.java
+++ b/spring-cloud-function-rsocket/src/test/java/org/springframework/cloud/function/rsocket/RSocketAutoConfigurationRoutingTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2021-2022 the original author or authors.
+ * Copyright 2021-present 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.
diff --git a/spring-cloud-function-rsocket/src/test/java/org/springframework/cloud/function/rsocket/RSocketAutoConfigurationTests.java b/spring-cloud-function-rsocket/src/test/java/org/springframework/cloud/function/rsocket/RSocketAutoConfigurationTests.java
index 05dc9b43e..cc295f143 100644
--- a/spring-cloud-function-rsocket/src/test/java/org/springframework/cloud/function/rsocket/RSocketAutoConfigurationTests.java
+++ b/spring-cloud-function-rsocket/src/test/java/org/springframework/cloud/function/rsocket/RSocketAutoConfigurationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2020-2022 the original author or authors.
+ * Copyright 2020-present 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.
diff --git a/spring-cloud-function-rsocket/src/test/java/org/springframework/cloud/function/rsocket/RoutingBrokerTests.java b/spring-cloud-function-rsocket/src/test/java/org/springframework/cloud/function/rsocket/RoutingBrokerTests.java
index 3b6005681..5ae1e0dab 100644
--- a/spring-cloud-function-rsocket/src/test/java/org/springframework/cloud/function/rsocket/RoutingBrokerTests.java
+++ b/spring-cloud-function-rsocket/src/test/java/org/springframework/cloud/function/rsocket/RoutingBrokerTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2020-2020 the original author or authors.
+ * Copyright 2020-present 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.
diff --git a/spring-cloud-function-samples/function-functional-sample-aws/pom.xml b/spring-cloud-function-samples/function-functional-sample-aws/pom.xml
index fe39d0911..0a941c9fb 100644
--- a/spring-cloud-function-samples/function-functional-sample-aws/pom.xml
+++ b/spring-cloud-function-samples/function-functional-sample-aws/pom.xml
@@ -15,7 +15,7 @@
org.springframework.boot
spring-boot-starter-parent
- 3.4.0
+ 3.4.13
@@ -24,7 +24,7 @@
UTF-8
1.0.27.RELEASE
3.9.0
- 4.2.1-SNAPSHOT
+ 4.2.5-SNAPSHOT
diff --git a/spring-cloud-function-samples/function-functional-sample-aws/src/test/java/example/MapTests.java b/spring-cloud-function-samples/function-functional-sample-aws/src/test/java/example/MapTests.java
index 289a8c9ff..bcd3660cd 100644
--- a/spring-cloud-function-samples/function-functional-sample-aws/src/test/java/example/MapTests.java
+++ b/spring-cloud-function-samples/function-functional-sample-aws/src/test/java/example/MapTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2019 the original author or authors.
+ * Copyright 2012-present 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.
diff --git a/spring-cloud-function-samples/function-sample-aws-custom-bean/pom.xml b/spring-cloud-function-samples/function-sample-aws-custom-bean/pom.xml
index 540855b20..738b2f392 100644
--- a/spring-cloud-function-samples/function-sample-aws-custom-bean/pom.xml
+++ b/spring-cloud-function-samples/function-sample-aws-custom-bean/pom.xml
@@ -5,7 +5,7 @@
org.springframework.boot
spring-boot-starter-parent
- 3.4.0
+ 3.4.13
io.spring.sample
@@ -16,7 +16,7 @@
1.0.27.RELEASE
- 4.2.1-SNAPSHOT
+ 4.2.5-SNAPSHOT
diff --git a/spring-cloud-function-samples/function-sample-aws-custom/pom.xml b/spring-cloud-function-samples/function-sample-aws-custom/pom.xml
index 698923bb9..0860aed66 100644
--- a/spring-cloud-function-samples/function-sample-aws-custom/pom.xml
+++ b/spring-cloud-function-samples/function-sample-aws-custom/pom.xml
@@ -5,7 +5,7 @@
org.springframework.boot
spring-boot-starter-parent
- 3.4.0
+ 3.4.13
io.spring.sample
@@ -16,7 +16,7 @@
1.0.27.RELEASE
- 4.2.1-SNAPSHOT
+ 4.2.5-SNAPSHOT
diff --git a/spring-cloud-function-samples/function-sample-aws-custom/src/test/java/com/example/LambdaApplicationTests.java b/spring-cloud-function-samples/function-sample-aws-custom/src/test/java/com/example/LambdaApplicationTests.java
index b7e560f00..55eeec2ca 100644
--- a/spring-cloud-function-samples/function-sample-aws-custom/src/test/java/com/example/LambdaApplicationTests.java
+++ b/spring-cloud-function-samples/function-sample-aws-custom/src/test/java/com/example/LambdaApplicationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2019-2019 the original author or authors.
+ * Copyright 2019-present 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.
diff --git a/spring-cloud-function-samples/function-sample-aws-native/pom.xml b/spring-cloud-function-samples/function-sample-aws-native/pom.xml
index 3b94f9154..89652a44d 100644
--- a/spring-cloud-function-samples/function-sample-aws-native/pom.xml
+++ b/spring-cloud-function-samples/function-sample-aws-native/pom.xml
@@ -5,7 +5,7 @@
org.springframework.boot
spring-boot-starter-parent
- 3.4.0
+ 3.4.13
oz.native.sample
@@ -15,7 +15,7 @@
Sample of AWS with Spring Native
19
- 2024.0.1-SNAPSHOT
+ 2024.0.4-SNAPSHOT
diff --git a/spring-cloud-function-samples/function-sample-aws-routing/pom.xml b/spring-cloud-function-samples/function-sample-aws-routing/pom.xml
index aa9c0fd5e..ba491ae1b 100644
--- a/spring-cloud-function-samples/function-sample-aws-routing/pom.xml
+++ b/spring-cloud-function-samples/function-sample-aws-routing/pom.xml
@@ -15,7 +15,7 @@
org.springframework.boot
spring-boot-starter-parent
- 3.4.0
+ 3.4.13
@@ -24,7 +24,7 @@
UTF-8
1.0.27.RELEASE
2.0.2
- 4.2.1-SNAPSHOT
+ 4.2.5-SNAPSHOT