Browse Source

Polish

pull/44012/head
Phillip Webb 1 year ago
parent
commit
7545bed284
  1. 5
      spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/JvmMetricsAutoConfiguration.java
  2. 113
      spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/PropertiesRedisConnectionDetails.java
  3. 92
      spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/RedisConnectionConfiguration.java
  4. 98
      spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/RedisUrl.java
  5. 34
      spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jooq/JooqAutoConfiguration.java

5
spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/JvmMetricsAutoConfiguration.java

@ -100,8 +100,9 @@ public class JvmMetricsAutoConfiguration { @@ -100,8 +100,9 @@ public class JvmMetricsAutoConfiguration {
@ConditionalOnMissingBean(type = VIRTUAL_THREAD_METRICS_CLASS)
@ImportRuntimeHints(VirtualThreadMetricsRuntimeHintsRegistrar.class)
MeterBinder virtualThreadMetrics() throws ClassNotFoundException {
Class<?> clazz = ClassUtils.forName(VIRTUAL_THREAD_METRICS_CLASS, getClass().getClassLoader());
return (MeterBinder) BeanUtils.instantiateClass(clazz);
Class<?> virtualThreadMetricsClass = ClassUtils.forName(VIRTUAL_THREAD_METRICS_CLASS,
getClass().getClassLoader());
return (MeterBinder) BeanUtils.instantiateClass(virtualThreadMetricsClass);
}
static final class VirtualThreadMetricsRuntimeHintsRegistrar implements RuntimeHintsRegistrar {

113
spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/PropertiesRedisConnectionDetails.java

@ -18,8 +18,6 @@ package org.springframework.boot.autoconfigure.data.redis; @@ -18,8 +18,6 @@ package org.springframework.boot.autoconfigure.data.redis;
import java.util.List;
import org.springframework.boot.autoconfigure.data.redis.RedisConnectionConfiguration.ConnectionInfo;
/**
* Adapts {@link RedisProperties} to {@link RedisConnectionDetails}.
*
@ -28,6 +26,7 @@ import org.springframework.boot.autoconfigure.data.redis.RedisConnectionConfigur @@ -28,6 +26,7 @@ import org.springframework.boot.autoconfigure.data.redis.RedisConnectionConfigur
* @author Phillip Webb
* @author Scott Frederick
* @author Yanming Zhou
* @author Phillip Webb
*/
class PropertiesRedisConnectionDetails implements RedisConnectionDetails {
@ -39,76 +38,45 @@ class PropertiesRedisConnectionDetails implements RedisConnectionDetails { @@ -39,76 +38,45 @@ class PropertiesRedisConnectionDetails implements RedisConnectionDetails {
@Override
public String getUsername() {
if (this.properties.getUrl() != null) {
ConnectionInfo connectionInfo = ConnectionInfo.of(this.properties.getUrl());
return connectionInfo.getUsername();
}
return this.properties.getUsername();
RedisUrl redisUrl = getRedisUrl();
return (redisUrl != null) ? redisUrl.credentials().username() : this.properties.getUsername();
}
@Override
public String getPassword() {
if (this.properties.getUrl() != null) {
ConnectionInfo connectionInfo = ConnectionInfo.of(this.properties.getUrl());
return connectionInfo.getPassword();
}
return this.properties.getPassword();
RedisUrl redisUrl = getRedisUrl();
return (redisUrl != null) ? redisUrl.credentials().password() : this.properties.getPassword();
}
@Override
public Standalone getStandalone() {
if (this.properties.getUrl() != null) {
ConnectionInfo connectionInfo = ConnectionInfo.of(this.properties.getUrl());
return Standalone.of(connectionInfo.getUri().getHost(), connectionInfo.getUri().getPort(),
connectionInfo.getDatabase());
}
return Standalone.of(this.properties.getHost(), this.properties.getPort(), this.properties.getDatabase());
RedisUrl redisUrl = getRedisUrl();
return (redisUrl != null)
? Standalone.of(redisUrl.uri().getHost(), redisUrl.uri().getPort(), redisUrl.database())
: Standalone.of(this.properties.getHost(), this.properties.getPort(), this.properties.getDatabase());
}
@Override
public Sentinel getSentinel() {
org.springframework.boot.autoconfigure.data.redis.RedisProperties.Sentinel sentinel = this.properties
.getSentinel();
if (sentinel == null) {
return null;
}
return new Sentinel() {
@Override
public int getDatabase() {
return getStandalone().getDatabase();
}
@Override
public String getMaster() {
return sentinel.getMaster();
}
@Override
public List<Node> getNodes() {
return sentinel.getNodes().stream().map(PropertiesRedisConnectionDetails.this::asNode).toList();
}
@Override
public String getUsername() {
return sentinel.getUsername();
}
@Override
public String getPassword() {
return sentinel.getPassword();
}
};
RedisProperties.Sentinel sentinel = this.properties.getSentinel();
return (sentinel != null) ? new PropertiesSentinel(getStandalone().getDatabase(), sentinel) : null;
}
@Override
public Cluster getCluster() {
RedisProperties.Cluster cluster = this.properties.getCluster();
List<Node> nodes = (cluster != null) ? cluster.getNodes().stream().map(this::asNode).toList() : null;
List<Node> nodes = (cluster != null) ? asNodes(cluster.getNodes()) : null;
return (nodes != null) ? () -> nodes : null;
}
private RedisUrl getRedisUrl() {
return RedisUrl.of(this.properties.getUrl());
}
private List<Node> asNodes(List<String> nodes) {
return nodes.stream().map(this::asNode).toList();
}
private Node asNode(String node) {
int portSeparatorIndex = node.lastIndexOf(':');
String host = node.substring(0, portSeparatorIndex);
@ -116,4 +84,45 @@ class PropertiesRedisConnectionDetails implements RedisConnectionDetails { @@ -116,4 +84,45 @@ class PropertiesRedisConnectionDetails implements RedisConnectionDetails {
return new Node(host, port);
}
/**
* {@link Sentinel} implementation backed by properties.
*/
private class PropertiesSentinel implements Sentinel {
private final int database;
private final RedisProperties.Sentinel properties;
PropertiesSentinel(int database, RedisProperties.Sentinel properties) {
this.database = database;
this.properties = properties;
}
@Override
public int getDatabase() {
return this.database;
}
@Override
public String getMaster() {
return this.properties.getMaster();
}
@Override
public List<Node> getNodes() {
return asNodes(this.properties.getNodes());
}
@Override
public String getUsername() {
return this.properties.getUsername();
}
@Override
public String getPassword() {
return this.properties.getPassword();
}
}
}

92
spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/RedisConnectionConfiguration.java

@ -16,8 +16,6 @@ @@ -16,8 +16,6 @@
package org.springframework.boot.autoconfigure.data.redis;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;
@ -33,7 +31,6 @@ import org.springframework.data.redis.connection.RedisPassword; @@ -33,7 +31,6 @@ import org.springframework.data.redis.connection.RedisPassword;
import org.springframework.data.redis.connection.RedisSentinelConfiguration;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
/**
* Base Redis connection configuration.
@ -152,14 +149,18 @@ abstract class RedisConnectionConfiguration { @@ -152,14 +149,18 @@ abstract class RedisConnectionConfiguration {
return this.properties;
}
protected SslBundles getSslBundles() {
protected final SslBundles getSslBundles() {
return this.sslBundles;
}
protected boolean isSslEnabled() {
protected final boolean isSslEnabled() {
return getProperties().getSsl().isEnabled();
}
protected final boolean urlUsesSsl() {
return RedisUrl.of(this.properties.getUrl()).useSsl();
}
protected boolean isPoolEnabled(Pool pool) {
Boolean enabled = pool.getEnabled();
return (enabled != null) ? enabled : COMMONS_POOL2_AVAILABLE;
@ -173,89 +174,8 @@ abstract class RedisConnectionConfiguration { @@ -173,89 +174,8 @@ abstract class RedisConnectionConfiguration {
return nodes;
}
protected final boolean urlUsesSsl() {
return ConnectionInfo.of(this.properties.getUrl()).isUseSsl();
}
protected final RedisConnectionDetails getConnectionDetails() {
return this.connectionDetails;
}
static final class ConnectionInfo {
private final URI uri;
private final boolean useSsl;
private final String username;
private final String password;
private final int database;
private ConnectionInfo(URI uri, boolean useSsl, String username, String password, int database) {
this.uri = uri;
this.useSsl = useSsl;
this.username = username;
this.password = password;
this.database = database;
}
URI getUri() {
return this.uri;
}
boolean isUseSsl() {
return this.useSsl;
}
String getUsername() {
return this.username;
}
String getPassword() {
return this.password;
}
int getDatabase() {
return this.database;
}
static ConnectionInfo of(String url) {
try {
URI uri = new URI(url);
String scheme = uri.getScheme();
if (!"redis".equals(scheme) && !"rediss".equals(scheme)) {
throw new RedisUrlSyntaxException(url);
}
boolean useSsl = ("rediss".equals(scheme));
String username = null;
String password = null;
if (uri.getUserInfo() != null) {
String candidate = uri.getUserInfo();
int index = candidate.indexOf(':');
if (index >= 0) {
username = candidate.substring(0, index);
password = candidate.substring(index + 1);
}
else {
password = candidate;
}
}
int database = 0;
if (StringUtils.hasText(uri.getPath())) {
String[] pathSplit = uri.getPath().split("/", 2);
if (pathSplit.length > 1 && !pathSplit[1].isEmpty()) {
database = Integer.parseInt(pathSplit[1]);
}
}
return new ConnectionInfo(uri, useSsl, username, password, database);
}
catch (URISyntaxException ex) {
throw new RedisUrlSyntaxException(url, ex);
}
}
}
}

98
spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/RedisUrl.java

@ -0,0 +1,98 @@ @@ -0,0 +1,98 @@
/*
* Copyright 2012-2025 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.boot.autoconfigure.data.redis;
import java.net.URI;
import java.net.URISyntaxException;
import org.springframework.util.StringUtils;
/**
* A parsed URL used to connect to Redis.
*
* @param uri the source URI
* @param useSsl if SSL is used to connect
* @param credentials the connection credentials
* @param database the database index
* @author Mark Paluch
* @author Stephane Nicoll
* @author Alen Turkovic
* @author Scott Frederick
* @author Eddú Meléndez
* @author Moritz Halbritter
* @author Andy Wilkinson
* @author Phillip Webb
* @author Yanming Zhou
* @author Phillip Webb
*/
record RedisUrl(URI uri, boolean useSsl, Credentials credentials, int database) {
static RedisUrl of(String url) {
return (url != null) ? of(toUri(url)) : null;
}
private static RedisUrl of(URI uri) {
boolean useSsl = ("rediss".equals(uri.getScheme()));
Credentials credentials = Credentials.fromUserInfo(uri.getUserInfo());
int database = getDatabase(uri);
return new RedisUrl(uri, useSsl, credentials, database);
}
private static int getDatabase(URI uri) {
String path = uri.getPath();
String[] split = (!StringUtils.hasText(path)) ? new String[0] : path.split("/", 2);
return (split.length > 1 && !split[1].isEmpty()) ? Integer.parseInt(split[1]) : 0;
}
private static URI toUri(String url) {
try {
URI uri = new URI(url);
String scheme = uri.getScheme();
if (!"redis".equals(scheme) && !"rediss".equals(scheme)) {
throw new RedisUrlSyntaxException(url);
}
return uri;
}
catch (URISyntaxException ex) {
throw new RedisUrlSyntaxException(url, ex);
}
}
/**
* Redis connection credentials.
*
* @param username the username or {@code null}
* @param password the password
*/
record Credentials(String username, String password) {
private static final Credentials NONE = new Credentials(null, null);
private static Credentials fromUserInfo(String userInfo) {
if (userInfo == null) {
return NONE;
}
int index = userInfo.indexOf(':');
if (index != -1) {
return new Credentials(userInfo.substring(0, index), userInfo.substring(index + 1));
}
return new Credentials(null, userInfo);
}
}
}

34
spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jooq/JooqAutoConfiguration.java

@ -22,13 +22,13 @@ import java.io.InputStream; @@ -22,13 +22,13 @@ import java.io.InputStream;
import javax.sql.DataSource;
import javax.xml.XMLConstants;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.transform.Source;
import javax.xml.transform.sax.SAXSource;
import jakarta.xml.bind.JAXBContext;
import jakarta.xml.bind.JAXBException;
import jakarta.xml.bind.Unmarshaller;
import org.jooq.ConnectionProvider;
import org.jooq.DSLContext;
import org.jooq.ExecuteListenerProvider;
@ -40,6 +40,8 @@ import org.jooq.impl.DefaultDSLContext; @@ -40,6 +40,8 @@ import org.jooq.impl.DefaultDSLContext;
import org.jooq.impl.DefaultExecuteListenerProvider;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXNotRecognizedException;
import org.xml.sax.SAXNotSupportedException;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfiguration;
@ -138,27 +140,35 @@ public class JooqAutoConfiguration { @@ -138,27 +140,35 @@ public class JooqAutoConfiguration {
}
}
/**
* Load {@link Settings} with <a href=
* "https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html#jaxb-unmarshaller">
* XML External Entity Prevention</a>.
*/
private static final class JaxbSettingsLoader {
private Settings load(InputStream inputStream) {
try {
// See
// https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html#jaxb-unmarshaller
SAXParserFactory spf = SAXParserFactory.newInstance();
spf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
spf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
spf.setNamespaceAware(true);
spf.setXIncludeAware(false);
Source xmlSource = new SAXSource(spf.newSAXParser().getXMLReader(), new InputSource(inputStream));
JAXBContext jc = JAXBContext.newInstance(Settings.class);
Unmarshaller um = jc.createUnmarshaller();
return um.unmarshal(xmlSource, Settings.class).getValue();
SAXParser parser = createParserFactory().newSAXParser();
Source source = new SAXSource(parser.getXMLReader(), new InputSource(inputStream));
JAXBContext context = JAXBContext.newInstance(Settings.class);
return context.createUnmarshaller().unmarshal(source, Settings.class).getValue();
}
catch (ParserConfigurationException | JAXBException | SAXException ex) {
throw new IllegalStateException("Failed to unmarshal settings", ex);
}
}
private SAXParserFactory createParserFactory()
throws ParserConfigurationException, SAXNotRecognizedException, SAXNotSupportedException {
SAXParserFactory factory = SAXParserFactory.newInstance();
factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
factory.setNamespaceAware(true);
factory.setXIncludeAware(false);
return factory;
}
}
}

Loading…
Cancel
Save