replaced code duplication with original spring boot configuration metadata implementation

This commit is contained in:
Martin Lippert
2017-02-11 16:30:11 +01:00
parent a5e9f45ea1
commit 5e61656faa
20 changed files with 25 additions and 1662 deletions

View File

@@ -1,76 +0,0 @@
/*
* 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.io.Serializable;
import java.util.HashMap;
import java.util.Map;
/**
* Gather a collection of {@link ConfigurationMetadataProperty properties} that are
* sharing a {@link #getId() common prefix}. Provide access to all the
* {@link ConfigurationMetadataSource sources} that have contributed properties to the
* group.
*
* @author Stephane Nicoll
* @since 1.3.0
*/
@SuppressWarnings("serial")
public class ConfigurationMetadataGroup implements Serializable {
private final String id;
private final Map<String, ConfigurationMetadataSource> sources = new HashMap<String, ConfigurationMetadataSource>();
private final Map<String, ConfigurationMetadataProperty> properties = new HashMap<String, ConfigurationMetadataProperty>();
public ConfigurationMetadataGroup(String id) {
this.id = id;
}
/**
* Return the id of the group, used as a common prefix for all properties associated
* to it.
* @return the id of the group
*/
public String getId() {
return this.id;
}
/**
* Return the {@link ConfigurationMetadataSource sources} defining the properties of
* this group.
* @return the sources of the group
*/
public Map<String, ConfigurationMetadataSource> getSources() {
return this.sources;
}
/**
* Return the {@link ConfigurationMetadataProperty properties} defined in this group.
* <p>
* 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()
*/
public Map<String, ConfigurationMetadataProperty> getProperties() {
return this.properties;
}
}

View File

@@ -1,74 +0,0 @@
/*
* Copyright 2012-2016 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.util.ArrayList;
import java.util.List;
/**
* A raw view of a hint used for parsing only.
*
* @author Stephane Nicoll
* @since 1.3.0
*/
class ConfigurationMetadataHint {
private static final String KEY_SUFFIX = ".keys";
private static final String VALUE_SUFFIX = ".values";
private String id;
private final List<ValueHint> valueHints = new ArrayList<ValueHint>();
private final List<ValueProvider> valueProviders = new ArrayList<ValueProvider>();
public boolean isMapKeyHints() {
return (this.id != null && this.id.endsWith(KEY_SUFFIX));
}
public boolean isMapValueHints() {
return (this.id != null && this.id.endsWith(VALUE_SUFFIX));
}
public String resolveId() {
if (isMapKeyHints()) {
return this.id.substring(0, this.id.length() - KEY_SUFFIX.length());
}
if (isMapValueHints()) {
return this.id.substring(0, this.id.length() - VALUE_SUFFIX.length());
}
return this.id;
}
public String getId() {
return this.id;
}
public void setId(String id) {
this.id = id;
}
public List<ValueHint> getValueHints() {
return this.valueHints;
}
public List<ValueProvider> getValueProviders() {
return this.valueProviders;
}
}

View File

@@ -1,60 +0,0 @@
/*
* Copyright 2012-2016 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;
/**
* An extension of {@link ConfigurationMetadataProperty} that provides a reference to its
* source.
*
* @author Stephane Nicoll
* @since 1.3.0
*/
class ConfigurationMetadataItem extends ConfigurationMetadataProperty {
private String sourceType;
private String sourceMethod;
/**
* The class name of the source that contributed this property. For example, if the
* property was from a class annotated with {@code @ConfigurationProperties} this
* attribute would contain the fully qualified name of that class.
* @return the source type
*/
public String getSourceType() {
return this.sourceType;
}
public void setSourceType(String sourceType) {
this.sourceType = sourceType;
}
/**
* The full name of the method (including parenthesis and argument types) that
* contributed this property. For example, the name of a getter in a
* {@code @ConfigurationProperties} annotated class.
* @return the source method
*/
public String getSourceMethod() {
return this.sourceMethod;
}
public void setSourceMethod(String sourceMethod) {
this.sourceMethod = sourceMethod;
}
}

View File

@@ -1,190 +0,0 @@
/*
* Copyright 2012-2016 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.io.Serializable;
import java.util.List;
/**
* Define a configuration property. Each property is fully identified by its
* {@link #getId() id} which is composed of a namespace prefix (the
* {@link ConfigurationMetadataGroup#getId() group id}), if any and the {@link #getName()
* name} of the property.
*
* @author Stephane Nicoll
* @since 1.3.0
*/
@SuppressWarnings("serial")
public class ConfigurationMetadataProperty implements Serializable {
private String id;
private String name;
private String type;
private String description;
private String shortDescription;
private Object defaultValue;
private final Hints hints = new Hints();
private Deprecation deprecation;
/**
* The full identifier of the property, in lowercase dashed form (e.g.
* my.group.simple-property)
* @return the property id
*/
public String getId() {
return this.id;
}
public void setId(String id) {
this.id = id;
}
/**
* The name of the property, in lowercase dashed form (e.g. simple-property). If this
* item does not belong to any group, the id is returned.
* @return the property name
*/
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
/**
* The class name of the data type of the property. For example,
* {@code java.lang.String}.
* <p>
* For consistency, the type of a primitive is specified using its wrapper
* counterpart, i.e. {@code boolean} becomes {@code java.lang.Boolean}. If the type
* holds generic information, these are provided as well, i.e. a {@code HashMap} of
* 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() {
return this.type;
}
public void setType(String type) {
this.type = type;
}
/**
* A description of the property, if any. Can be multi-lines.
* @return the property description
* @see #getShortDescription()
*/
public String getDescription() {
return this.description;
}
public void setDescription(String description) {
this.description = description;
}
/**
* A single-line, single-sentence description of this property, if any.
* @return the property short description
* @see #getDescription()
*/
public String getShortDescription() {
return this.shortDescription;
}
public void setShortDescription(String shortDescription) {
this.shortDescription = shortDescription;
}
/**
* The default value, if any.
* @return the default value
*/
public Object getDefaultValue() {
return this.defaultValue;
}
public void setDefaultValue(Object defaultValue) {
this.defaultValue = defaultValue;
}
/**
* Return the hints of this item.
* @return the hints
*/
public Hints getHints() {
return this.hints;
}
/**
* The list of well-defined values, if any. If no extra {@link ValueProvider provider}
* is specified, these values are to be considered a closed-set of the available
* values for this item.
* @return the value hints
* @see #getHints()
*/
@Deprecated
public List<ValueHint> getValueHints() {
return this.hints.getValueHints();
}
/**
* The value providers that are applicable to this item. Only one
* {@link ValueProvider} is enabled for an item: the first in the list that is
* supported should be used.
* @return the value providers
* @see #getHints()
*/
@Deprecated
public List<ValueProvider> getValueProviders() {
return this.hints.getValueProviders();
}
/**
* The {@link Deprecation} for this property, if any.
* @return the deprecation
* @see #isDeprecated()
*/
public Deprecation getDeprecation() {
return this.deprecation;
}
public void setDeprecation(Deprecation deprecation) {
this.deprecation = deprecation;
}
/**
* Specify if the property is deprecated.
* @return if the property is deprecated
* @see #getDeprecation()
*/
public boolean isDeprecated() {
return this.deprecation != null;
}
}

View File

@@ -1,47 +0,0 @@
/*
* 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.util.Map;
/**
* A repository of configuration metadata.
*
* @author Stephane Nicoll
* @since 1.3.0
*/
public interface ConfigurationMetadataRepository {
/**
* Defines the name of the "root" group, that is the group that gathers all the
* properties that aren't attached to a specific group.
*/
String ROOT_GROUP = "_ROOT_GROUP_";
/**
* Return the groups, indexed by id.
* @return all configuration meta-data groups
*/
Map<String, ConfigurationMetadataGroup> getAllGroups();
/**
* Return the properties, indexed by id.
* @return all configuration meta-data properties
*/
Map<String, ConfigurationMetadataProperty> getAllProperties();
}

View File

@@ -1,231 +0,0 @@
/*
* Copyright 2012-2016 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.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import org.springframework.ide.eclipse.org.json.JSONException;
/**
* Load a {@link ConfigurationMetadataRepository} from the content of arbitrary
* resource(s).
*
* @author Stephane Nicoll
* @since 1.3.0
*/
public final class ConfigurationMetadataRepositoryJsonBuilder {
/**
* UTF-8 Charset.
*/
public static final Charset UTF_8 = Charset.forName("UTF-8");
private Charset defaultCharset = UTF_8;
private final JsonReader reader = new JsonReader();
private final List<RawConfigurationMetadata> rawDatas = new ArrayList<>();
private ConfigurationMetadataRepositoryJsonBuilder(Charset defaultCharset) {
this.defaultCharset = defaultCharset;
}
/**
* Add the content of a {@link ConfigurationMetadataRepository} defined by the
* specified {@link InputStream} json document using the default charset. If this
* metadata repository holds items that were loaded previously, these are ignored.
* <p>
* Leaves the stream open when done.
* @param origin optional information object to help identify where the inputstream came from
* @param inputStream the source input stream
* @return this builder
* @throws IOException in case of I/O errors
*/
public ConfigurationMetadataRepositoryJsonBuilder withJsonResource(
Object origin, InputStream inputStream) throws IOException {
return withJsonResource(origin, inputStream, this.defaultCharset);
}
/**
* Add the content of a {@link ConfigurationMetadataRepository} defined by the
* specified {@link InputStream} json document using the specified {@link Charset}. If
* this metadata repository holds items that were loaded previously, these are
* ignored.
* <p>
* Leaves the stream open when done.
* @param origin optional information object to help identify where the inputstream came from
* @param inputStream the source input stream
* @param charset the charset of the input
* @return this builder
* @throws IOException in case of I/O errors
*/
public ConfigurationMetadataRepositoryJsonBuilder withJsonResource(
Object origin, InputStream inputStream, Charset charset) throws IOException {
if (inputStream == null) {
throw new IllegalArgumentException("InputStream must not be null.");
}
this.rawDatas.add(parseRaw(origin, inputStream, charset));
return this;
}
/**
* Build a {@link ConfigurationMetadataRepository} with the current state of this
* builder.
* @return this builder
*/
public ConfigurationMetadataRepository build() {
SimpleConfigurationMetadataRepository result = new SimpleConfigurationMetadataRepository();
result.include(create(rawDatas));
return result;
}
private RawConfigurationMetadata parseRaw(Object origin, InputStream in, Charset charset)
throws IOException {
try {
return this.reader.read(origin, in, charset);
}
catch (IOException ex) {
throw new IllegalArgumentException(
"Failed to read configuration " + "metadata", ex);
}
catch (JSONException ex) {
throw new IllegalArgumentException(
"Invalid configuration " + "metadata document", ex);
}
}
private SimpleConfigurationMetadataRepository create(
Iterable<RawConfigurationMetadata> metadatas) {
SimpleConfigurationMetadataRepository repository = new SimpleConfigurationMetadataRepository();
for (RawConfigurationMetadata metadata : metadatas) {
repository.add(metadata.getSources());
}
for (RawConfigurationMetadata metadata : metadatas) {
for (ConfigurationMetadataItem item : metadata.getItems()) {
ConfigurationMetadataSource source = getSource(metadata, item);
repository.add(item, source);
}
}
for (RawConfigurationMetadata metadata : metadatas) {
Map<String, ConfigurationMetadataProperty> allProperties = repository
.getAllProperties();
for (ConfigurationMetadataHint hint : metadata.getHints()) {
ConfigurationMetadataProperty property = allProperties.get(hint.getId());
if (property != null) {
addValueHints(property, hint);
}
else {
String id = hint.resolveId();
property = allProperties.get(id);
if (property != null) {
if (hint.isMapKeyHints()) {
addMapHints(property, hint);
}
else {
addValueHints(property, hint);
}
}
}
}
}
return repository;
}
private void addValueHints(ConfigurationMetadataProperty property,
ConfigurationMetadataHint hint) {
addAll(property.getHints().getValueHints(), hint.getValueHints());
property.getHints().getValueProviders().addAll(hint.getValueProviders());
}
private void addMapHints(ConfigurationMetadataProperty property,
ConfigurationMetadataHint hint) {
addAll(property.getHints().getKeyHints(), hint.getValueHints());
property.getHints().getKeyProviders().addAll(hint.getValueProviders());
}
/**
* Add a bunch of hints to a list, but guard against duplicates.
*/
private void addAll(List<ValueHint> existing, List<ValueHint> toAdd) {
if (existing.isEmpty()) {
existing.addAll(toAdd);
} else if (toAdd.isEmpty()) {
//nothing to add
} else {
Set<Object> existingValues = existing
.stream()
.map((hint) -> ""+hint.getValue())
.collect(Collectors.toSet());
for (ValueHint hint : toAdd) {
if (!existingValues.contains(""+hint.getValue())) {
existing.add(hint);
}
}
}
}
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(null, 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);
}
}

View File

@@ -1,131 +0,0 @@
/*
* 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.io.Serializable;
import java.util.HashMap;
import java.util.Map;
/**
* A source of configuration metadata. Also defines where the source is declared, for
* instance if it is defined as a {@code @Bean}.
*
* @author Stephane Nicoll
* @since 1.3.0
*/
@SuppressWarnings("serial")
public class ConfigurationMetadataSource implements Serializable {
private String groupId;
private String type;
private String description;
private String shortDescription;
private String sourceType;
private String sourceMethod;
private final Map<String, ConfigurationMetadataProperty> properties = new HashMap<String, ConfigurationMetadataProperty>();
/**
* The identifier of the group to which this source is associated.
* @return the group id
*/
public String getGroupId() {
return this.groupId;
}
void setGroupId(String groupId) {
this.groupId = groupId;
}
/**
* The type of the source. Usually this is the fully qualified name of a class that
* defines configuration items. This class may or may not be available at runtime.
* @return the type
*/
public String getType() {
return this.type;
}
void setType(String type) {
this.type = type;
}
/**
* A description of this source, if any. Can be multi-lines.
* @return the description
* @see #getShortDescription()
*/
public String getDescription() {
return this.description;
}
void setDescription(String description) {
this.description = description;
}
/**
* A single-line, single-sentence description of this source, if any.
* @return the short description
* @see #getDescription()
*/
public String getShortDescription() {
return this.shortDescription;
}
public void setShortDescription(String shortDescription) {
this.shortDescription = shortDescription;
}
/**
* The type where this source is defined. This can be identical to the
* {@link #getType() type} if the source is self-defined.
* @return the source type
*/
public String getSourceType() {
return this.sourceType;
}
void setSourceType(String sourceType) {
this.sourceType = sourceType;
}
/**
* The method name that defines this source, if any.
* @return the source method
*/
public String getSourceMethod() {
return this.sourceMethod;
}
void setSourceMethod(String sourceMethod) {
this.sourceMethod = sourceMethod;
}
/**
* Return the properties defined by this source.
* @return the properties
*/
public Map<String, ConfigurationMetadataProperty> getProperties() {
return this.properties;
}
}

View File

@@ -1,66 +0,0 @@
/*
* 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.io.Serializable;
/**
* Indicate that a property is deprecated. Provide additional information about the
* deprecation.
*
* @author Stephane Nicoll
* @since 1.3.0
*/
@SuppressWarnings("serial")
public class Deprecation implements Serializable {
private String reason;
private String replacement;
/**
* A reason why the related property is deprecated, if any. Can be multi-lines.
* @return the deprecation reason
*/
public String getReason() {
return this.reason;
}
public void setReason(String reason) {
this.reason = reason;
}
/**
* The full name of the property that replaces the related deprecated property, if
* any.
* @return the replacement property name
*/
public String getReplacement() {
return this.replacement;
}
public void setReplacement(String replacement) {
this.replacement = replacement;
}
@Override
public String toString() {
return "Deprecation{" + "reason='" + this.reason + '\'' + ", replacement='"
+ this.replacement + '\'' + '}';
}
}

View File

@@ -1,58 +0,0 @@
/*
* 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 description.
*
* @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();
}
}

View File

@@ -1,82 +0,0 @@
/*
* Copyright 2012-2016 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.util.ArrayList;
import java.util.List;
/**
* Hints of an item to provide the list of values and/or the name of the provider
* responsible to identify suitable values. If the type of the related item is a
* {@link java.util.Map} it can have both key and value hints.
*
* @author Stephane Nicoll
* @since 1.4.0
*/
public class Hints {
private final List<ValueHint> keyHints = new ArrayList<ValueHint>();
private final List<ValueProvider> keyProviders = new ArrayList<ValueProvider>();
private final List<ValueHint> valueHints = new ArrayList<ValueHint>();
private final List<ValueProvider> valueProviders = new ArrayList<ValueProvider>();
/**
* The list of well-defined keys, if any. Only applicable if the type of the related
* item is a {@link java.util.Map}. If no extra {@link ValueProvider provider} is
* specified, these values are to be considered a closed-set of the available keys for
* the map.
* @return the key hints
*/
public List<ValueHint> getKeyHints() {
return this.keyHints;
}
/**
* The value providers that are applicable to the keys of this item. Only applicable
* if the type of the related item is a {@link java.util.Map}. Only one
* {@link ValueProvider} is enabled for a key: the first in the list that is supported
* should be used.
* @return the key providers
*/
public List<ValueProvider> getKeyProviders() {
return this.keyProviders;
}
/**
* The list of well-defined values, if any. If no extra {@link ValueProvider provider}
* is specified, these values are to be considered a closed-set of the available
* values for this item.
* @return the value hints
*/
public List<ValueHint> getValueHints() {
return this.valueHints;
}
/**
* The value providers that are applicable to this item. Only one
* {@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() {
return this.valueProviders;
}
}

View File

@@ -1,195 +0,0 @@
/*
* 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.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.springframework.ide.eclipse.org.json.JSONArray;
import org.springframework.ide.eclipse.org.json.JSONObject;
/**
* Read standard json metadata format as {@link ConfigurationMetadataRepository}.
*
* @author Stephane Nicoll
* @since 1.3.0
*/
class JsonReader {
private static final int BUFFER_SIZE = 4096;
private final DescriptionExtractor descriptionExtractor = new DescriptionExtractor();
public RawConfigurationMetadata read(Object origin, InputStream in, Charset charset)
throws IOException {
JSONObject json = readJson(in, charset);
List<ConfigurationMetadataSource> groups = parseAllSources(json);
List<ConfigurationMetadataItem> items = parseAllItems(json);
List<ConfigurationMetadataHint> hints = parseAllHints(json);
return new RawConfigurationMetadata(origin, groups, items, hints);
}
private List<ConfigurationMetadataSource> parseAllSources(JSONObject root) {
List<ConfigurationMetadataSource> result = new ArrayList<ConfigurationMetadataSource>();
if (!root.has("groups")) {
return result;
}
JSONArray sources = root.getJSONArray("groups");
for (int i = 0; i < sources.length(); i++) {
JSONObject source = sources.getJSONObject(i);
result.add(parseSource(source));
}
return result;
}
private List<ConfigurationMetadataItem> parseAllItems(JSONObject root) {
List<ConfigurationMetadataItem> result = new ArrayList<ConfigurationMetadataItem>();
if (!root.has("properties")) {
return result;
}
JSONArray items = root.getJSONArray("properties");
for (int i = 0; i < items.length(); i++) {
JSONObject item = items.getJSONObject(i);
result.add(parseItem(item));
}
return result;
}
private List<ConfigurationMetadataHint> parseAllHints(JSONObject root) {
List<ConfigurationMetadataHint> result = new ArrayList<ConfigurationMetadataHint>();
if (!root.has("hints")) {
return result;
}
JSONArray items = root.getJSONArray("hints");
for (int i = 0; i < items.length(); i++) {
JSONObject item = items.getJSONObject(i);
result.add(parseHint(item));
}
return result;
}
private ConfigurationMetadataSource parseSource(JSONObject json) {
ConfigurationMetadataSource source = new ConfigurationMetadataSource();
source.setGroupId(json.getString("name"));
source.setType(json.optString("type", null));
String description = json.optString("description", null);
source.setDescription(description);
source.setShortDescription(
this.descriptionExtractor.getShortDescription(description));
source.setSourceType(json.optString("sourceType", null));
source.setSourceMethod(json.optString("sourceMethod", null));
return source;
}
private ConfigurationMetadataItem parseItem(JSONObject json) {
ConfigurationMetadataItem item = new ConfigurationMetadataItem();
item.setId(json.getString("name"));
item.setType(json.optString("type", null));
String description = json.optString("description", null);
item.setDescription(description);
item.setShortDescription(
this.descriptionExtractor.getShortDescription(description));
item.setDefaultValue(readItemValue(json.opt("defaultValue")));
item.setDeprecation(parseDeprecation(json));
item.setSourceType(json.optString("sourceType", null));
item.setSourceMethod(json.optString("sourceMethod", null));
return item;
}
private ConfigurationMetadataHint parseHint(JSONObject json) {
ConfigurationMetadataHint hint = new ConfigurationMetadataHint();
hint.setId(json.getString("name"));
if (json.has("values")) {
JSONArray values = json.getJSONArray("values");
for (int i = 0; i < values.length(); i++) {
JSONObject value = values.getJSONObject(i);
ValueHint valueHint = new ValueHint();
valueHint.setValue(readItemValue(value.get("value")));
String description = value.optString("description", null);
valueHint.setDescription(description);
valueHint.setShortDescription(
this.descriptionExtractor.getShortDescription(description));
hint.getValueHints().add(valueHint);
}
}
if (json.has("providers")) {
JSONArray providers = json.getJSONArray("providers");
for (int i = 0; i < providers.length(); i++) {
JSONObject provider = providers.getJSONObject(i);
ValueProvider valueProvider = new ValueProvider();
valueProvider.setName(provider.getString("name"));
if (provider.has("parameters")) {
JSONObject parameters = provider.getJSONObject("parameters");
Iterator<?> keys = parameters.keys();
while (keys.hasNext()) {
String key = (String) keys.next();
valueProvider.getParameters().put(key,
readItemValue(parameters.get(key)));
}
}
hint.getValueProviders().add(valueProvider);
}
}
return hint;
}
private Deprecation parseDeprecation(JSONObject object) {
if (object.has("deprecation")) {
JSONObject deprecationJsonObject = object.getJSONObject("deprecation");
Deprecation deprecation = new Deprecation();
deprecation.setReason(deprecationJsonObject.optString("reason", null));
deprecation
.setReplacement(deprecationJsonObject.optString("replacement", null));
return deprecation;
}
return (object.optBoolean("deprecated") ? new Deprecation() : null);
}
private Object readItemValue(Object value) {
if (value instanceof JSONArray) {
JSONArray array = (JSONArray) value;
Object[] content = new Object[array.length()];
for (int i = 0; i < array.length(); i++) {
content[i] = array.get(i);
}
return content;
}
return value;
}
private JSONObject readJson(InputStream in, Charset charset) throws IOException {
try {
StringBuilder out = new StringBuilder();
InputStreamReader reader = new InputStreamReader(in, charset);
char[] buffer = new char[BUFFER_SIZE];
int bytesRead = -1;
while ((bytesRead = reader.read(buffer)) != -1) {
out.append(buffer, 0, bytesRead);
}
return new JSONObject(out.toString());
}
finally {
in.close();
}
}
}

View File

@@ -1,10 +0,0 @@
The source code in this package is taken from here:
https://github.com/spring-projects/spring-boot/tree/fca6dbaf09c32202d9d958f815221aad54b9fc7b/spring-boot-tools/spring-boot-configuration-metadata/src/main/java/org/springframework/boot/configurationmetadata
Notes:
- This commit is from the master branch at a point in time where boot team is working on Boot 1.4.x on that branch.
There are currently no modifications being made to that code at all to accomodate STS. So it may now be possible to consume it as a proper dependency.
However, keep in mind that we are using a modified copy of 'org.json' to allow controlling key order in json maps. So that probably
complicates things.

View File

@@ -1,106 +0,0 @@
/*
* Copyright 2012-2016 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.util.ArrayList;
import java.util.List;
/**
* A raw metadata structure. Used to initialize a {@link ConfigurationMetadataRepository}.
*
* @author Stephane Nicoll
* @since 1.3.0
*/
class RawConfigurationMetadata {
private final Object origin;
private final List<ConfigurationMetadataSource> sources;
private final List<ConfigurationMetadataItem> items;
private final List<ConfigurationMetadataHint> hints;
RawConfigurationMetadata(Object parsedFrom,
List<ConfigurationMetadataSource> sources,
List<ConfigurationMetadataItem> items,
List<ConfigurationMetadataHint> hints) {
this.origin = parsedFrom;
this.sources = new ArrayList<ConfigurationMetadataSource>(sources);
this.items = new ArrayList<ConfigurationMetadataItem>(items);
this.hints = new ArrayList<ConfigurationMetadataHint>(hints);
for (ConfigurationMetadataItem item : this.items) {
resolveName(item);
}
}
public List<ConfigurationMetadataSource> getSources() {
return this.sources;
}
public ConfigurationMetadataSource getSource(String type) {
for (ConfigurationMetadataSource source : this.sources) {
if (type.equals(source.getType())) {
return source;
}
}
return null;
}
public List<ConfigurationMetadataItem> getItems() {
return this.items;
}
public List<ConfigurationMetadataHint> getHints() {
return this.hints;
}
/**
* Resolve the name of an item against this instance.
* @param item the item to resolve
* @see ConfigurationMetadataProperty#setName(String)
*/
private void resolveName(ConfigurationMetadataItem item) {
item.setName(item.getId()); // fallback
if (item.getSourceType() == null) {
return;
}
ConfigurationMetadataSource source = getSource(item.getSourceType());
if (source != null) {
String groupId = source.getGroupId();
String dottedPrefix = groupId + ".";
String id = item.getId();
if (hasLength(groupId) && id.startsWith(dottedPrefix)) {
String name = id.substring(dottedPrefix.length(), id.length());
item.setName(name);
}
}
}
private static boolean hasLength(String string) {
return (string != null && string.length() > 0);
}
@Override
public String toString() {
if (origin!=null) {
return "RawConfigurationMetadata("+origin+")";
}
return super.toString();
}
}

View File

@@ -1,130 +0,0 @@
/*
* 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.io.Serializable;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
/**
* The default {@link ConfigurationMetadataRepository} implementation.
*
* @author Stephane Nicoll
* @since 1.3.0
*/
@SuppressWarnings("serial")
public class SimpleConfigurationMetadataRepository
implements ConfigurationMetadataRepository, Serializable {
private final Map<String, ConfigurationMetadataGroup> allGroups = new HashMap<String, ConfigurationMetadataGroup>();
@Override
public Map<String, ConfigurationMetadataGroup> getAllGroups() {
return Collections.unmodifiableMap(this.allGroups);
}
@Override
public Map<String, ConfigurationMetadataProperty> getAllProperties() {
Map<String, ConfigurationMetadataProperty> properties = new HashMap<String, ConfigurationMetadataProperty>();
for (ConfigurationMetadataGroup group : this.allGroups.values()) {
properties.putAll(group.getProperties());
}
return properties;
}
/**
* Register the specified {@link ConfigurationMetadataSource sources}.
* @param sources the sources to add
*/
public void add(Collection<ConfigurationMetadataSource> sources) {
for (ConfigurationMetadataSource source : sources) {
String groupId = source.getGroupId();
ConfigurationMetadataGroup group = this.allGroups.get(groupId);
if (group == null) {
group = new ConfigurationMetadataGroup(groupId);
this.allGroups.put(groupId, group);
}
String sourceType = source.getType();
if (sourceType != null) {
putIfAbsent(group.getSources(), sourceType, source);
}
}
}
/**
* Add a {@link ConfigurationMetadataProperty} with the
* {@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) {
if (source != null) {
putIfAbsent(source.getProperties(), property.getId(), property);
}
putIfAbsent(getGroup(source).getProperties(), property.getId(), property);
}
/**
* Merge the content of the specified repository to this repository.
* @param repository the repository to include
*/
public void include(ConfigurationMetadataRepository repository) {
for (ConfigurationMetadataGroup group : repository.getAllGroups().values()) {
ConfigurationMetadataGroup existingGroup = this.allGroups.get(group.getId());
if (existingGroup == null) {
this.allGroups.put(group.getId(), group);
}
else {
// Merge properties
for (Map.Entry<String, ConfigurationMetadataProperty> entry : group
.getProperties().entrySet()) {
putIfAbsent(existingGroup.getProperties(), entry.getKey(),
entry.getValue());
}
// Merge sources
for (Map.Entry<String, ConfigurationMetadataSource> entry : group
.getSources().entrySet()) {
putIfAbsent(existingGroup.getSources(), entry.getKey(),
entry.getValue());
}
}
}
}
private ConfigurationMetadataGroup getGroup(ConfigurationMetadataSource source) {
if (source == null) {
ConfigurationMetadataGroup rootGroup = this.allGroups.get(ROOT_GROUP);
if (rootGroup == null) {
rootGroup = new ConfigurationMetadataGroup(ROOT_GROUP);
this.allGroups.put(ROOT_GROUP, rootGroup);
}
return rootGroup;
}
return this.allGroups.get(source.getGroupId());
}
private <V> void putIfAbsent(Map<String, V> map, String key, V value) {
if (!map.containsKey(key)) {
map.put(key, value);
}
}
}

View File

@@ -1,97 +0,0 @@
/*
* 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.io.Serializable;
/**
* Hint for a value a given property may have. Provide the value and an optional
* description.
*
* @author Stephane Nicoll
* @since 1.3.0
*/
@SuppressWarnings("serial")
public class ValueHint implements Serializable, Cloneable {
public static ValueHint withValue(Object value) {
ValueHint hint = new ValueHint();
hint.setValue(value);
return hint;
}
public ValueHint prefixWith(String prefix) {
try {
ValueHint clone = (ValueHint) this.clone();
clone.setValue(prefix+value);
return clone;
} catch (CloneNotSupportedException e) {
//This is supposed to be impossble.
throw new RuntimeException(e);
}
}
private Object value;
private String description;
private String shortDescription;
/**
* Return the hint value.
* @return the value
*/
public Object getValue() {
return this.value;
}
public void setValue(Object value) {
this.value = value;
}
/**
* A description of this value, if any. Can be multi-lines.
* @return the description
* @see #getShortDescription()
*/
public String getDescription() {
return this.description;
}
public void setDescription(String description) {
this.description = description;
}
/**
* A single-line, single-sentence description of this hint, if any.
* @return the short description
* @see #getDescription()
*/
public String getShortDescription() {
return this.shortDescription;
}
public void setShortDescription(String shortDescription) {
this.shortDescription = shortDescription;
}
@Override
public String toString() {
return "ValueHint{" + "value=" + this.value + ", description='" + this.description
+ '\'' + '}';
}
}

View File

@@ -1,66 +0,0 @@
/*
* 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.io.Serializable;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* Define a component that is able to provide the values of a property.
* <p>
* Each provider is defined by a {@code name} and can have an arbitrary number of
* {@code parameters}. The available providers are defined in the Spring Boot
* documentation.
*
* @author Stephane Nicoll
* @since 1.3.0
*/
@SuppressWarnings("serial")
public class ValueProvider implements Serializable {
private String name;
private final Map<String, Object> parameters = new LinkedHashMap<String, Object>();
/**
* Return the name of the provider.
* @return the name
*/
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
/**
* Return the parameters.
* @return the parameters
*/
public Map<String, Object> getParameters() {
return this.parameters;
}
@Override
public String toString() {
return "ValueProvider{" + "name='" + this.name + ", parameters=" + this.parameters
+ '}';
}
}

View File

@@ -1,20 +0,0 @@
/*
* 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.
*/
/**
* Spring Boot configuration meta-data parser.
*/
package org.springframework.boot.configurationmetadata;

View File

@@ -15,8 +15,8 @@ import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.LinkedHashMap;
import org.springframework.ide.eclipse.org.json.JSONArray;
import org.springframework.ide.eclipse.org.json.JSONObject;
import org.json.JSONArray;
import org.json.JSONObject;
/**
* Helper class to manipulate data in a file presumed to contain
@@ -44,7 +44,12 @@ public class MetadataManipulator {
}
public String toString() {
return object.toString(indentFactor);
try {
return object.toString(indentFactor);
}
catch (Exception e) {
return null;
}
}
@Override

View File

@@ -84,7 +84,7 @@ public class PropertiesLoader {
InputStream is = null;
try {
is = Files.newInputStream(mdf);
loadFromInputStream(mdf, is);
loadFromInputStream(is);
} catch (Exception e) {
LOG.log(Level.SEVERE, "Error loading file '" + mdf + "'", e);
} finally {
@@ -127,7 +127,7 @@ public class PropertiesLoader {
InputStream is = null;
try {
is = jarFile.getInputStream(ze);
loadFromInputStream(jarFile.getName()+"["+ze.getName()+"]", is);
loadFromInputStream(is);
} catch (Throwable e) {
LOG.log(Level.SEVERE, "Error loading JAR file", e);
} finally {
@@ -140,8 +140,8 @@ public class PropertiesLoader {
}
}
private void loadFromInputStream(Object origin, InputStream is) throws IOException {
builder.withJsonResource(origin, is);
private void loadFromInputStream(InputStream is) throws IOException {
builder.withJsonResource(is);
}
}