Detect default enum value in configuration metadata
Closes gh-7562
This commit is contained in:
@@ -30,14 +30,6 @@
|
||||
"description": "Whether to enable default metrics exporters.",
|
||||
"defaultValue": true
|
||||
},
|
||||
{
|
||||
"name": "management.endpoint.configprops.show-values",
|
||||
"defaultValue": "never"
|
||||
},
|
||||
{
|
||||
"name": "management.endpoint.env.show-values",
|
||||
"defaultValue": "never"
|
||||
},
|
||||
{
|
||||
"name": "management.endpoint.health.probes.add-additional-paths",
|
||||
"type": "java.lang.Boolean",
|
||||
@@ -50,10 +42,6 @@
|
||||
"description": "Whether to enable liveness and readiness probes.",
|
||||
"defaultValue": false
|
||||
},
|
||||
{
|
||||
"name": "management.endpoint.health.show-details",
|
||||
"defaultValue": "never"
|
||||
},
|
||||
{
|
||||
"name": "management.endpoint.health.status.order",
|
||||
"defaultValue": [
|
||||
@@ -69,10 +57,6 @@
|
||||
"description": "Whether to validate health group membership on startup. Validation fails if a group includes or excludes a health contributor that does not exist.",
|
||||
"defaultValue": true
|
||||
},
|
||||
{
|
||||
"name": "management.endpoint.quartz.show-values",
|
||||
"defaultValue": "never"
|
||||
},
|
||||
{
|
||||
"name": "management.endpoints.enabled-by-default",
|
||||
"type": "java.lang.Boolean",
|
||||
@@ -107,26 +91,6 @@
|
||||
"health"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "management.ganglia.metrics.export.addressing-mode",
|
||||
"defaultValue": "multicast"
|
||||
},
|
||||
{
|
||||
"name": "management.ganglia.metrics.export.duration-units",
|
||||
"defaultValue": "milliseconds"
|
||||
},
|
||||
{
|
||||
"name": "management.graphite.metrics.export.duration-units",
|
||||
"defaultValue": "milliseconds"
|
||||
},
|
||||
{
|
||||
"name": "management.graphite.metrics.export.protocol",
|
||||
"defaultValue": "pickled"
|
||||
},
|
||||
{
|
||||
"name": "management.graphite.metrics.export.rate-units",
|
||||
"defaultValue": "seconds"
|
||||
},
|
||||
{
|
||||
"name": "management.health.cassandra.enabled",
|
||||
"type": "java.lang.Boolean",
|
||||
@@ -277,10 +241,6 @@
|
||||
"errors"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "management.influx.metrics.export.consistency",
|
||||
"defaultValue": "one"
|
||||
},
|
||||
{
|
||||
"name": "management.info.build.enabled",
|
||||
"type": "java.lang.Boolean",
|
||||
@@ -305,10 +265,6 @@
|
||||
"description": "Whether to enable git info.",
|
||||
"defaultValue": true
|
||||
},
|
||||
{
|
||||
"name": "management.info.git.mode",
|
||||
"defaultValue": "simple"
|
||||
},
|
||||
{
|
||||
"name": "management.info.java.enabled",
|
||||
"type": "java.lang.Boolean",
|
||||
@@ -2079,45 +2035,17 @@
|
||||
"level": "error"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "management.newrelic.metrics.export.client-provider-type",
|
||||
"defaultValue": "insights-api"
|
||||
},
|
||||
{
|
||||
"name": "management.observations.annotations.enabled",
|
||||
"type": "java.lang.Boolean",
|
||||
"description": "Whether auto-configuration of Micrometer annotations is enabled.",
|
||||
"defaultValue": false
|
||||
},
|
||||
{
|
||||
"name": "management.otlp.logging.compression",
|
||||
"defaultValue": "none"
|
||||
},
|
||||
{
|
||||
"name": "management.otlp.metrics.export.aggregation-temporality",
|
||||
"defaultValue": "cumulative"
|
||||
},
|
||||
{
|
||||
"name": "management.otlp.metrics.export.base-time-unit",
|
||||
"defaultValue": "milliseconds"
|
||||
},
|
||||
{
|
||||
"name": "management.otlp.tracing.compression",
|
||||
"defaultValue": "none"
|
||||
},
|
||||
{
|
||||
"name": "management.otlp.tracing.export.enabled",
|
||||
"type": "java.lang.Boolean",
|
||||
"description": "Whether auto-configuration of tracing is enabled to export OTLP traces."
|
||||
},
|
||||
{
|
||||
"name": "management.prometheus.metrics.export.histogram-flavor",
|
||||
"defaultValue": "prometheus"
|
||||
},
|
||||
{
|
||||
"name": "management.prometheus.metrics.export.pushgateway.shutdown-operation",
|
||||
"defaultValue": "none"
|
||||
},
|
||||
{
|
||||
"name": "management.server.add-application-context-header",
|
||||
"type": "java.lang.Boolean",
|
||||
@@ -2218,22 +2146,6 @@
|
||||
"name": "management.server.ssl.trust-store-type",
|
||||
"description": "Type of the trust store."
|
||||
},
|
||||
{
|
||||
"name": "management.signalfx.metrics.export.published-histogram-type",
|
||||
"defaultValue": "default"
|
||||
},
|
||||
{
|
||||
"name": "management.simple.metrics.export.mode",
|
||||
"defaultValue": "cumulative"
|
||||
},
|
||||
{
|
||||
"name": "management.statsd.metrics.export.flavor",
|
||||
"defaultValue": "datadog"
|
||||
},
|
||||
{
|
||||
"name": "management.statsd.metrics.export.protocol",
|
||||
"defaultValue": "udp"
|
||||
},
|
||||
{
|
||||
"name": "management.trace.http.enabled",
|
||||
"deprecation": {
|
||||
|
||||
@@ -37,22 +37,6 @@
|
||||
"level": "error"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "server.error.include-binding-errors",
|
||||
"defaultValue": "never"
|
||||
},
|
||||
{
|
||||
"name": "server.error.include-message",
|
||||
"defaultValue": "never"
|
||||
},
|
||||
{
|
||||
"name": "server.error.include-path",
|
||||
"defaultValue": "always"
|
||||
},
|
||||
{
|
||||
"name": "server.error.include-stacktrace",
|
||||
"defaultValue": "never"
|
||||
},
|
||||
{
|
||||
"name": "server.http2.enabled",
|
||||
"description": "Whether to enable HTTP/2 support, if the current environment supports it.",
|
||||
@@ -72,10 +56,6 @@
|
||||
"level": "error"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "server.jetty.accesslog.format",
|
||||
"defaultValue": "ncsa"
|
||||
},
|
||||
{
|
||||
"name": "server.jetty.accesslog.locale",
|
||||
"deprecation": {
|
||||
@@ -279,10 +259,6 @@
|
||||
"name": "server.servlet.session.tracking-modes",
|
||||
"description": "Session tracking modes."
|
||||
},
|
||||
{
|
||||
"name": "server.shutdown",
|
||||
"defaultValue": "immediate"
|
||||
},
|
||||
{
|
||||
"name": "server.ssl.bundle",
|
||||
"description": "The name of a configured SSL bundle."
|
||||
@@ -499,10 +475,6 @@
|
||||
"level": "error"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "spring.batch.jdbc.initialize-schema",
|
||||
"defaultValue": "embedded"
|
||||
},
|
||||
{
|
||||
"name": "spring.batch.job.enabled",
|
||||
"type": "java.lang.Boolean",
|
||||
@@ -1055,10 +1027,6 @@
|
||||
"name": "spring.data.mongodb.uri",
|
||||
"defaultValue": "mongodb://localhost/test"
|
||||
},
|
||||
{
|
||||
"name": "spring.data.mongodb.uuid-representation",
|
||||
"defaultValue": "java-legacy"
|
||||
},
|
||||
{
|
||||
"name": "spring.data.neo4j.auto-index",
|
||||
"description": "Auto index mode.",
|
||||
@@ -1157,10 +1125,6 @@
|
||||
"level": "error"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "spring.data.rest.detection-strategy",
|
||||
"defaultValue": "default"
|
||||
},
|
||||
{
|
||||
"name" : "spring.datasource.continue-on-error",
|
||||
"type" : "java.lang.Boolean",
|
||||
@@ -1619,10 +1583,6 @@
|
||||
"name": "spring.info.git.location",
|
||||
"defaultValue": "classpath:git.properties"
|
||||
},
|
||||
{
|
||||
"name": "spring.integration.jdbc.initialize-schema",
|
||||
"defaultValue": "embedded"
|
||||
},
|
||||
{
|
||||
"name": "spring.jackson.constructor-detector",
|
||||
"defaultValue": "default"
|
||||
@@ -1639,22 +1599,6 @@
|
||||
"level": "error"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "spring.jersey.type",
|
||||
"defaultValue": "servlet"
|
||||
},
|
||||
{
|
||||
"name": "spring.jms.listener.session.acknowledge-mode",
|
||||
"defaultValue": "auto"
|
||||
},
|
||||
{
|
||||
"name": "spring.jms.template.session.acknowledge-mode",
|
||||
"defaultValue": "auto"
|
||||
},
|
||||
{
|
||||
"name": "spring.jmx.registration-policy",
|
||||
"defaultValue": "fail-on-existing"
|
||||
},
|
||||
{
|
||||
"name": "spring.jpa.hibernate.use-new-id-generator-mappings",
|
||||
"type": "java.lang.Boolean",
|
||||
@@ -1835,10 +1779,6 @@
|
||||
"level": "error"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "spring.kafka.consumer.isolation-level",
|
||||
"defaultValue": "read-uncommitted"
|
||||
},
|
||||
{
|
||||
"name": "spring.kafka.consumer.ssl.keystore-location",
|
||||
"type": "org.springframework.core.io.Resource",
|
||||
@@ -1875,10 +1815,6 @@
|
||||
"level": "error"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "spring.kafka.jaas.control-flag",
|
||||
"defaultValue": "required"
|
||||
},
|
||||
{
|
||||
"name": "spring.kafka.listener.only-log-record-metadata",
|
||||
"type": "java.lang.Boolean",
|
||||
@@ -1889,10 +1825,6 @@
|
||||
"level": "error"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "spring.kafka.listener.type",
|
||||
"defaultValue": "single"
|
||||
},
|
||||
{
|
||||
"name": "spring.kafka.producer.ssl.keystore-location",
|
||||
"type": "org.springframework.core.io.Resource",
|
||||
@@ -2097,10 +2029,6 @@
|
||||
"level": "error"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "spring.mvc.pathmatch.matching-strategy",
|
||||
"defaultValue": "path-pattern-parser"
|
||||
},
|
||||
{
|
||||
"name": "spring.mvc.throw-exception-if-no-handler-found",
|
||||
"deprecation": {
|
||||
@@ -2108,58 +2036,22 @@
|
||||
"level": "error"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "spring.neo4j.security.trust-strategy",
|
||||
"defaultValue": "trust-system-ca-signed-certificates"
|
||||
},
|
||||
{
|
||||
"name": "spring.neo4j.uri",
|
||||
"defaultValue": "bolt://localhost:7687"
|
||||
},
|
||||
{
|
||||
"name": "spring.pulsar.client.failover.policy",
|
||||
"defaultValue": "order"
|
||||
},
|
||||
{
|
||||
"name": "spring.pulsar.consumer.subscription.initial-position",
|
||||
"defaultValue": "latest"
|
||||
},
|
||||
{
|
||||
"name": "spring.pulsar.consumer.subscription.mode",
|
||||
"defaultValue": "durable"
|
||||
},
|
||||
{
|
||||
"name": "spring.pulsar.consumer.subscription.topics-mode",
|
||||
"defaultValue": "persistentonly"
|
||||
},
|
||||
{
|
||||
"name": "spring.pulsar.consumer.subscription.type",
|
||||
"defaultValue": "exclusive"
|
||||
},
|
||||
{
|
||||
"name": "spring.pulsar.function.enabled",
|
||||
"type": "java.lang.Boolean",
|
||||
"description": "Whether to enable function support.",
|
||||
"defaultValue": true
|
||||
},
|
||||
{
|
||||
"name": "spring.pulsar.producer.access-mode",
|
||||
"defaultValue": "shared"
|
||||
},
|
||||
{
|
||||
"name": "spring.pulsar.producer.cache.enabled",
|
||||
"type": "java.lang.Boolean",
|
||||
"description": "Whether to enable caching in the PulsarProducerFactory.",
|
||||
"defaultValue": true
|
||||
},
|
||||
{
|
||||
"name": "spring.pulsar.producer.hashing-scheme",
|
||||
"defaultValue": "javastringhash"
|
||||
},
|
||||
{
|
||||
"name": "spring.pulsar.producer.message-routing-mode",
|
||||
"defaultValue": "roundrobinpartition"
|
||||
},
|
||||
{
|
||||
"name": "spring.quartz.jdbc.comment-prefix",
|
||||
"defaultValue": [
|
||||
@@ -2167,30 +2059,10 @@
|
||||
"--"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "spring.quartz.jdbc.initialize-schema",
|
||||
"defaultValue": "embedded"
|
||||
},
|
||||
{
|
||||
"name": "spring.quartz.job-store-type",
|
||||
"defaultValue": "memory"
|
||||
},
|
||||
{
|
||||
"name": "spring.quartz.scheduler-name",
|
||||
"defaultValue": "quartzScheduler"
|
||||
},
|
||||
{
|
||||
"name": "spring.r2dbc.pool.validation-depth",
|
||||
"defaultValue": "local"
|
||||
},
|
||||
{
|
||||
"name": "spring.rabbitmq.address-shuffle-mode",
|
||||
"defaultValue": "none"
|
||||
},
|
||||
{
|
||||
"name": "spring.rabbitmq.cache.connection.mode",
|
||||
"defaultValue": "channel"
|
||||
},
|
||||
{
|
||||
"name": "spring.rabbitmq.dynamic",
|
||||
"type": "java.lang.Boolean",
|
||||
@@ -2204,10 +2076,6 @@
|
||||
"level": "error"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "spring.rabbitmq.listener.type",
|
||||
"defaultValue": "simple"
|
||||
},
|
||||
{
|
||||
"name": "spring.rabbitmq.publisher-confirms",
|
||||
"type": "java.lang.Boolean",
|
||||
@@ -2223,10 +2091,6 @@
|
||||
"level": "error"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "spring.reactor.context-propagation",
|
||||
"defaultValue": "limited"
|
||||
},
|
||||
{
|
||||
"name": "spring.reactor.stacktrace-mode.enabled",
|
||||
"description": "Whether Reactor should collect stacktrace information at runtime.",
|
||||
@@ -2772,10 +2636,6 @@
|
||||
"name": "spring.rsocket.server.ssl.trust-store-type",
|
||||
"description": "Type of the trust store."
|
||||
},
|
||||
{
|
||||
"name": "spring.rsocket.server.transport",
|
||||
"defaultValue": "tcp"
|
||||
},
|
||||
{
|
||||
"name": "spring.security.filter.dispatcher-types",
|
||||
"defaultValue": [
|
||||
@@ -2798,46 +2658,10 @@
|
||||
"level": "error"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "spring.session.hazelcast.flush-mode",
|
||||
"defaultValue": "on-save"
|
||||
},
|
||||
{
|
||||
"name": "spring.session.hazelcast.save-mode",
|
||||
"defaultValue": "on-set-attribute"
|
||||
},
|
||||
{
|
||||
"name": "spring.session.jdbc.flush-mode",
|
||||
"defaultValue": "on-save"
|
||||
},
|
||||
{
|
||||
"name": "spring.session.jdbc.initialize-schema",
|
||||
"defaultValue": "embedded"
|
||||
},
|
||||
{
|
||||
"name": "spring.session.jdbc.save-mode",
|
||||
"defaultValue": "on-set-attribute"
|
||||
},
|
||||
{
|
||||
"name": "spring.session.redis.cleanup-cron",
|
||||
"defaultValue": "0 * * * * *"
|
||||
},
|
||||
{
|
||||
"name": "spring.session.redis.configure-action",
|
||||
"defaultValue": "notify-keyspace-events"
|
||||
},
|
||||
{
|
||||
"name": "spring.session.redis.flush-mode",
|
||||
"defaultValue": "on-save"
|
||||
},
|
||||
{
|
||||
"name": "spring.session.redis.repository-type",
|
||||
"defaultValue": "default"
|
||||
},
|
||||
{
|
||||
"name": "spring.session.redis.save-mode",
|
||||
"defaultValue": "on-set-attribute"
|
||||
},
|
||||
{
|
||||
"name": "spring.session.servlet.filter-dispatcher-types",
|
||||
"defaultValue": [
|
||||
@@ -2856,10 +2680,6 @@
|
||||
"level": "warning"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "spring.sql.init.mode",
|
||||
"defaultValue": "embedded"
|
||||
},
|
||||
{
|
||||
"name": "spring.threads.virtual.enabled",
|
||||
"type": "java.lang.Boolean",
|
||||
@@ -2893,10 +2713,6 @@
|
||||
"name": "spring.thymeleaf.suffix",
|
||||
"defaultValue": ".html"
|
||||
},
|
||||
{
|
||||
"name": "spring.web.locale-resolver",
|
||||
"defaultValue": "accept-header"
|
||||
},
|
||||
{
|
||||
"name": "spring.webflux.hiddenmethod.filter.enabled",
|
||||
"type": "java.lang.Boolean",
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
{
|
||||
"groups": [],
|
||||
"hints": [],
|
||||
"properties": [
|
||||
{
|
||||
"name": "spring.docker.compose.lifecycle-management",
|
||||
"defaultValue": "start-and-stop"
|
||||
},
|
||||
{
|
||||
"name": "spring.docker.compose.readiness.wait",
|
||||
"defaultValue": "always"
|
||||
},
|
||||
{
|
||||
"name": "spring.docker.compose.start.command",
|
||||
"defaultValue": "up"
|
||||
},
|
||||
{
|
||||
"name": "spring.docker.compose.start.log-level",
|
||||
"defaultValue": "info"
|
||||
},
|
||||
{
|
||||
"name": "spring.docker.compose.start.skip",
|
||||
"defaultValue": "if-running"
|
||||
},
|
||||
{
|
||||
"name": "spring.docker.compose.stop.command",
|
||||
"defaultValue": "stop"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -93,7 +93,7 @@ If you use `@ConfigurationProperties` with record class then record components'
|
||||
|
||||
The annotation processor applies a number of heuristics to extract the default value from the source model.
|
||||
Default values have to be provided statically. In particular, do not refer to a constant defined in another class.
|
||||
Also, the annotation processor cannot auto-detect default values for ``Enum``s and ``Collections``s.
|
||||
Also, the annotation processor cannot auto-detect default values for ``Collections``s.
|
||||
|
||||
For cases where the default value could not be detected, xref:configuration-metadata/annotation-processor.adoc#appendix.configuration-metadata.annotation-processor.adding-additional-metadata[manual metadata] should be provided.
|
||||
Consider the following example:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
* Copyright 2012-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -36,6 +36,12 @@ class ExpressionTree extends ReflectionWrapper {
|
||||
|
||||
private final Method methodInvocationArgumentsMethod = findMethod(this.methodInvocationTreeType, "getArguments");
|
||||
|
||||
private final Class<?> memberSelectTreeType = findClass("com.sun.source.tree.MemberSelectTree");
|
||||
|
||||
private final Method memberSelectTreeExpressionMethod = findMethod(this.memberSelectTreeType, "getExpression");
|
||||
|
||||
private final Method memberSelectTreeIdentifierMethod = findMethod(this.memberSelectTreeType, "getIdentifier");
|
||||
|
||||
private final Class<?> newArrayTreeType = findClass("com.sun.source.tree.NewArrayTree");
|
||||
|
||||
private final Method arrayValueMethod = findMethod(this.newArrayTreeType, "getInitializers");
|
||||
@@ -65,6 +71,17 @@ class ExpressionTree extends ReflectionWrapper {
|
||||
return null;
|
||||
}
|
||||
|
||||
Member getSelectedMember() throws Exception {
|
||||
if (this.memberSelectTreeType.isAssignableFrom(getInstance().getClass())) {
|
||||
String expression = this.memberSelectTreeExpressionMethod.invoke(getInstance()).toString();
|
||||
String identifier = this.memberSelectTreeIdentifierMethod.invoke(getInstance()).toString();
|
||||
if (expression != null && identifier != null) {
|
||||
return new Member(expression, identifier);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
List<? extends ExpressionTree> getArrayExpression() throws Exception {
|
||||
if (this.newArrayTreeType.isAssignableFrom(getInstance().getClass())) {
|
||||
List<?> elements = (List<?>) this.arrayValueMethod.invoke(getInstance());
|
||||
@@ -80,4 +97,7 @@ class ExpressionTree extends ReflectionWrapper {
|
||||
return null;
|
||||
}
|
||||
|
||||
record Member(String expression, String identifier) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ package org.springframework.boot.configurationprocessor.fieldvalues.javac;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -27,6 +28,8 @@ import javax.lang.model.element.Modifier;
|
||||
import javax.lang.model.element.TypeElement;
|
||||
|
||||
import org.springframework.boot.configurationprocessor.fieldvalues.FieldValuesParser;
|
||||
import org.springframework.boot.configurationprocessor.fieldvalues.javac.ExpressionTree.Member;
|
||||
import org.springframework.boot.configurationprocessor.support.ConventionUtils;
|
||||
|
||||
/**
|
||||
* {@link FieldValuesParser} implementation for the standard Java compiler.
|
||||
@@ -165,12 +168,12 @@ public class JavaCompilerFieldValuesParser implements FieldValuesParser {
|
||||
Class<?> wrapperType = WRAPPER_TYPES.get(variable.getType());
|
||||
Object defaultValue = DEFAULT_TYPE_VALUES.get(wrapperType);
|
||||
if (initializer != null) {
|
||||
return getValue(initializer, defaultValue);
|
||||
return getValue(variable.getType(), initializer, defaultValue);
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
private Object getValue(ExpressionTree expression, Object defaultValue) throws Exception {
|
||||
private Object getValue(String variableType, ExpressionTree expression, Object defaultValue) throws Exception {
|
||||
Object literalValue = expression.getLiteralValue();
|
||||
if (literalValue != null) {
|
||||
return literalValue;
|
||||
@@ -183,7 +186,7 @@ public class JavaCompilerFieldValuesParser implements FieldValuesParser {
|
||||
if (arrayValues != null) {
|
||||
Object[] result = new Object[arrayValues.size()];
|
||||
for (int i = 0; i < arrayValues.size(); i++) {
|
||||
Object value = getValue(arrayValues.get(i), null);
|
||||
Object value = getValue(variableType, arrayValues.get(i), null);
|
||||
if (value == null) { // One of the elements could not be resolved
|
||||
return defaultValue;
|
||||
}
|
||||
@@ -195,7 +198,16 @@ public class JavaCompilerFieldValuesParser implements FieldValuesParser {
|
||||
return this.staticFinals.get(expression.toString());
|
||||
}
|
||||
if (expression.getKind().equals("MEMBER_SELECT")) {
|
||||
return WELL_KNOWN_STATIC_FINALS.get(expression.toString());
|
||||
Object value = WELL_KNOWN_STATIC_FINALS.get(expression.toString());
|
||||
if (value != null) {
|
||||
return value;
|
||||
}
|
||||
Member selectedMember = expression.getSelectedMember();
|
||||
// Type matching the expression, assuming an enum
|
||||
if (selectedMember != null && selectedMember.expression().equals(variableType)) {
|
||||
return ConventionUtils.toDashedCase(selectedMember.identifier().toLowerCase(Locale.ENGLISH));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
@@ -17,14 +17,12 @@
|
||||
package org.springframework.boot.configurationprocessor.metadata;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.boot.configurationprocessor.support.ConventionUtils;
|
||||
|
||||
/**
|
||||
* Configuration meta-data.
|
||||
@@ -36,13 +34,6 @@ import java.util.Set;
|
||||
*/
|
||||
public class ConfigurationMetadata {
|
||||
|
||||
private static final Set<Character> SEPARATORS;
|
||||
|
||||
static {
|
||||
List<Character> chars = Arrays.asList('-', '_');
|
||||
SEPARATORS = Collections.unmodifiableSet(new HashSet<>(chars));
|
||||
}
|
||||
|
||||
private final Map<String, List<ItemMetadata>> items;
|
||||
|
||||
private final Map<String, List<ItemHint>> hints;
|
||||
@@ -184,31 +175,11 @@ public class ConfigurationMetadata {
|
||||
|
||||
public static String nestedPrefix(String prefix, String name) {
|
||||
String nestedPrefix = (prefix != null) ? prefix : "";
|
||||
String dashedName = toDashedCase(name);
|
||||
String dashedName = ConventionUtils.toDashedCase(name);
|
||||
nestedPrefix += nestedPrefix.isEmpty() ? dashedName : "." + dashedName;
|
||||
return nestedPrefix;
|
||||
}
|
||||
|
||||
static String toDashedCase(String name) {
|
||||
StringBuilder dashed = new StringBuilder();
|
||||
Character previous = null;
|
||||
for (int i = 0; i < name.length(); i++) {
|
||||
char current = name.charAt(i);
|
||||
if (SEPARATORS.contains(current)) {
|
||||
dashed.append("-");
|
||||
}
|
||||
else if (Character.isUpperCase(current) && previous != null && !SEPARATORS.contains(previous)) {
|
||||
dashed.append("-").append(current);
|
||||
}
|
||||
else {
|
||||
dashed.append(current);
|
||||
}
|
||||
previous = current;
|
||||
|
||||
}
|
||||
return dashed.toString().toLowerCase(Locale.ENGLISH);
|
||||
}
|
||||
|
||||
private static <T extends Comparable<T>> List<T> flattenValues(Map<?, List<T>> map) {
|
||||
List<T> content = new ArrayList<>();
|
||||
for (List<T> values : map.values()) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
* Copyright 2012-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -22,6 +22,8 @@ import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.boot.configurationprocessor.support.ConventionUtils;
|
||||
|
||||
/**
|
||||
* Provide hints on an {@link ItemMetadata}. Defines the list of possible values for a
|
||||
* particular item as {@link ItemHint.ValueHint} instances.
|
||||
@@ -53,9 +55,9 @@ public class ItemHint implements Comparable<ItemHint> {
|
||||
if (dot != -1) {
|
||||
String prefix = name.substring(0, dot);
|
||||
String originalName = name.substring(dot);
|
||||
return prefix + ConfigurationMetadata.toDashedCase(originalName);
|
||||
return prefix + ConventionUtils.toDashedCase(originalName);
|
||||
}
|
||||
return ConfigurationMetadata.toDashedCase(name);
|
||||
return ConventionUtils.toDashedCase(name);
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
|
||||
@@ -18,6 +18,8 @@ package org.springframework.boot.configurationprocessor.metadata;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import org.springframework.boot.configurationprocessor.support.ConventionUtils;
|
||||
|
||||
/**
|
||||
* A group or property meta-data item from some {@link ConfigurationMetadata}.
|
||||
*
|
||||
@@ -68,7 +70,7 @@ public final class ItemMetadata implements Comparable<ItemMetadata> {
|
||||
if (!fullName.isEmpty()) {
|
||||
fullName.append('.');
|
||||
}
|
||||
fullName.append(ConfigurationMetadata.toDashedCase(name));
|
||||
fullName.append(ConventionUtils.toDashedCase(name));
|
||||
}
|
||||
return fullName.toString();
|
||||
}
|
||||
@@ -218,7 +220,7 @@ public final class ItemMetadata implements Comparable<ItemMetadata> {
|
||||
}
|
||||
|
||||
public static String newItemMetadataPrefix(String prefix, String suffix) {
|
||||
return prefix.toLowerCase(Locale.ENGLISH) + ConfigurationMetadata.toDashedCase(suffix);
|
||||
return prefix.toLowerCase(Locale.ENGLISH) + ConventionUtils.toDashedCase(suffix);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright 2012-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* 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.configurationprocessor.support;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Convention utilities.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 3.4.0
|
||||
*/
|
||||
public abstract class ConventionUtils {
|
||||
|
||||
private static final Set<Character> SEPARATORS;
|
||||
|
||||
static {
|
||||
List<Character> chars = Arrays.asList('-', '_');
|
||||
SEPARATORS = Collections.unmodifiableSet(new HashSet<>(chars));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the idiomatic metadata format for the given {@code value}.
|
||||
* @param value a value
|
||||
* @return the idiomatic format for the value, or the value itself if it already
|
||||
* complies with the idiomatic metadata format.
|
||||
*/
|
||||
public static String toDashedCase(String value) {
|
||||
StringBuilder dashed = new StringBuilder();
|
||||
Character previous = null;
|
||||
for (int i = 0; i < value.length(); i++) {
|
||||
char current = value.charAt(i);
|
||||
if (SEPARATORS.contains(current)) {
|
||||
dashed.append("-");
|
||||
}
|
||||
else if (Character.isUpperCase(current) && previous != null && !SEPARATORS.contains(previous)) {
|
||||
dashed.append("-").append(current);
|
||||
}
|
||||
else {
|
||||
dashed.append(current);
|
||||
}
|
||||
previous = current;
|
||||
|
||||
}
|
||||
return dashed.toString().toLowerCase(Locale.ENGLISH);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2012-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Support classes for configuration metadata processing.
|
||||
*/
|
||||
package org.springframework.boot.configurationprocessor.support;
|
||||
@@ -16,6 +16,9 @@
|
||||
|
||||
package org.springframework.boot.configurationprocessor;
|
||||
|
||||
import java.time.temporal.ChronoField;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.configurationprocessor.metadata.ConfigurationMetadata;
|
||||
@@ -50,6 +53,7 @@ import org.springframework.boot.configurationsample.specific.DeprecatedSimplePoj
|
||||
import org.springframework.boot.configurationsample.specific.DeprecatedUnrelatedMethodPojo;
|
||||
import org.springframework.boot.configurationsample.specific.DoubleRegistrationProperties;
|
||||
import org.springframework.boot.configurationsample.specific.EmptyDefaultValueProperties;
|
||||
import org.springframework.boot.configurationsample.specific.EnumValuesPojo;
|
||||
import org.springframework.boot.configurationsample.specific.ExcludedTypesPojo;
|
||||
import org.springframework.boot.configurationsample.specific.InnerClassAnnotatedGetterConfig;
|
||||
import org.springframework.boot.configurationsample.specific.InnerClassHierarchicalProperties;
|
||||
@@ -173,6 +177,15 @@ class ConfigurationMetadataAnnotationProcessorTests extends AbstractMetadataGene
|
||||
.fromSource(HierarchicalProperties.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void enumValues() {
|
||||
ConfigurationMetadata metadata = compile(EnumValuesPojo.class);
|
||||
assertThat(metadata).has(Metadata.withGroup("test").fromSource(EnumValuesPojo.class));
|
||||
assertThat(metadata).has(Metadata.withProperty("test.seconds", ChronoUnit.class).withDefaultValue("seconds"));
|
||||
assertThat(metadata)
|
||||
.has(Metadata.withProperty("test.hour-of-day", ChronoField.class).withDefaultValue("hour-of-day"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void descriptionProperties() {
|
||||
ConfigurationMetadata metadata = compile(DescriptionProperties.class);
|
||||
|
||||
@@ -48,7 +48,7 @@ public abstract class AbstractFieldValuesProcessorTests {
|
||||
protected abstract FieldValuesParser createProcessor(ProcessingEnvironment env);
|
||||
|
||||
@Test
|
||||
void getFieldValues() throws Exception {
|
||||
void getFieldValues() {
|
||||
TestProcessor processor = new TestProcessor();
|
||||
TestCompiler compiler = TestCompiler.forSystem()
|
||||
.withProcessors(processor)
|
||||
@@ -105,6 +105,11 @@ public abstract class AbstractFieldValuesProcessorTests {
|
||||
assertThat(values.get("periodMonths")).isEqualTo("10m");
|
||||
assertThat(values.get("periodYears")).isEqualTo("15y");
|
||||
assertThat(values.get("periodZero")).isEqualTo(0);
|
||||
assertThat(values.get("enumNone")).isNull();
|
||||
assertThat(values.get("enumSimple")).isEqualTo("seconds");
|
||||
assertThat(values.get("enumQualified")).isEqualTo("hour-of-day");
|
||||
assertThat(values.get("enumWithIndirection")).isNull();
|
||||
assertThat(values.get("memberSelectInt")).isNull();
|
||||
}
|
||||
|
||||
@SupportedAnnotationTypes({ "org.springframework.boot.configurationsample.ConfigurationProperties" })
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
* Copyright 2012-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -14,18 +14,18 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.configurationprocessor.metadata;
|
||||
package org.springframework.boot.configurationprocessor.support;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link ConfigurationMetadata}.
|
||||
* Tests for {@link ConventionUtils}.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
class ConfigurationMetadataTests {
|
||||
class ConventionUtilsTests {
|
||||
|
||||
@Test
|
||||
void toDashedCaseCamelCase() {
|
||||
@@ -78,7 +78,7 @@ class ConfigurationMetadataTests {
|
||||
}
|
||||
|
||||
private String toDashedCase(String name) {
|
||||
return ConfigurationMetadata.toDashedCase(name);
|
||||
return ConventionUtils.toDashedCase(name);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2020 the original author or authors.
|
||||
* Copyright 2012-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -20,6 +20,7 @@ import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.Duration;
|
||||
import java.time.Period;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
|
||||
import org.springframework.boot.configurationsample.ConfigurationProperties;
|
||||
import org.springframework.util.MimeType;
|
||||
@@ -151,4 +152,22 @@ public class FieldValues {
|
||||
|
||||
private Period periodZero = Period.ZERO;
|
||||
|
||||
private ChronoUnit enumNone;
|
||||
|
||||
private ChronoUnit enumSimple = ChronoUnit.SECONDS;
|
||||
|
||||
private java.time.temporal.ChronoField enumQualified = java.time.temporal.ChronoField.HOUR_OF_DAY;
|
||||
|
||||
private ChronoUnit enumWithIndirection = SampleOptions.DEFAULT_UNIT;
|
||||
|
||||
private int memberSelectInt = SampleOptions.DEFAULT_MAX_RETRIES;
|
||||
|
||||
public static class SampleOptions {
|
||||
|
||||
static final Integer DEFAULT_MAX_RETRIES = 20;
|
||||
|
||||
static final ChronoUnit DEFAULT_UNIT = ChronoUnit.SECONDS;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 2012-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* 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.configurationsample.specific;
|
||||
|
||||
import java.time.temporal.ChronoField;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
|
||||
import org.springframework.boot.configurationsample.ConfigurationProperties;
|
||||
|
||||
/**
|
||||
* Sample config for enum and default values.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
@ConfigurationProperties("test")
|
||||
public class EnumValuesPojo {
|
||||
|
||||
private ChronoUnit seconds = ChronoUnit.SECONDS;
|
||||
|
||||
private ChronoField hourOfDay = ChronoField.HOUR_OF_DAY;
|
||||
|
||||
public ChronoUnit getSeconds() {
|
||||
return this.seconds;
|
||||
}
|
||||
|
||||
public void setSeconds(ChronoUnit seconds) {
|
||||
this.seconds = seconds;
|
||||
}
|
||||
|
||||
public ChronoField getHourOfDay() {
|
||||
return this.hourOfDay;
|
||||
}
|
||||
|
||||
public void setHourOfDay(ChronoField hourOfDay) {
|
||||
this.hourOfDay = hourOfDay;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user