Skip to content

Commit

Permalink
#18 Comments on beans: Rename methods, revise Javadoc, add missing te…
Browse files Browse the repository at this point in the history
…sts, remove unused CollectionUtils
  • Loading branch information
ljacqu committed Aug 9, 2023
1 parent bfa35bb commit 2de3b82
Show file tree
Hide file tree
Showing 19 changed files with 226 additions and 177 deletions.
13 changes: 8 additions & 5 deletions src/main/java/ch/jalu/configme/Comment.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@
import java.lang.annotation.Target;

/**
* Comment for properties which are also included in the YAML file upon saving.
* Comment for properties which are also included in the YAML file upon saving. This annotation can be used on
* {@link ch.jalu.configme.properties.Property Property} fields, as well as on the fields of
* bean classes that are used for {@link ch.jalu.configme.properties.BeanProperty bean properties}.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
Expand All @@ -23,11 +25,12 @@
String @NotNull [] value();

/**
* Defines if the comment should be repeated if it would be included multiple times. Relevant only for bean
* properties: if a class used in a collection has comments, the comments will either be included on the first
* entry if {@code false}, or on each entry if {@code true}.
* Defines if the comment should be repeated, or if it should only be included in the output the first time.
* This method is relevant only for bean properties: if a bean class used in a collection has comments,
* the comments will either be included on the first entry if {@code false}, or on each entry if {@code true}.
*
* @return whether to repeat the comment if the same field is exported multiple times
* @return whether the comment should be repeated for each occurrence of the same field
*/
boolean repeat() default false;

}
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public interface BeanPropertyDescription {
@Nullable Object getValue(@NotNull Object bean);

/**
* @return the comments to add when this property is exported
* @return the comments associated with this property
*/
@NotNull BeanPropertyComments getComments();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public BeanPropertyDescriptionImpl(@NotNull String name, @NotNull TypeInformatio
* @param typeInformation type of the property
* @param getter getter for the property
* @param setter setter for the property
* @param comments the comments for this property
* @param comments the comments of the property
*/
public BeanPropertyDescriptionImpl(@NotNull String name, @NotNull TypeInformation typeInformation,
@NotNull Method getter, @NotNull Method setter,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
package ch.jalu.configme.properties.convertresult;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.List;
import java.util.stream.Stream;

/**
* Wraps a value and allows to associate it with comments. Can be used as return type from
* {@link ch.jalu.configme.properties.Property#toExportValue}.
* <p>
* Prefer defining comments in {@link ch.jalu.configme.SettingsHolder} classes whenever possible.
* Prefer defining comments in {@link ch.jalu.configme.SettingsHolder} classes whenever your comments can be statically
* defined.
*/
public class ValueWithComments {

Expand All @@ -19,7 +24,7 @@ public class ValueWithComments {
* @param value the value to wrap
* @param comments the comments associated with the value
*/
public ValueWithComments(Object value, List<String> comments) {
public ValueWithComments(@NotNull Object value, @NotNull List<String> comments) {
this.value = value;
this.comments = comments;
}
Expand Down Expand Up @@ -51,4 +56,18 @@ public static Object unwrapValue(Object object) {
}
return object;
}

/**
* Returns a stream with the comments on the given object, if it is a {@link ValueWithComments}. An empty
* stream is returned otherwise.
*
* @param object the object to get comments from, if applicable
* @return stream with the comments (never null)
*/
public static @NotNull Stream<String> streamThroughCommentsIfApplicable(@Nullable Object object) {
if (object instanceof ValueWithComments) {
return ((ValueWithComments) object).getComments().stream();
}
return Stream.empty();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public class PropertyPathTraverser {

/** The last path that was processed. */
private String lastPath;
private boolean isFirstProperty = true;
private boolean isFirstElement = true;

/**
* Returns all path elements of the given path.
Expand All @@ -35,14 +35,14 @@ public class PropertyPathTraverser {
int level = 0;
for (int i = 0; i < totalParts; ++i) {
fullPathBuilder.append(pathParts[i]);
PathElement element = new PathElement(level, pathParts[i], fullPathBuilder.toString(), isFirstProperty);
PathElement element = new PathElement(level, pathParts[i], fullPathBuilder.toString(), isFirstElement);
element.setEndOfPath(i == totalParts - 1);
element.setFirstOfGroup(levelOfFirstNewPart == level);
pathElements.add(element);

++level;
fullPathBuilder.append(".");
isFirstProperty = false;
isFirstElement = false;
}
lastPath = path;
return pathElements;
Expand All @@ -56,7 +56,7 @@ public class PropertyPathTraverser {
* @param path the new path
* @return the level of the first new path element
*/
private int returnLevelOfFirstNewPathElement(@NotNull String path) {
protected int returnLevelOfFirstNewPathElement(@NotNull String path) {
if (lastPath == null) {
return 0;
}
Expand Down Expand Up @@ -134,22 +134,22 @@ public boolean isFirstOfGroup() {
return isFirstOfGroup;
}

void setFirstOfGroup(boolean firstOfGroup) {
protected void setFirstOfGroup(boolean firstOfGroup) {
isFirstOfGroup = firstOfGroup;
}

/**
* Returns if this path element is at the end, i.e. whether it represents a leaf path that is associated to
* Returns whether this path element represents the final part of a path, indicating that it is associated with
* a property. For example, given a property {@code config.datasource.driver.version}, the path element for
* {@code version} returns true for this method.
*
* @return true if this element is the final part of the given path
* @return true if this element is the last part of the path (i.e. if it's a "leaf element")
*/
public boolean isEndOfPath() {
return isEndOfPath;
}

void setEndOfPath(boolean isEndOfPath) {
protected void setEndOfPath(boolean isEndOfPath) {
this.isEndOfPath = isEndOfPath;
}
}
Expand Down
35 changes: 23 additions & 12 deletions src/main/java/ch/jalu/configme/resource/YamlFileResource.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import ch.jalu.configme.resource.yaml.SnakeYamlNodeBuilderImpl;
import ch.jalu.configme.resource.yaml.SnakeYamlNodeContainer;
import ch.jalu.configme.resource.yaml.SnakeYamlNodeContainerImpl;
import ch.jalu.configme.utils.StreamUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.yaml.snakeyaml.DumperOptions;
Expand All @@ -22,14 +23,12 @@
import java.nio.file.Path;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;

public class YamlFileResource implements PropertyResource {

private final Path path;
private final @NotNull YamlFileResourceOptions options;
private final int indentationSize;
private @Nullable Yaml yamlObject;

public YamlFileResource(@NotNull Path path) {
Expand All @@ -39,7 +38,6 @@ public YamlFileResource(@NotNull Path path) {
public YamlFileResource(@NotNull Path path, @NotNull YamlFileResourceOptions options) {
this.path = path;
this.options = options;
this.indentationSize = options.getIndentationSize();
}

/**
Expand Down Expand Up @@ -68,8 +66,9 @@ public void exportProperties(@NotNull ConfigurationData configurationData) {
for (Property<?> property : properties) {
Object exportValue = getExportValue(property, configurationData);
if (exportValue != null) {
List<PathElement> pathElements = pathTraverser.getPathElements(property.getPath());
exportValue(configurationData, root, pathElements, nodeBuilder, property.getPath(), exportValue);
String path = property.getPath();
List<PathElement> pathElements = pathTraverser.getPathElements(path);
createAndAddYamlNode(exportValue, path, pathElements, root, configurationData, nodeBuilder);
}
}

Expand All @@ -90,16 +89,28 @@ public void exportProperties(@NotNull ConfigurationData configurationData) {
}
}

private void exportValue(@NotNull ConfigurationData configurationData,
@NotNull SnakeYamlNodeContainer rootContainer,
@NotNull List<PathElement> pathElements, @NotNull SnakeYamlNodeBuilder nodeBuilder,
@NotNull String path, @NotNull Object exportValue) {
/**
* Creates a YAML node for the export value and stores it, along with any comments for intermediate paths that
* have not been visited yet.
*
* @param exportValue the export value to store
* @param path the path the export value is for
* @param pathElements the path elements of this property's path
* @param rootContainer the root YAML node container for storing the export value
* @param configurationData the configuration data (for the retrieval of comments)
* @param nodeBuilder YAML node builder
*/
protected void createAndAddYamlNode(@NotNull Object exportValue, @NotNull String path,
@NotNull List<PathElement> pathElements,
@NotNull SnakeYamlNodeContainer rootContainer,
@NotNull ConfigurationData configurationData,
@NotNull SnakeYamlNodeBuilder nodeBuilder) {
SnakeYamlNodeContainer container = rootContainer;
for (PathElement pathElement : pathElements) {
if (pathElement.isEndOfPath()) {
int emptyLines = options.getNumberOfEmptyLinesBefore(pathElement);
container.putNode(pathElement.getName(),
nodeBuilder.toYamlNode(exportValue, path, configurationData, emptyLines));
nodeBuilder.createYamlNode(exportValue, path, configurationData, emptyLines));
} else {
container = container.getOrCreateChildContainer(pathElement.getName(),
() -> getCommentsForPathElement(configurationData, pathElement));
Expand All @@ -111,7 +122,7 @@ private void exportValue(@NotNull ConfigurationData configurationData,
protected List<String> getCommentsForPathElement(@NotNull ConfigurationData configurationData,
@NotNull PathElement pathElement) {
return Stream.concat(
IntStream.range(0, options.getNumberOfEmptyLinesBefore(pathElement)).mapToObj(i -> "\n"),
StreamUtils.repeat("\n", options.getNumberOfEmptyLinesBefore(pathElement)),
configurationData.getCommentsForSection(pathElement.getFullPath()).stream())
.collect(Collectors.toList());
}
Expand Down Expand Up @@ -150,7 +161,7 @@ protected void onWriteComplete() {
options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
options.setAllowUnicode(true);
options.setProcessComments(true);
options.setIndent(indentationSize);
options.setIndent(this.options.getIndentationSize());
return new Yaml(options);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,16 @@
public interface SnakeYamlNodeBuilder {

/**
* Creates a SnakeYAML node for the given value.
* Creates a SnakeYAML node representing the given value.
*
* @param value the value to create the node for (export value of a property)
* @param path the path of the property whose value is exported
* @param configurationData configuration data (for the retrieval of comments)
* @param numberOfNewLines number of new lines before the property, to add as new lines to the node
* @return SnakeYAML node of the appropriate type for the value, including comments
*/
@NotNull Node toYamlNode(@NotNull Object value, @NotNull String path, @NotNull ConfigurationData configurationData,
int numberOfNewLines);
@NotNull Node createYamlNode(@NotNull Object value, @NotNull String path,
@NotNull ConfigurationData configurationData, int numberOfNewLines);

/**
* Creates a SnakeYAML string node for a key value (e.g. object property, or map key).
Expand All @@ -32,7 +32,7 @@ public interface SnakeYamlNodeBuilder {

/**
* Creates a SnakeYAML {@link CommentLine} to represent the given comment. If the comment is equal to the new line
* character {@code \n}, the comment line should represent a blank line.
* character {@code \n}, the created comment line represents a blank line.
*
* @param comment the comment to represent as CommentLine
* @return appropriate comment line object for the given comment
Expand All @@ -41,11 +41,11 @@ public interface SnakeYamlNodeBuilder {

/**
* Transfers the comments from the value node to the key node. Logically, comments are associated with values,
* but we do not want the comments to appear between the key and the value in the YAML. Therefore, this method is
* called before producing YAML as to move the comments from the value to the key node.
* but we do not want the comments to appear between the key and the value in the YAML output. Therefore, this
* method is called before producing YAML as to move the comments from the value to the key node.
*
* @implNote Only considers {@link Node#getBlockComments() block comments} on the nodes because it's the only type
* of comment that this builder sets.
* of comment that this builder sets. Any block comments on the key node are overwritten.
*
* @param valueNode the value node to remove the comments from
* @param keyNode the key node to set the comments to
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import ch.jalu.configme.configurationdata.ConfigurationData;
import ch.jalu.configme.properties.convertresult.ValueWithComments;
import ch.jalu.configme.utils.StreamUtils;
import org.jetbrains.annotations.NotNull;
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.comments.CommentLine;
Expand All @@ -22,7 +23,6 @@
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

Expand All @@ -32,8 +32,8 @@
public class SnakeYamlNodeBuilderImpl implements SnakeYamlNodeBuilder {

@Override
public @NotNull Node toYamlNode(@NotNull Object obj, @NotNull String path,
@NotNull ConfigurationData configurationData, int numberOfNewLines) {
public @NotNull Node createYamlNode(@NotNull Object obj, @NotNull String path,
@NotNull ConfigurationData configurationData, int numberOfNewLines) {
Object value = ValueWithComments.unwrapValue(obj);
if (value instanceof Enum<?>) {
value = ((Enum<?>) value).name();
Expand Down Expand Up @@ -108,7 +108,7 @@ public void transferComments(@NotNull Node valueNode, @NotNull Node keyNode) {
List<Node> values = entries
.map(entry -> {
String entryPath = pathPrefix.concat(Integer.toString(counter.getAndIncrement()));
return toYamlNode(entry, entryPath, configurationData, 0);
return createYamlNode(entry, entryPath, configurationData, 0);
})
.collect(Collectors.toList());

Expand All @@ -122,7 +122,7 @@ public void transferComments(@NotNull Node valueNode, @NotNull Node keyNode) {

for (Map.Entry<String, ?> entry : value.entrySet()) {
Node keyNode = createKeyNode(entry.getKey());
Node valueNode = toYamlNode(entry.getValue(), pathPrefix.concat(entry.getKey()), configurationData, 0);
Node valueNode = createYamlNode(entry.getValue(), pathPrefix.concat(entry.getKey()), configurationData, 0);
transferComments(valueNode, keyNode);

nodeEntries.add(new NodeTuple(keyNode, valueNode));
Expand All @@ -144,12 +144,9 @@ public void transferComments(@NotNull Node valueNode, @NotNull Node keyNode) {
protected @NotNull List<CommentLine> collectComments(@NotNull Object value, @NotNull String path,
@NotNull ConfigurationData configurationData,
int numberOfNewLines) {
Stream<String> emptyLineStream = IntStream.range(0, numberOfNewLines)
.mapToObj(i -> "\n");
Stream<String> emptyLineStream = StreamUtils.repeat("\n", numberOfNewLines);
Stream<String> configDataStream = configurationData.getCommentsForSection(path).stream();
Stream<String> additionalCommentsStream = (value instanceof ValueWithComments)
? ((ValueWithComments) value).getComments().stream()
: Stream.empty();
Stream<String> additionalCommentsStream = ValueWithComments.streamThroughCommentsIfApplicable(value);

return Stream.of(emptyLineStream, configDataStream, additionalCommentsStream)
.flatMap(Function.identity())
Expand Down
Loading

0 comments on commit 2de3b82

Please sign in to comment.