Commit 9ebe1523 authored by Phillip Webb's avatar Phillip Webb

Polish

parent 6fdcdd88
...@@ -79,23 +79,17 @@ public class MetricExportAutoConfiguration { ...@@ -79,23 +79,17 @@ public class MetricExportAutoConfiguration {
reader = new CompositeMetricReader( reader = new CompositeMetricReader(
this.readers.toArray(new MetricReader[this.readers.size()])); this.readers.toArray(new MetricReader[this.readers.size()]));
} }
MetricExporters exporters = null; if (reader == null && this.exporters.isEmpty()) {
return new NoOpSchedulingConfigurer();
}
MetricExporters exporters = new MetricExporters(this.properties);
if (reader != null) { if (reader != null) {
exporters = new MetricExporters(this.properties);
writers.putAll(this.writers); writers.putAll(this.writers);
exporters.setReader(reader); exporters.setReader(reader);
exporters.setWriters(writers); exporters.setWriters(writers);
} }
if (!this.exporters.isEmpty()) { exporters.setExporters(this.exporters);
if (exporters==null) { return exporters;
exporters = new MetricExporters(this.properties);
}
exporters.setExporters(this.exporters);
}
if (exporters!=null) {
return exporters;
}
return new NoOpSchedulingConfigurer();
} }
@Configuration @Configuration
......
...@@ -16,9 +16,6 @@ ...@@ -16,9 +16,6 @@
package org.springframework.boot.actuate.metrics.export; package org.springframework.boot.actuate.metrics.export;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import java.util.Collections; import java.util.Collections;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
...@@ -29,6 +26,9 @@ import org.springframework.boot.actuate.metrics.reader.MetricReader; ...@@ -29,6 +26,9 @@ import org.springframework.boot.actuate.metrics.reader.MetricReader;
import org.springframework.boot.actuate.metrics.writer.MetricWriter; import org.springframework.boot.actuate.metrics.writer.MetricWriter;
import org.springframework.scheduling.config.ScheduledTaskRegistrar; import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
/** /**
* Tests for {@link MetricExporters}. * Tests for {@link MetricExporters}.
* *
......
...@@ -32,6 +32,8 @@ import org.springframework.context.annotation.Configuration; ...@@ -32,6 +32,8 @@ import org.springframework.context.annotation.Configuration;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
/** /**
* Tests for {@link SessionAutoConfiguration}.
*
* @author Dave Syer * @author Dave Syer
* @since 1.3.0 * @since 1.3.0
*/ */
......
...@@ -24,6 +24,5 @@ ...@@ -24,6 +24,5 @@
<groupId>org.json</groupId> <groupId>org.json</groupId>
<artifactId>json</artifactId> <artifactId>json</artifactId>
</dependency> </dependency>
</dependencies> </dependencies>
</project> </project>
/* /*
* Copyright 2012-2014 the original author or authors. * Copyright 2012-2015 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -20,10 +20,10 @@ import java.util.HashMap; ...@@ -20,10 +20,10 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
/** /**
* Gather a collection of {@link ConfigurationMetadataProperty properties} that * Gather a collection of {@link ConfigurationMetadataProperty properties} that are
* are sharing a {@link #getId() common prefix}. Provide access to all the * sharing a {@link #getId() common prefix}. Provide access to all the
* {@link ConfigurationMetadataSource sources} that have contributed properties * {@link ConfigurationMetadataSource sources} that have contributed properties to the
* to the group. * group.
* *
* @author Stephane Nicoll * @author Stephane Nicoll
* @since 1.3.0 * @since 1.3.0
...@@ -32,27 +32,27 @@ public class ConfigurationMetadataGroup { ...@@ -32,27 +32,27 @@ public class ConfigurationMetadataGroup {
private final String id; private final String id;
private final Map<String, ConfigurationMetadataSource> sources = private final Map<String, ConfigurationMetadataSource> sources = new HashMap<String, ConfigurationMetadataSource>();
new HashMap<String, ConfigurationMetadataSource>();
private final Map<String, ConfigurationMetadataProperty> properties = private final Map<String, ConfigurationMetadataProperty> properties = new HashMap<String, ConfigurationMetadataProperty>();
new HashMap<String, ConfigurationMetadataProperty>();
public ConfigurationMetadataGroup(String id) { public ConfigurationMetadataGroup(String id) {
this.id = id; this.id = id;
} }
/** /**
* Return the id of the group, used as a common prefix for all properties * Return the id of the group, used as a common prefix for all properties associated
* associated to it. * to it.
* @return the id of the group
*/ */
public String getId() { public String getId() {
return this.id; return this.id;
} }
/** /**
* Return the {@link ConfigurationMetadataSource sources} defining * Return the {@link ConfigurationMetadataSource sources} defining the properties of
* the properties of this group. * this group.
* @return the sources of the group
*/ */
public Map<String, ConfigurationMetadataSource> getSources() { public Map<String, ConfigurationMetadataSource> getSources() {
return this.sources; return this.sources;
...@@ -60,8 +60,11 @@ public class ConfigurationMetadataGroup { ...@@ -60,8 +60,11 @@ public class ConfigurationMetadataGroup {
/** /**
* Return the {@link ConfigurationMetadataProperty properties} defined in this group. * Return the {@link ConfigurationMetadataProperty properties} defined in this group.
* <p>A property may appear more than once for a given source, potentially with conflicting * <p>
* type or documentation. This is a "merged" view of the properties of this group. * A property may appear more than once for a given source, potentially with
* conflicting type or documentation. This is a "merged" view of the properties of
* this group.
* @return the properties of the group
* @see ConfigurationMetadataSource#getProperties() * @see ConfigurationMetadataSource#getProperties()
*/ */
public Map<String, ConfigurationMetadataProperty> getProperties() { public Map<String, ConfigurationMetadataProperty> getProperties() {
......
/*
* Copyright 2012-2015 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
*
* http://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.configurationmetadata; package org.springframework.boot.configurationmetadata;
import java.util.ArrayList; import java.util.ArrayList;
...@@ -18,7 +34,7 @@ class ConfigurationMetadataHint { ...@@ -18,7 +34,7 @@ class ConfigurationMetadataHint {
private final List<ValueProvider> valueProviders = new ArrayList<ValueProvider>(); private final List<ValueProvider> valueProviders = new ArrayList<ValueProvider>();
public String getId() { public String getId() {
return id; return this.id;
} }
public void setId(String id) { public void setId(String id) {
...@@ -26,11 +42,11 @@ class ConfigurationMetadataHint { ...@@ -26,11 +42,11 @@ class ConfigurationMetadataHint {
} }
public List<ValueHint> getValueHints() { public List<ValueHint> getValueHints() {
return valueHints; return this.valueHints;
} }
public List<ValueProvider> getValueProviders() { public List<ValueProvider> getValueProviders() {
return valueProviders; return this.valueProviders;
} }
} }
/* /*
* Copyright 2012-2014 the original author or authors. * Copyright 2012-2015 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -17,8 +17,8 @@ ...@@ -17,8 +17,8 @@
package org.springframework.boot.configurationmetadata; package org.springframework.boot.configurationmetadata;
/** /**
* An extension of {@link ConfigurationMetadataProperty} that provides the * An extension of {@link ConfigurationMetadataProperty} that provides the a reference to
* a reference to its source. * its source.
* *
* @author Stephane Nicoll * @author Stephane Nicoll
* @since 1.3.0 * @since 1.3.0
...@@ -30,9 +30,10 @@ class ConfigurationMetadataItem extends ConfigurationMetadataProperty { ...@@ -30,9 +30,10 @@ class ConfigurationMetadataItem extends ConfigurationMetadataProperty {
private String sourceMethod; private String sourceMethod;
/** /**
* The class name of the source that contributed this property. For example, if the property * The class name of the source that contributed this property. For example, if the
* was from a class annotated with {@code @ConfigurationProperties} this attribute would * property was from a class annotated with {@code @ConfigurationProperties} this
* contain the fully qualified name of that class. * attribute would contain the fully qualified name of that class.
* @return the source type
*/ */
public String getSourceType() { public String getSourceType() {
return this.sourceType; return this.sourceType;
...@@ -43,9 +44,10 @@ class ConfigurationMetadataItem extends ConfigurationMetadataProperty { ...@@ -43,9 +44,10 @@ class ConfigurationMetadataItem extends ConfigurationMetadataProperty {
} }
/** /**
* The full name of the method (including parenthesis and argument types) that contributed this * The full name of the method (including parenthesis and argument types) that
* property. For example, the name of a getter in a {@code @ConfigurationProperties} annotated * contributed this property. For example, the name of a getter in a
* class. * {@code @ConfigurationProperties} annotated class.
* @return the source method
*/ */
public String getSourceMethod() { public String getSourceMethod() {
return this.sourceMethod; return this.sourceMethod;
......
/* /*
* Copyright 2012-2014 the original author or authors. * Copyright 2012-2015 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -20,10 +20,10 @@ import java.util.ArrayList; ...@@ -20,10 +20,10 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
/** /**
* Define a configuration property. Each property is fully identified by * Define a configuration property. Each property is fully identified by its
* its {@link #getId() id} who is composed of a namespace prefix (the * {@link #getId() id} who is composed of a namespace prefix (the
* {@link ConfigurationMetadataGroup#getId() group id}), if any and the * {@link ConfigurationMetadataGroup#getId() group id}), if any and the {@link #getName()
* {@link #getName() name} of the property. * name} of the property.
* *
* @author Stephane Nicoll * @author Stephane Nicoll
* @since 1.3.0 * @since 1.3.0
...@@ -49,7 +49,9 @@ public class ConfigurationMetadataProperty { ...@@ -49,7 +49,9 @@ public class ConfigurationMetadataProperty {
private boolean deprecated; private boolean deprecated;
/** /**
* The full identifier of the property, in lowercase dashed form (e.g. my.group.simple-property) * The full identifier of the property, in lowercase dashed form (e.g.
* my.group.simple-property)
* @return the property id
*/ */
public String getId() { public String getId() {
return this.id; return this.id;
...@@ -60,8 +62,9 @@ public class ConfigurationMetadataProperty { ...@@ -60,8 +62,9 @@ public class ConfigurationMetadataProperty {
} }
/** /**
* The name of the property, in lowercase dashed form (e.g. simple-property). If this item * The name of the property, in lowercase dashed form (e.g. simple-property). If this
* does not belong to any group, the id is returned. * item does not belong to any group, the id is returned.
* @return the property name
*/ */
public String getName() { public String getName() {
return this.name; return this.name;
...@@ -72,13 +75,18 @@ public class ConfigurationMetadataProperty { ...@@ -72,13 +75,18 @@ public class ConfigurationMetadataProperty {
} }
/** /**
* The class name of the data type of the property. For example, {@code java.lang.String}. * The class name of the data type of the property. For example,
* <p>For consistency, the type of a primitive is specified using its wrapper counterpart, * {@code java.lang.String}.
* i.e. {@code boolean} becomes {@code java.lang.Boolean}. If the type holds generic * <p>
* information, these are provided as well, i.e. a {@code HashMap} of String to Integer * For consistency, the type of a primitive is specified using its wrapper
* would be defined as {@code java.util.HashMap<java.lang.String,java.lang.Integer>}. * counterpart, i.e. {@code boolean} becomes {@code java.lang.Boolean}. If the type
* <p>Note that this class may be a complex type that gets converted from a String as values * holds generic information, these are provided as well, i.e. a {@code HashMap} of
* are bound. * String to Integer would be defined as
* {@code java.util.HashMap<java.lang.String,java.lang.Integer>}.
* <p>
* Note that this class may be a complex type that gets converted from a String as
* values are bound.
* @return the property type
*/ */
public String getType() { public String getType() {
return this.type; return this.type;
...@@ -90,6 +98,7 @@ public class ConfigurationMetadataProperty { ...@@ -90,6 +98,7 @@ public class ConfigurationMetadataProperty {
/** /**
* A description of the property, if any. Can be multi-lines. * A description of the property, if any. Can be multi-lines.
* @return the property description
* @see #getShortDescription() * @see #getShortDescription()
*/ */
public String getDescription() { public String getDescription() {
...@@ -102,10 +111,11 @@ public class ConfigurationMetadataProperty { ...@@ -102,10 +111,11 @@ public class ConfigurationMetadataProperty {
/** /**
* A single-line, single-sentence description of this property, if any. * A single-line, single-sentence description of this property, if any.
* @return the property short description
* @see #getDescription() * @see #getDescription()
*/ */
public String getShortDescription() { public String getShortDescription() {
return shortDescription; return this.shortDescription;
} }
public void setShortDescription(String shortDescription) { public void setShortDescription(String shortDescription) {
...@@ -114,6 +124,7 @@ public class ConfigurationMetadataProperty { ...@@ -114,6 +124,7 @@ public class ConfigurationMetadataProperty {
/** /**
* The default value, if any. * The default value, if any.
* @return the default value
*/ */
public Object getDefaultValue() { public Object getDefaultValue() {
return this.defaultValue; return this.defaultValue;
...@@ -124,24 +135,28 @@ public class ConfigurationMetadataProperty { ...@@ -124,24 +135,28 @@ public class ConfigurationMetadataProperty {
} }
/** /**
* The list of well-defined values, if any. If no extra {@link ValueProvider provider} is * The list of well-defined values, if any. If no extra {@link ValueProvider provider}
* specified, these values are to be considered a closed-set of the available values * is specified, these values are to be considered a closed-set of the available
* for this item. * values for this item.
* @return the value hints
*/ */
public List<ValueHint> getValueHints() { public List<ValueHint> getValueHints() {
return valueHints; return this.valueHints;
} }
/** /**
* The value providers that are applicable to this item. Only one {@link ValueProvider} is * The value providers that are applicable to this item. Only one
* enabled for an item: the first in the list that is supported should be used. * {@link ValueProvider} is enabled for an item: the first in the list that is
* supported should be used.
* @return the value providers
*/ */
public List<ValueProvider> getValueProviders() { public List<ValueProvider> getValueProviders() {
return valueProviders; return this.valueProviders;
} }
/** /**
* Specify if the property is deprecated. * Specify if the property is deprecated.
* @return if the property is deprecated
*/ */
public boolean isDeprecated() { public boolean isDeprecated() {
return this.deprecated; return this.deprecated;
......
/* /*
* Copyright 2012-2014 the original author or authors. * Copyright 2012-2015 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -27,19 +27,20 @@ import java.util.Map; ...@@ -27,19 +27,20 @@ import java.util.Map;
public interface ConfigurationMetadataRepository { public interface ConfigurationMetadataRepository {
/** /**
* Defines the name of the "root" group, that is the group that * Defines the name of the "root" group, that is the group that gathers all the
* gathers all the properties that aren't attached to a specific * properties that aren't attached to a specific group.
* group.
*/ */
String ROOT_GROUP = "_ROOT_GROUP_"; String ROOT_GROUP = "_ROOT_GROUP_";
/** /**
* Return the groups, indexed by id. * Return the groups, indexed by id.
* @return all configuration meta-data groups
*/ */
Map<String, ConfigurationMetadataGroup> getAllGroups(); Map<String, ConfigurationMetadataGroup> getAllGroups();
/** /**
* Return the properties, indexed by id. * Return the properties, indexed by id.
* @return all configuration meta-data properties
*/ */
Map<String, ConfigurationMetadataProperty> getAllProperties(); Map<String, ConfigurationMetadataProperty> getAllProperties();
......
/* /*
* Copyright 2012-2014 the original author or authors. * Copyright 2012-2015 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -26,7 +26,8 @@ import java.util.Map; ...@@ -26,7 +26,8 @@ import java.util.Map;
import org.json.JSONException; import org.json.JSONException;
/** /**
* Load a {@link ConfigurationMetadataRepository} from the content of arbitrary resource(s). * Load a {@link ConfigurationMetadataRepository} from the content of arbitrary
* resource(s).
* *
* @author Stephane Nicoll * @author Stephane Nicoll
* @since 1.3.0 * @since 1.3.0
...@@ -39,75 +40,74 @@ public class ConfigurationMetadataRepositoryJsonBuilder { ...@@ -39,75 +40,74 @@ public class ConfigurationMetadataRepositoryJsonBuilder {
private final JsonReader reader = new JsonReader(); private final JsonReader reader = new JsonReader();
private final List<SimpleConfigurationMetadataRepository> repositories private final List<SimpleConfigurationMetadataRepository> repositories = new ArrayList<SimpleConfigurationMetadataRepository>();
= new ArrayList<SimpleConfigurationMetadataRepository>();
/**
* Create a new builder instance using {@link #UTF_8} as the default charset.
*/
public static ConfigurationMetadataRepositoryJsonBuilder create() {
return create(UTF_8);
}
/**
* Create a new builder instance using the specified default {@link Charset}.
*/
public static ConfigurationMetadataRepositoryJsonBuilder create(Charset defaultCharset) {
return new ConfigurationMetadataRepositoryJsonBuilder(defaultCharset);
}
private ConfigurationMetadataRepositoryJsonBuilder(Charset defaultCharset) { private ConfigurationMetadataRepositoryJsonBuilder(Charset defaultCharset) {
this.defaultCharset = defaultCharset; this.defaultCharset = defaultCharset;
} }
/** /**
* Add the content of a {@link ConfigurationMetadataRepository} defined by the specified * Add the content of a {@link ConfigurationMetadataRepository} defined by the
* {@link InputStream} json document using the default charset. If this metadata * specified {@link InputStream} json document using the default charset. If this
* repository holds items that were loaded previously, these are ignored. * metadata repository holds items that were loaded previously, these are ignored.
* <p>Leave the stream open when done. * <p>
* Leaves the stream open when done.
* @param inputStream the source input stream
* @return this builder
* @throws IOException
*/ */
public ConfigurationMetadataRepositoryJsonBuilder withJsonResource(InputStream in) public ConfigurationMetadataRepositoryJsonBuilder withJsonResource(
throws IOException { InputStream inputStream) throws IOException {
return withJsonResource(in, defaultCharset); return withJsonResource(inputStream, this.defaultCharset);
} }
/** /**
* Add the content of a {@link ConfigurationMetadataRepository} defined by the specified * Add the content of a {@link ConfigurationMetadataRepository} defined by the
* {@link InputStream} json document using the specified {@link Charset}. If this metadata * specified {@link InputStream} json document using the specified {@link Charset}. If
* repository holds items that were loaded previously, these are ignored. * this metadata repository holds items that were loaded previously, these are
* <p>Leave the stream open when done. * ignored.
* <p>
* Leaves the stream open when done.
* @param inputstream the source input stream
* @param charset the charset of the input
* @return this builder
* @throws IOException
*/ */
public ConfigurationMetadataRepositoryJsonBuilder withJsonResource(InputStream inputstream, Charset charset) public ConfigurationMetadataRepositoryJsonBuilder withJsonResource(
throws IOException { InputStream inputstream, Charset charset) throws IOException {
if (inputstream == null) { if (inputstream == null) {
throw new IllegalArgumentException("InputStream must not be null."); throw new IllegalArgumentException("InputStream must not be null.");
} }
repositories.add(add(inputstream, charset)); this.repositories.add(add(inputstream, charset));
return this; return this;
} }
/** /**
* Build a {@link ConfigurationMetadataRepository} with the current state of this builder. * Build a {@link ConfigurationMetadataRepository} with the current state of this
* builder.
* @return this builder
*/ */
public ConfigurationMetadataRepository build() { public ConfigurationMetadataRepository build() {
SimpleConfigurationMetadataRepository result = new SimpleConfigurationMetadataRepository(); SimpleConfigurationMetadataRepository result = new SimpleConfigurationMetadataRepository();
for (SimpleConfigurationMetadataRepository repository : repositories) { for (SimpleConfigurationMetadataRepository repository : this.repositories) {
result.include(repository); result.include(repository);
} }
return result; return result;
} }
private SimpleConfigurationMetadataRepository add(InputStream in, Charset charset) throws IOException { private SimpleConfigurationMetadataRepository add(InputStream in, Charset charset)
throws IOException {
try { try {
RawConfigurationMetadata metadata = this.reader.read(in, charset); RawConfigurationMetadata metadata = this.reader.read(in, charset);
return create(metadata); return create(metadata);
} }
catch (IOException e) { catch (IOException ex) {
throw new IllegalArgumentException("Failed to read configuration metadata", e); throw new IllegalArgumentException("Failed to read configuration "
+ "metadata", ex);
} }
catch (JSONException e) { catch (JSONException ex) {
throw new IllegalArgumentException("Invalid configuration metadata document", e); throw new IllegalArgumentException("Invalid configuration "
+ "metadata document", ex);
} }
} }
...@@ -115,14 +115,11 @@ public class ConfigurationMetadataRepositoryJsonBuilder { ...@@ -115,14 +115,11 @@ public class ConfigurationMetadataRepositoryJsonBuilder {
SimpleConfigurationMetadataRepository repository = new SimpleConfigurationMetadataRepository(); SimpleConfigurationMetadataRepository repository = new SimpleConfigurationMetadataRepository();
repository.add(metadata.getSources()); repository.add(metadata.getSources());
for (ConfigurationMetadataItem item : metadata.getItems()) { for (ConfigurationMetadataItem item : metadata.getItems()) {
ConfigurationMetadataSource source = null; ConfigurationMetadataSource source = getSource(metadata, item);
String sourceType = item.getSourceType();
if (sourceType != null) {
source = metadata.getSource(sourceType);
}
repository.add(item, source); repository.add(item, source);
} }
Map<String, ConfigurationMetadataProperty> allProperties = repository.getAllProperties(); Map<String, ConfigurationMetadataProperty> allProperties = repository
.getAllProperties();
for (ConfigurationMetadataHint hint : metadata.getHints()) { for (ConfigurationMetadataHint hint : metadata.getHints()) {
ConfigurationMetadataProperty property = allProperties.get(hint.getId()); ConfigurationMetadataProperty property = allProperties.get(hint.getId());
if (property != null) { if (property != null) {
...@@ -133,5 +130,45 @@ public class ConfigurationMetadataRepositoryJsonBuilder { ...@@ -133,5 +130,45 @@ public class ConfigurationMetadataRepositoryJsonBuilder {
return repository; return repository;
} }
} private ConfigurationMetadataSource getSource(RawConfigurationMetadata metadata,
ConfigurationMetadataItem item) {
if (item.getSourceType() != null) {
return metadata.getSource(item.getSourceType());
}
return null;
}
/**
* Create a new builder instance using {@link #UTF_8} as the default charset and the
* specified json resource.
* @param inputStreams the source input streams
* @return a new {@link ConfigurationMetadataRepositoryJsonBuilder} instance.
* @throws IOException on error
*/
public static ConfigurationMetadataRepositoryJsonBuilder create(
InputStream... inputStreams) throws IOException {
ConfigurationMetadataRepositoryJsonBuilder builder = create();
for (InputStream inputStream : inputStreams) {
builder = builder.withJsonResource(inputStream);
}
return builder;
}
/**
* Create a new builder instance using {@link #UTF_8} as the default charset.
* @return a new {@link ConfigurationMetadataRepositoryJsonBuilder} instance.
*/
public static ConfigurationMetadataRepositoryJsonBuilder create() {
return create(UTF_8);
}
/**
* Create a new builder instance using the specified default {@link Charset}.
* @param defaultCharset the default charset to use
* @return a new {@link ConfigurationMetadataRepositoryJsonBuilder} instance.
*/
public static ConfigurationMetadataRepositoryJsonBuilder create(Charset defaultCharset) {
return new ConfigurationMetadataRepositoryJsonBuilder(defaultCharset);
}
}
/* /*
* Copyright 2012-2014 the original author or authors. * Copyright 2012-2015 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -20,8 +20,8 @@ import java.util.HashMap; ...@@ -20,8 +20,8 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
/** /**
* A source of configuration metadata. Also defines where the source is declared, * A source of configuration metadata. Also defines where the source is declared, for
* for instance if it is defined as a {@code @Bean}. * instance if it is defined as a {@code @Bean}.
* *
* @author Stephane Nicoll * @author Stephane Nicoll
* @since 1.3.0 * @since 1.3.0
...@@ -40,11 +40,11 @@ public class ConfigurationMetadataSource { ...@@ -40,11 +40,11 @@ public class ConfigurationMetadataSource {
private String sourceMethod; private String sourceMethod;
private final Map<String, ConfigurationMetadataProperty> properties private final Map<String, ConfigurationMetadataProperty> properties = new HashMap<String, ConfigurationMetadataProperty>();
= new HashMap<String, ConfigurationMetadataProperty>();
/** /**
* The identifier of the group to which this source is associated * The identifier of the group to which this source is associated
* @return the group id
*/ */
public String getGroupId() { public String getGroupId() {
return this.groupId; return this.groupId;
...@@ -55,9 +55,9 @@ public class ConfigurationMetadataSource { ...@@ -55,9 +55,9 @@ public class ConfigurationMetadataSource {
} }
/** /**
* The type of the source. Usually this is the fully qualified name of a * The type of the source. Usually this is the fully qualified name of a class that
* class that defines configuration items. This class may or may not be * defines configuration items. This class may or may not be available at runtime.
* available at runtime. * @return the type
*/ */
public String getType() { public String getType() {
return this.type; return this.type;
...@@ -69,6 +69,7 @@ public class ConfigurationMetadataSource { ...@@ -69,6 +69,7 @@ public class ConfigurationMetadataSource {
/** /**
* A description of this source, if any. Can be multi-lines. * A description of this source, if any. Can be multi-lines.
* @return the description
* @see #getShortDescription() * @see #getShortDescription()
*/ */
public String getDescription() { public String getDescription() {
...@@ -81,10 +82,11 @@ public class ConfigurationMetadataSource { ...@@ -81,10 +82,11 @@ public class ConfigurationMetadataSource {
/** /**
* A single-line, single-sentence description of this source, if any. * A single-line, single-sentence description of this source, if any.
* @return the short description
* @see #getDescription() * @see #getDescription()
*/ */
public String getShortDescription() { public String getShortDescription() {
return shortDescription; return this.shortDescription;
} }
public void setShortDescription(String shortDescription) { public void setShortDescription(String shortDescription) {
...@@ -92,8 +94,9 @@ public class ConfigurationMetadataSource { ...@@ -92,8 +94,9 @@ public class ConfigurationMetadataSource {
} }
/** /**
* The type where this source is defined. This can be identical * The type where this source is defined. This can be identical to the
* to the {@link #getType() type} if the source is self-defined. * {@link #getType() type} if the source is self-defined.
* @return the source type
*/ */
public String getSourceType() { public String getSourceType() {
return this.sourceType; return this.sourceType;
...@@ -105,6 +108,7 @@ public class ConfigurationMetadataSource { ...@@ -105,6 +108,7 @@ public class ConfigurationMetadataSource {
/** /**
* The method name that defines this source, if any. * The method name that defines this source, if any.
* @return the source method
*/ */
public String getSourceMethod() { public String getSourceMethod() {
return this.sourceMethod; return this.sourceMethod;
...@@ -116,6 +120,7 @@ public class ConfigurationMetadataSource { ...@@ -116,6 +120,7 @@ public class ConfigurationMetadataSource {
/** /**
* Return the properties defined by this source. * Return the properties defined by this source.
* @return the properties
*/ */
public Map<String, ConfigurationMetadataProperty> getProperties() { public Map<String, ConfigurationMetadataProperty> getProperties() {
return this.properties; return this.properties;
......
/*
* Copyright 2012-2015 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
*
* http://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.configurationmetadata;
import java.text.BreakIterator;
import java.util.Locale;
/**
* Utility to extract a descriptions.
*
* @author Stephane Nicoll
*/
class DescriptionExtractor {
private static final String NEW_LINE = System.getProperty("line.separator");
public String getShortDescription(String description) {
if (description == null) {
return null;
}
int dot = description.indexOf(".");
if (dot != -1) {
BreakIterator breakIterator = BreakIterator.getSentenceInstance(Locale.US);
breakIterator.setText(description);
String text = description.substring(breakIterator.first(),
breakIterator.next()).trim();
return removeSpaceBetweenLine(text);
}
else {
String[] lines = description.split(NEW_LINE);
return lines[0].trim();
}
}
private String removeSpaceBetweenLine(String text) {
String[] lines = text.split(NEW_LINE);
StringBuilder sb = new StringBuilder();
for (String line : lines) {
sb.append(line.trim()).append(" ");
}
return sb.toString().trim();
}
}
/* /*
* Copyright 2012-2014 the original author or authors. * Copyright 2012-2015 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -20,11 +20,9 @@ import java.io.IOException; ...@@ -20,11 +20,9 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.text.BreakIterator;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Locale;
import org.json.JSONArray; import org.json.JSONArray;
import org.json.JSONObject; import org.json.JSONObject;
...@@ -39,9 +37,10 @@ class JsonReader { ...@@ -39,9 +37,10 @@ class JsonReader {
private static final int BUFFER_SIZE = 4096; private static final int BUFFER_SIZE = 4096;
private static final String NEW_LINE = System.getProperty("line.separator"); private final DescriptionExtractor descriptionExtractor = new DescriptionExtractor();
public RawConfigurationMetadata read(InputStream in, Charset charset) throws IOException { public RawConfigurationMetadata read(InputStream in, Charset charset)
throws IOException {
JSONObject json = readJson(in, charset); JSONObject json = readJson(in, charset);
List<ConfigurationMetadataSource> groups = parseAllSources(json); List<ConfigurationMetadataSource> groups = parseAllSources(json);
List<ConfigurationMetadataItem> items = parseAllItems(json); List<ConfigurationMetadataItem> items = parseAllItems(json);
...@@ -94,7 +93,8 @@ class JsonReader { ...@@ -94,7 +93,8 @@ class JsonReader {
source.setType(json.optString("type", null)); source.setType(json.optString("type", null));
String description = json.optString("description", null); String description = json.optString("description", null);
source.setDescription(description); source.setDescription(description);
source.setShortDescription(extractShortDescription(description)); source.setShortDescription(this.descriptionExtractor
.getShortDescription(description));
source.setSourceType(json.optString("sourceType", null)); source.setSourceType(json.optString("sourceType", null));
source.setSourceMethod(json.optString("sourceMethod", null)); source.setSourceMethod(json.optString("sourceMethod", null));
return source; return source;
...@@ -106,7 +106,8 @@ class JsonReader { ...@@ -106,7 +106,8 @@ class JsonReader {
item.setType(json.optString("type", null)); item.setType(json.optString("type", null));
String description = json.optString("description", null); String description = json.optString("description", null);
item.setDescription(description); item.setDescription(description);
item.setShortDescription(extractShortDescription(description)); item.setShortDescription(this.descriptionExtractor
.getShortDescription(description));
item.setDefaultValue(readItemValue(json.opt("defaultValue"))); item.setDefaultValue(readItemValue(json.opt("defaultValue")));
item.setDeprecated(json.optBoolean("deprecated", false)); item.setDeprecated(json.optBoolean("deprecated", false));
item.setSourceType(json.optString("sourceType", null)); item.setSourceType(json.optString("sourceType", null));
...@@ -125,7 +126,8 @@ class JsonReader { ...@@ -125,7 +126,8 @@ class JsonReader {
valueHint.setValue(readItemValue(value.get("value"))); valueHint.setValue(readItemValue(value.get("value")));
String description = value.optString("description", null); String description = value.optString("description", null);
valueHint.setDescription(description); valueHint.setDescription(description);
valueHint.setShortDescription(extractShortDescription(description)); valueHint.setShortDescription(this.descriptionExtractor
.getShortDescription(description));
hint.getValueHints().add(valueHint); hint.getValueHints().add(valueHint);
} }
} }
...@@ -140,7 +142,8 @@ class JsonReader { ...@@ -140,7 +142,8 @@ class JsonReader {
Iterator<?> keys = parameters.keys(); Iterator<?> keys = parameters.keys();
while (keys.hasNext()) { while (keys.hasNext()) {
String key = (String) keys.next(); String key = (String) keys.next();
valueProvider.getParameters().put(key, readItemValue(parameters.get(key))); valueProvider.getParameters().put(key,
readItemValue(parameters.get(key)));
} }
} }
hint.getValueProviders().add(valueProvider); hint.getValueProviders().add(valueProvider);
...@@ -161,32 +164,6 @@ class JsonReader { ...@@ -161,32 +164,6 @@ class JsonReader {
return value; return value;
} }
static String extractShortDescription(String description) {
if (description == null) {
return null;
}
int dot = description.indexOf(".");
if (dot != -1) {
BreakIterator breakIterator = BreakIterator.getSentenceInstance(Locale.US);
breakIterator.setText(description);
String text = description.substring(breakIterator.first(), breakIterator.next()).trim();
return removeSpaceBetweenLine(text);
}
else {
String[] lines = description.split(NEW_LINE);
return lines[0].trim();
}
}
private static String removeSpaceBetweenLine(String text) {
String[] lines = text.split(NEW_LINE);
StringBuilder sb = new StringBuilder();
for (String line : lines) {
sb.append(line.trim()).append(" ");
}
return sb.toString().trim();
}
private JSONObject readJson(InputStream in, Charset charset) throws IOException { private JSONObject readJson(InputStream in, Charset charset) throws IOException {
try { try {
StringBuilder out = new StringBuilder(); StringBuilder out = new StringBuilder();
......
/* /*
* Copyright 2012-2014 the original author or authors. * Copyright 2012-2015 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -61,7 +61,7 @@ class RawConfigurationMetadata { ...@@ -61,7 +61,7 @@ class RawConfigurationMetadata {
} }
public List<ConfigurationMetadataHint> getHints() { public List<ConfigurationMetadataHint> getHints() {
return hints; return this.hints;
} }
/** /**
......
/* /*
* Copyright 2012-2014 the original author or authors. * Copyright 2012-2015 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -27,7 +27,8 @@ import java.util.Map; ...@@ -27,7 +27,8 @@ import java.util.Map;
* @author Stephane Nicoll * @author Stephane Nicoll
* @since 1.3.0 * @since 1.3.0
*/ */
public class SimpleConfigurationMetadataRepository implements ConfigurationMetadataRepository { public class SimpleConfigurationMetadataRepository implements
ConfigurationMetadataRepository {
private final Map<String, ConfigurationMetadataGroup> allGroups = new HashMap<String, ConfigurationMetadataGroup>(); private final Map<String, ConfigurationMetadataGroup> allGroups = new HashMap<String, ConfigurationMetadataGroup>();
...@@ -47,6 +48,7 @@ public class SimpleConfigurationMetadataRepository implements ConfigurationMetad ...@@ -47,6 +48,7 @@ public class SimpleConfigurationMetadataRepository implements ConfigurationMetad
/** /**
* Register the specified {@link ConfigurationMetadataSource sources}. * Register the specified {@link ConfigurationMetadataSource sources}.
* @param sources the sources to add
*/ */
public void add(Collection<ConfigurationMetadataSource> sources) { public void add(Collection<ConfigurationMetadataSource> sources) {
for (ConfigurationMetadataSource source : sources) { for (ConfigurationMetadataSource source : sources) {
...@@ -64,19 +66,22 @@ public class SimpleConfigurationMetadataRepository implements ConfigurationMetad ...@@ -64,19 +66,22 @@ public class SimpleConfigurationMetadataRepository implements ConfigurationMetad
} }
/** /**
* Add a {@link ConfigurationMetadataProperty} with the {@link ConfigurationMetadataSource source} * Add a {@link ConfigurationMetadataProperty} with the
* that defines it, if any. * {@link ConfigurationMetadataSource source} that defines it, if any.
* @param property the property to add
* @param source the source
*/ */
public void add(ConfigurationMetadataProperty property, ConfigurationMetadataSource source) { public void add(ConfigurationMetadataProperty property,
ConfigurationMetadataSource source) {
if (source != null) { if (source != null) {
putIfAbsent(source.getProperties(), property.getId(), property); putIfAbsent(source.getProperties(), property.getId(), property);
} }
putIfAbsent(getGroup(source).getProperties(), property.getId(), property); putIfAbsent(getGroup(source).getProperties(), property.getId(), property);
} }
/** /**
* Merge the content of the specified repository to this repository. * Merge the content of the specified repository to this repository.
* @param repository the repository to include
*/ */
public void include(ConfigurationMetadataRepository repository) { public void include(ConfigurationMetadataRepository repository) {
for (ConfigurationMetadataGroup group : repository.getAllGroups().values()) { for (ConfigurationMetadataGroup group : repository.getAllGroups().values()) {
...@@ -86,12 +91,16 @@ public class SimpleConfigurationMetadataRepository implements ConfigurationMetad ...@@ -86,12 +91,16 @@ public class SimpleConfigurationMetadataRepository implements ConfigurationMetad
} }
else { else {
// Merge properties // Merge properties
for (Map.Entry<String, ConfigurationMetadataProperty> entry : group.getProperties().entrySet()) { for (Map.Entry<String, ConfigurationMetadataProperty> entry : group
putIfAbsent(existingGroup.getProperties(), entry.getKey(), entry.getValue()); .getProperties().entrySet()) {
putIfAbsent(existingGroup.getProperties(), entry.getKey(),
entry.getValue());
} }
// Merge sources // Merge sources
for (Map.Entry<String, ConfigurationMetadataSource> entry : group.getSources().entrySet()) { for (Map.Entry<String, ConfigurationMetadataSource> entry : group
putIfAbsent(existingGroup.getSources(), entry.getKey(), entry.getValue()); .getSources().entrySet()) {
putIfAbsent(existingGroup.getSources(), entry.getKey(),
entry.getValue());
} }
} }
} }
...@@ -107,9 +116,7 @@ public class SimpleConfigurationMetadataRepository implements ConfigurationMetad ...@@ -107,9 +116,7 @@ public class SimpleConfigurationMetadataRepository implements ConfigurationMetad
} }
return rootGroup; return rootGroup;
} }
else { return this.allGroups.get(source.getGroupId());
return this.allGroups.get(source.getGroupId());
}
} }
private <V> void putIfAbsent(Map<String, V> map, String key, V value) { private <V> void putIfAbsent(Map<String, V> map, String key, V value) {
......
/*
* Copyright 2012-2015 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
*
* http://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.configurationmetadata; package org.springframework.boot.configurationmetadata;
/** /**
* Hint for a value a given property may have. Provide the value and * Hint for a value a given property may have. Provide the value and an optional
* an optional description. * description.
* *
* @author Stephane Nicoll * @author Stephane Nicoll
* @since 1.3.0 * @since 1.3.0
...@@ -17,9 +33,10 @@ public class ValueHint { ...@@ -17,9 +33,10 @@ public class ValueHint {
/** /**
* Return the hint value. * Return the hint value.
* @return the value
*/ */
public Object getValue() { public Object getValue() {
return value; return this.value;
} }
public void setValue(Object value) { public void setValue(Object value) {
...@@ -28,10 +45,11 @@ public class ValueHint { ...@@ -28,10 +45,11 @@ public class ValueHint {
/** /**
* A description of this value, if any. Can be multi-lines. * A description of this value, if any. Can be multi-lines.
* @return the description
* @see #getShortDescription() * @see #getShortDescription()
*/ */
public String getDescription() { public String getDescription() {
return description; return this.description;
} }
public void setDescription(String description) { public void setDescription(String description) {
...@@ -40,10 +58,11 @@ public class ValueHint { ...@@ -40,10 +58,11 @@ public class ValueHint {
/** /**
* A single-line, single-sentence description of this hint, if any. * A single-line, single-sentence description of this hint, if any.
* @return the short description
* @see #getDescription() * @see #getDescription()
*/ */
public String getShortDescription() { public String getShortDescription() {
return shortDescription; return this.shortDescription;
} }
public void setShortDescription(String shortDescription) { public void setShortDescription(String shortDescription) {
......
/*
* Copyright 2012-2015 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
*
* http://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.configurationmetadata; package org.springframework.boot.configurationmetadata;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
...@@ -6,9 +22,9 @@ import java.util.Map; ...@@ -6,9 +22,9 @@ import java.util.Map;
/** /**
* Define a component that is able to provide the values of a property. * Define a component that is able to provide the values of a property.
* <p> * <p>
* Each provider is defined by a {@code name} and can have an arbitrary * Each provider is defined by a {@code name} and can have an arbitrary number of
* number of {@code parameters}. The available providers are defined in * {@code parameters}. The available providers are defined in the Spring Boot
* the Spring Boot documentation. * documentation.
* *
* @author Stephane Nicoll * @author Stephane Nicoll
* @since 1.3.0 * @since 1.3.0
...@@ -21,9 +37,10 @@ public class ValueProvider { ...@@ -21,9 +37,10 @@ public class ValueProvider {
/** /**
* Return the name of the provider. * Return the name of the provider.
* @return the name
*/ */
public String getName() { public String getName() {
return name; return this.name;
} }
public void setName(String name) { public void setName(String name) {
...@@ -32,15 +49,16 @@ public class ValueProvider { ...@@ -32,15 +49,16 @@ public class ValueProvider {
/** /**
* Return the parameters. * Return the parameters.
* @return the parameters
*/ */
public Map<String, Object> getParameters() { public Map<String, Object> getParameters() {
return parameters; return this.parameters;
} }
@Override @Override
public String toString() { public String toString() {
return "ValueProvider{" + "name='" + this.name + ", parameters=" + this.parameters + return "ValueProvider{" + "name='" + this.name + ", parameters="
'}'; + this.parameters + '}';
} }
} }
/* /*
* Copyright 2012-2014 the original author or authors. * Copyright 2012-2015 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -21,7 +21,6 @@ import java.io.InputStream; ...@@ -21,7 +21,6 @@ import java.io.InputStream;
import org.junit.Rule; import org.junit.Rule;
import org.junit.rules.ExpectedException; import org.junit.rules.ExpectedException;
import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource; import org.springframework.core.io.Resource;
...@@ -29,6 +28,7 @@ import static org.junit.Assert.assertEquals; ...@@ -29,6 +28,7 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
/** /**
* Base for configuration meta-data tests.
* *
* @author Stephane Nicoll * @author Stephane Nicoll
*/ */
...@@ -37,15 +37,16 @@ public abstract class AbstractConfigurationMetadataTests { ...@@ -37,15 +37,16 @@ public abstract class AbstractConfigurationMetadataTests {
@Rule @Rule
public final ExpectedException thrown = ExpectedException.none(); public final ExpectedException thrown = ExpectedException.none();
protected void assertSource(ConfigurationMetadataSource actual, String groupId, String type, String sourceType) { protected void assertSource(ConfigurationMetadataSource actual, String groupId,
String type, String sourceType) {
assertNotNull(actual); assertNotNull(actual);
assertEquals(groupId, actual.getGroupId()); assertEquals(groupId, actual.getGroupId());
assertEquals(type, actual.getType()); assertEquals(type, actual.getType());
assertEquals(sourceType, actual.getSourceType()); assertEquals(sourceType, actual.getSourceType());
} }
protected void assertProperty(ConfigurationMetadataProperty actual, String id, String name, protected void assertProperty(ConfigurationMetadataProperty actual, String id,
Class<?> type, Object defaultValue) { String name, Class<?> type, Object defaultValue) {
assertNotNull(actual); assertNotNull(actual);
assertEquals(id, actual.getId()); assertEquals(id, actual.getId());
assertEquals(name, actual.getName()); assertEquals(name, actual.getName());
...@@ -60,7 +61,9 @@ public abstract class AbstractConfigurationMetadataTests { ...@@ -60,7 +61,9 @@ public abstract class AbstractConfigurationMetadataTests {
} }
protected InputStream getInputStreamFor(String name) throws IOException { protected InputStream getInputStreamFor(String name) throws IOException {
Resource r = new ClassPathResource("metadata/configuration-metadata-" + name + ".json"); Resource r = new ClassPathResource("metadata/configuration-metadata-" + name
+ ".json");
return r.getInputStream(); return r.getInputStream();
} }
} }
/* /*
* Copyright 2012-2014 the original author or authors. * Copyright 2012-2015 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -31,12 +31,12 @@ import static org.junit.Assert.assertTrue; ...@@ -31,12 +31,12 @@ import static org.junit.Assert.assertTrue;
* *
* @author Stephane Nicoll * @author Stephane Nicoll
*/ */
public class ConfigurationMetadataRepositoryJsonBuilderTests extends AbstractConfigurationMetadataTests { public class ConfigurationMetadataRepositoryJsonBuilderTests extends
AbstractConfigurationMetadataTests {
@Test @Test
public void nullResource() throws IOException { public void nullResource() throws IOException {
thrown.expect(IllegalArgumentException.class); this.thrown.expect(IllegalArgumentException.class);
ConfigurationMetadataRepositoryJsonBuilder.create().withJsonResource(null); ConfigurationMetadataRepositoryJsonBuilder.create().withJsonResource(null);
} }
...@@ -44,13 +44,12 @@ public class ConfigurationMetadataRepositoryJsonBuilderTests extends AbstractCon ...@@ -44,13 +44,12 @@ public class ConfigurationMetadataRepositoryJsonBuilderTests extends AbstractCon
public void simpleRepository() throws IOException { public void simpleRepository() throws IOException {
InputStream foo = getInputStreamFor("foo"); InputStream foo = getInputStreamFor("foo");
try { try {
ConfigurationMetadataRepository repo = ConfigurationMetadataRepositoryJsonBuilder.create() ConfigurationMetadataRepository repo = ConfigurationMetadataRepositoryJsonBuilder
.withJsonResource(foo) .create(foo).build();
.build();
validateFoo(repo); validateFoo(repo);
assertEquals(1, repo.getAllGroups().size()); assertEquals(1, repo.getAllGroups().size());
contains(repo.getAllProperties(), "spring.foo.name",
contains(repo.getAllProperties(), "spring.foo.name", "spring.foo.description", "spring.foo.counter"); "spring.foo.description", "spring.foo.counter");
assertEquals(3, repo.getAllProperties().size()); assertEquals(3, repo.getAllProperties().size());
} }
finally { finally {
...@@ -63,16 +62,14 @@ public class ConfigurationMetadataRepositoryJsonBuilderTests extends AbstractCon ...@@ -63,16 +62,14 @@ public class ConfigurationMetadataRepositoryJsonBuilderTests extends AbstractCon
InputStream foo = getInputStreamFor("foo"); InputStream foo = getInputStreamFor("foo");
InputStream bar = getInputStreamFor("bar"); InputStream bar = getInputStreamFor("bar");
try { try {
ConfigurationMetadataRepository repo = ConfigurationMetadataRepositoryJsonBuilder.create() ConfigurationMetadataRepository repo = ConfigurationMetadataRepositoryJsonBuilder
.withJsonResource(foo) .create(foo, bar).build();
.withJsonResource(bar)
.build();
validateFoo(repo); validateFoo(repo);
validateBar(repo); validateBar(repo);
assertEquals(2, repo.getAllGroups().size()); assertEquals(2, repo.getAllGroups().size());
contains(repo.getAllProperties(), "spring.foo.name",
contains(repo.getAllProperties(), "spring.foo.name", "spring.foo.description", "spring.foo.counter", "spring.foo.description", "spring.foo.counter", "spring.bar.name",
"spring.bar.name", "spring.bar.description", "spring.bar.counter"); "spring.bar.description", "spring.bar.counter");
assertEquals(6, repo.getAllProperties().size()); assertEquals(6, repo.getAllProperties().size());
} }
finally { finally {
...@@ -86,15 +83,14 @@ public class ConfigurationMetadataRepositoryJsonBuilderTests extends AbstractCon ...@@ -86,15 +83,14 @@ public class ConfigurationMetadataRepositoryJsonBuilderTests extends AbstractCon
InputStream foo = getInputStreamFor("foo"); InputStream foo = getInputStreamFor("foo");
InputStream root = getInputStreamFor("root"); InputStream root = getInputStreamFor("root");
try { try {
ConfigurationMetadataRepository repo = ConfigurationMetadataRepositoryJsonBuilder.create() ConfigurationMetadataRepository repo = ConfigurationMetadataRepositoryJsonBuilder
.withJsonResource(foo) .create(foo, root).build();
.withJsonResource(root)
.build();
validateFoo(repo); validateFoo(repo);
assertEquals(2, repo.getAllGroups().size()); assertEquals(2, repo.getAllGroups().size());
contains(repo.getAllProperties(), "spring.foo.name", "spring.foo.description", "spring.foo.counter", contains(repo.getAllProperties(), "spring.foo.name",
"spring.root.name", "spring.root2.name"); "spring.foo.description", "spring.foo.counter", "spring.root.name",
"spring.root2.name");
assertEquals(5, repo.getAllProperties().size()); assertEquals(5, repo.getAllProperties().size());
} }
finally { finally {
...@@ -108,19 +104,19 @@ public class ConfigurationMetadataRepositoryJsonBuilderTests extends AbstractCon ...@@ -108,19 +104,19 @@ public class ConfigurationMetadataRepositoryJsonBuilderTests extends AbstractCon
InputStream foo = getInputStreamFor("foo"); InputStream foo = getInputStreamFor("foo");
InputStream foo2 = getInputStreamFor("foo2"); InputStream foo2 = getInputStreamFor("foo2");
try { try {
ConfigurationMetadataRepository repo = ConfigurationMetadataRepositoryJsonBuilder.create() ConfigurationMetadataRepository repo = ConfigurationMetadataRepositoryJsonBuilder
.withJsonResource(foo) .create(foo, foo2).build();
.withJsonResource(foo2)
.build();
assertEquals(1, repo.getAllGroups().size()); assertEquals(1, repo.getAllGroups().size());
ConfigurationMetadataGroup group = repo.getAllGroups().get("spring.foo"); ConfigurationMetadataGroup group = repo.getAllGroups().get("spring.foo");
contains(group.getSources(), "org.acme.Foo", "org.acme.Foo2", "org.springframework.boot.FooProperties"); contains(group.getSources(), "org.acme.Foo", "org.acme.Foo2",
"org.springframework.boot.FooProperties");
assertEquals(3, group.getSources().size()); assertEquals(3, group.getSources().size());
contains(group.getProperties(), "spring.foo.name", "spring.foo.description", "spring.foo.counter", contains(group.getProperties(), "spring.foo.name", "spring.foo.description",
"spring.foo.enabled", "spring.foo.type"); "spring.foo.counter", "spring.foo.enabled", "spring.foo.type");
assertEquals(5, group.getProperties().size()); assertEquals(5, group.getProperties().size());
contains(repo.getAllProperties(), "spring.foo.name", "spring.foo.description", "spring.foo.counter", contains(repo.getAllProperties(), "spring.foo.name",
"spring.foo.enabled", "spring.foo.type"); "spring.foo.description", "spring.foo.counter", "spring.foo.enabled",
"spring.foo.type");
assertEquals(5, repo.getAllProperties().size()); assertEquals(5, repo.getAllProperties().size());
} }
finally { finally {
...@@ -134,18 +130,15 @@ public class ConfigurationMetadataRepositoryJsonBuilderTests extends AbstractCon ...@@ -134,18 +130,15 @@ public class ConfigurationMetadataRepositoryJsonBuilderTests extends AbstractCon
InputStream foo = getInputStreamFor("foo"); InputStream foo = getInputStreamFor("foo");
InputStream bar = getInputStreamFor("bar"); InputStream bar = getInputStreamFor("bar");
try { try {
ConfigurationMetadataRepositoryJsonBuilder builder = ConfigurationMetadataRepositoryJsonBuilder.create(); ConfigurationMetadataRepositoryJsonBuilder builder = ConfigurationMetadataRepositoryJsonBuilder
ConfigurationMetadataRepository firstRepo = builder .create();
.withJsonResource(foo) ConfigurationMetadataRepository firstRepo = builder.withJsonResource(foo)
.build(); .build();
validateFoo(firstRepo); validateFoo(firstRepo);
ConfigurationMetadataRepository secondRepo = builder.withJsonResource(bar)
ConfigurationMetadataRepository secondRepo = builder
.withJsonResource(bar)
.build(); .build();
validateFoo(secondRepo); validateFoo(secondRepo);
validateBar(secondRepo); validateBar(secondRepo);
// first repo not impacted by second build // first repo not impacted by second build
assertNotEquals(firstRepo, secondRepo); assertNotEquals(firstRepo, secondRepo);
assertEquals(1, firstRepo.getAllGroups().size()); assertEquals(1, firstRepo.getAllGroups().size());
...@@ -161,11 +154,13 @@ public class ConfigurationMetadataRepositoryJsonBuilderTests extends AbstractCon ...@@ -161,11 +154,13 @@ public class ConfigurationMetadataRepositoryJsonBuilderTests extends AbstractCon
private void validateFoo(ConfigurationMetadataRepository repo) { private void validateFoo(ConfigurationMetadataRepository repo) {
ConfigurationMetadataGroup group = repo.getAllGroups().get("spring.foo"); ConfigurationMetadataGroup group = repo.getAllGroups().get("spring.foo");
contains(group.getSources(), "org.acme.Foo", "org.springframework.boot.FooProperties"); contains(group.getSources(), "org.acme.Foo",
"org.springframework.boot.FooProperties");
ConfigurationMetadataSource source = group.getSources().get("org.acme.Foo"); ConfigurationMetadataSource source = group.getSources().get("org.acme.Foo");
contains(source.getProperties(), "spring.foo.name", "spring.foo.description"); contains(source.getProperties(), "spring.foo.name", "spring.foo.description");
assertEquals(2, source.getProperties().size()); assertEquals(2, source.getProperties().size());
ConfigurationMetadataSource source2 = group.getSources().get("org.springframework.boot.FooProperties"); ConfigurationMetadataSource source2 = group.getSources().get(
"org.springframework.boot.FooProperties");
contains(source2.getProperties(), "spring.foo.name", "spring.foo.counter"); contains(source2.getProperties(), "spring.foo.name", "spring.foo.counter");
assertEquals(2, source2.getProperties().size()); assertEquals(2, source2.getProperties().size());
validatePropertyHints(repo.getAllProperties().get("spring.foo.name"), 0, 0); validatePropertyHints(repo.getAllProperties().get("spring.foo.name"), 0, 0);
...@@ -175,11 +170,13 @@ public class ConfigurationMetadataRepositoryJsonBuilderTests extends AbstractCon ...@@ -175,11 +170,13 @@ public class ConfigurationMetadataRepositoryJsonBuilderTests extends AbstractCon
private void validateBar(ConfigurationMetadataRepository repo) { private void validateBar(ConfigurationMetadataRepository repo) {
ConfigurationMetadataGroup group = repo.getAllGroups().get("spring.bar"); ConfigurationMetadataGroup group = repo.getAllGroups().get("spring.bar");
contains(group.getSources(), "org.acme.Bar", "org.springframework.boot.BarProperties"); contains(group.getSources(), "org.acme.Bar",
"org.springframework.boot.BarProperties");
ConfigurationMetadataSource source = group.getSources().get("org.acme.Bar"); ConfigurationMetadataSource source = group.getSources().get("org.acme.Bar");
contains(source.getProperties(), "spring.bar.name", "spring.bar.description"); contains(source.getProperties(), "spring.bar.name", "spring.bar.description");
assertEquals(2, source.getProperties().size()); assertEquals(2, source.getProperties().size());
ConfigurationMetadataSource source2 = group.getSources().get("org.springframework.boot.BarProperties"); ConfigurationMetadataSource source2 = group.getSources().get(
"org.springframework.boot.BarProperties");
contains(source2.getProperties(), "spring.bar.name", "spring.bar.counter"); contains(source2.getProperties(), "spring.bar.name", "spring.bar.counter");
assertEquals(2, source2.getProperties().size()); assertEquals(2, source2.getProperties().size());
validatePropertyHints(repo.getAllProperties().get("spring.bar.name"), 0, 0); validatePropertyHints(repo.getAllProperties().get("spring.bar.name"), 0, 0);
...@@ -187,14 +184,17 @@ public class ConfigurationMetadataRepositoryJsonBuilderTests extends AbstractCon ...@@ -187,14 +184,17 @@ public class ConfigurationMetadataRepositoryJsonBuilderTests extends AbstractCon
validatePropertyHints(repo.getAllProperties().get("spring.bar.counter"), 0, 0); validatePropertyHints(repo.getAllProperties().get("spring.bar.counter"), 0, 0);
} }
private void validatePropertyHints(ConfigurationMetadataProperty property, int valueHints, int valueProviders) { private void validatePropertyHints(ConfigurationMetadataProperty property,
int valueHints, int valueProviders) {
assertEquals(valueHints, property.getValueHints().size()); assertEquals(valueHints, property.getValueHints().size());
assertEquals(valueProviders, property.getValueHints().size()); assertEquals(valueProviders, property.getValueHints().size());
} }
private void contains(Map<String, ?> source, String... keys) { private void contains(Map<String, ?> source, String... keys) {
for (String key : keys) { for (String key : keys) {
assertTrue("Item '" + key + "' not found. Got " + source.keySet(), source.containsKey(key)); assertTrue("Item '" + key + "' not found. Got " + source.keySet(),
source.containsKey(key));
} }
} }
} }
/*
* Copyright 2012-2015 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
*
* http://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.configurationmetadata;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
/**
* Tests for {@link DescriptionExtractor}.
*
* @author Stephane Nicoll
*/
public class DescriptionExtractorTests {
private DescriptionExtractor extractor = new DescriptionExtractor();
@Test
public void extractShortDescription() {
assertEquals("My short description.",
this.extractor.getShortDescription("My short description. More stuff."));
}
@Test
public void extractShortDescriptionNewLineBeforeDot() {
assertEquals("My short description.",
this.extractor.getShortDescription("My short\ndescription.\nMore stuff."));
}
@Test
public void extractShortDescriptionNewLineBeforeDotWithSpaces() {
assertEquals("My short description.",
this.extractor
.getShortDescription("My short \n description. \nMore stuff."));
}
@Test
public void extractShortDescriptionNoDot() {
assertEquals("My short description",
this.extractor.getShortDescription("My short description"));
}
@Test
public void extractShortDescriptionNoDotMultipleLines() {
assertEquals("My short description",
this.extractor.getShortDescription("My short description \n More stuff"));
}
@Test
public void extractShortDescriptionNull() {
assertEquals(null, this.extractor.getShortDescription(null));
}
}
/* /*
* Copyright 2012-2014 the original author or authors. * Copyright 2012-2015 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -46,7 +46,7 @@ public class JsonReaderTests extends AbstractConfigurationMetadataTests { ...@@ -46,7 +46,7 @@ public class JsonReaderTests extends AbstractConfigurationMetadataTests {
@Test @Test
public void invalidMetadata() throws IOException { public void invalidMetadata() throws IOException {
thrown.expect(JSONException.class); this.thrown.expect(JSONException.class);
readFor("invalid"); readFor("invalid");
} }
...@@ -70,7 +70,8 @@ public class JsonReaderTests extends AbstractConfigurationMetadataTests { ...@@ -70,7 +70,8 @@ public class JsonReaderTests extends AbstractConfigurationMetadataTests {
assertProperty(item, "spring.foo.name", "name", String.class, null); assertProperty(item, "spring.foo.name", "name", String.class, null);
assertItem(item, "org.acme.Foo"); assertItem(item, "org.acme.Foo");
ConfigurationMetadataItem item2 = items.get(1); ConfigurationMetadataItem item2 = items.get(1);
assertProperty(item2, "spring.foo.description", "description", String.class, "FooBar"); assertProperty(item2, "spring.foo.description", "description", String.class,
"FooBar");
assertEquals("Foo description.", item2.getDescription()); assertEquals("Foo description.", item2.getDescription());
assertEquals("Foo description.", item2.getShortDescription()); assertEquals("Foo description.", item2.getShortDescription());
assertNull(item2.getSourceMethod()); assertNull(item2.getSourceMethod());
...@@ -125,46 +126,10 @@ public class JsonReaderTests extends AbstractConfigurationMetadataTests { ...@@ -125,46 +126,10 @@ public class JsonReaderTests extends AbstractConfigurationMetadataTests {
assertEquals(0, sources.size()); assertEquals(0, sources.size());
List<ConfigurationMetadataItem> items = rawMetadata.getItems(); List<ConfigurationMetadataItem> items = rawMetadata.getItems();
assertEquals(2, items.size()); assertEquals(2, items.size());
ConfigurationMetadataItem item = items.get(0); ConfigurationMetadataItem item = items.get(0);
assertProperty(item, "spring.root.name", "spring.root.name", String.class, null); assertProperty(item, "spring.root.name", "spring.root.name", String.class, null);
} }
@Test
public void extractShortDescription() {
assertEquals("My short description.", JsonReader.extractShortDescription(
"My short description. More stuff."));
}
@Test
public void extractShortDescriptionNewLineBeforeDot() {
assertEquals("My short description.", JsonReader.extractShortDescription(
"My short\ndescription.\nMore stuff."));
}
@Test
public void extractShortDescriptionNewLineBeforeDotWithSpaces() {
assertEquals("My short description.", JsonReader.extractShortDescription(
"My short \n description. \nMore stuff."));
}
@Test
public void extractShortDescriptionNoDot() {
assertEquals("My short description", JsonReader.extractShortDescription(
"My short description"));
}
@Test
public void extractShortDescriptionNoDotMultipleLines() {
assertEquals("My short description", JsonReader.extractShortDescription(
"My short description \n More stuff"));
}
@Test
public void extractShortDescriptionNull() {
assertEquals(null, JsonReader.extractShortDescription(null));
}
RawConfigurationMetadata readFor(String path) throws IOException { RawConfigurationMetadata readFor(String path) throws IOException {
return this.reader.read(getInputStreamFor(path), DEFAULT_CHARSET); return this.reader.read(getInputStreamFor(path), DEFAULT_CHARSET);
} }
......
...@@ -136,8 +136,8 @@ public class ItemHint implements Comparable<ItemHint> { ...@@ -136,8 +136,8 @@ public class ItemHint implements Comparable<ItemHint> {
@Override @Override
public String toString() { public String toString() {
return "ValueProvider{" + "name='" + this.name + "', parameters=" + this.parameters return "ValueProvider{" + "name='" + this.name + "', parameters="
+ '}'; + this.parameters + '}';
} }
} }
......
...@@ -96,37 +96,50 @@ public class JsonMarshaller { ...@@ -96,37 +96,50 @@ public class JsonMarshaller {
JSONObject jsonObject = new JSONOrderedObject(); JSONObject jsonObject = new JSONOrderedObject();
jsonObject.put("name", hint.getName()); jsonObject.put("name", hint.getName());
if (!hint.getValues().isEmpty()) { if (!hint.getValues().isEmpty()) {
JSONArray valuesArray = new JSONArray(); jsonObject.put("values", getItemHintValues(hint));
for (ItemHint.ValueHint valueHint : hint.getValues()) {
JSONObject valueObject = new JSONOrderedObject();
putHintValue(valueObject, valueHint.getValue());
putIfPresent(valueObject, "description", valueHint.getDescription());
valuesArray.put(valueObject);
}
jsonObject.put("values", valuesArray);
} }
if (!hint.getProviders().isEmpty()) { if (!hint.getProviders().isEmpty()) {
JSONArray providersArray = new JSONArray(); jsonObject.put("providers", getItemHintProviders(hint));
for (ItemHint.ValueProvider valueProvider : hint.getProviders()) {
JSONObject valueProviderObject = new JSONOrderedObject();
valueProviderObject.put("name", valueProvider.getName());
if (valueProvider.getParameters() != null
&& !valueProvider.getParameters().isEmpty()) {
JSONObject parametersObject = new JSONOrderedObject();
for (Map.Entry<String, Object> entry : valueProvider.getParameters()
.entrySet()) {
parametersObject.put(entry.getKey(),
extractItemValue(entry.getValue()));
}
valueProviderObject.put("parameters", parametersObject);
}
providersArray.put(valueProviderObject);
}
jsonObject.put("providers", providersArray);
} }
return jsonObject; return jsonObject;
} }
private JSONArray getItemHintValues(ItemHint hint) {
JSONArray values = new JSONArray();
for (ItemHint.ValueHint value : hint.getValues()) {
values.put(getItemHintValue(value));
}
return values;
}
private JSONObject getItemHintValue(ItemHint.ValueHint value) {
JSONObject result = new JSONOrderedObject();
putHintValue(result, value.getValue());
putIfPresent(result, "description", value.getDescription());
return result;
}
private JSONArray getItemHintProviders(ItemHint hint) {
JSONArray providers = new JSONArray();
for (ItemHint.ValueProvider provider : hint.getProviders()) {
providers.put(getItemHintProvider(provider));
}
return providers;
}
private JSONObject getItemHintProvider(ItemHint.ValueProvider provider) {
JSONObject result = new JSONOrderedObject();
result.put("name", provider.getName());
if (provider.getParameters() != null && !provider.getParameters().isEmpty()) {
JSONObject parameters = new JSONOrderedObject();
for (Map.Entry<String, Object> entry : provider.getParameters().entrySet()) {
parameters.put(entry.getKey(), extractItemValue(entry.getValue()));
}
result.put("parameters", parameters);
}
return result;
}
private void putIfPresent(JSONObject jsonObject, String name, Object value) { private void putIfPresent(JSONObject jsonObject, String name, Object value) {
if (value != null) { if (value != null) {
jsonObject.put(name, value); jsonObject.put(name, value);
......
...@@ -366,7 +366,8 @@ public class ConfigurationMetadataAnnotationProcessorTests { ...@@ -366,7 +366,8 @@ public class ConfigurationMetadataAnnotationProcessorTests {
writeAdditionalHints(ItemHint.newHint("simple.the-name", new ItemHint.ValueHint( writeAdditionalHints(ItemHint.newHint("simple.the-name", new ItemHint.ValueHint(
"boot", "Bla bla"), new ItemHint.ValueHint("spring", null))); "boot", "Bla bla"), new ItemHint.ValueHint("spring", null)));
ConfigurationMetadata metadata = compile(SimpleProperties.class); ConfigurationMetadata metadata = compile(SimpleProperties.class);
assertThat(metadata, assertThat(
metadata,
containsProperty("simple.the-name", String.class) containsProperty("simple.the-name", String.class)
.fromSource(SimpleProperties.class) .fromSource(SimpleProperties.class)
.withDescription("The name of this simple properties.") .withDescription("The name of this simple properties.")
...@@ -381,7 +382,8 @@ public class ConfigurationMetadataAnnotationProcessorTests { ...@@ -381,7 +382,8 @@ public class ConfigurationMetadataAnnotationProcessorTests {
writeAdditionalHints(ItemHint.newHint("simple.theName", new ItemHint.ValueHint( writeAdditionalHints(ItemHint.newHint("simple.theName", new ItemHint.ValueHint(
"boot", "Bla bla"))); "boot", "Bla bla")));
ConfigurationMetadata metadata = compile(SimpleProperties.class); ConfigurationMetadata metadata = compile(SimpleProperties.class);
assertThat(metadata, assertThat(
metadata,
containsProperty("simple.the-name", String.class) containsProperty("simple.the-name", String.class)
.fromSource(SimpleProperties.class) .fromSource(SimpleProperties.class)
.withDescription("The name of this simple properties.") .withDescription("The name of this simple properties.")
...@@ -398,7 +400,8 @@ public class ConfigurationMetadataAnnotationProcessorTests { ...@@ -398,7 +400,8 @@ public class ConfigurationMetadataAnnotationProcessorTests {
.<String, Object> singletonMap("target", "org.foo")), .<String, Object> singletonMap("target", "org.foo")),
new ItemHint.ValueProvider("second", null)))); new ItemHint.ValueProvider("second", null))));
ConfigurationMetadata metadata = compile(SimpleProperties.class); ConfigurationMetadata metadata = compile(SimpleProperties.class);
assertThat(metadata, assertThat(
metadata,
containsProperty("simple.the-name", String.class) containsProperty("simple.the-name", String.class)
.fromSource(SimpleProperties.class) .fromSource(SimpleProperties.class)
.withDescription("The name of this simple properties.") .withDescription("The name of this simple properties.")
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment