Dave Jarvis' Repositories

git clone https://repo.autonoma.ca/repo/keenwrite.git

Simplifications to make parsed document immutable

AuthorDaveJarvis <email>
Date2020-06-07 10:46:00 GMT-0700
Commit07e19578b4703c04cd7b1c329e9a98d34334861d
Parente200f86
Delta410 lines added, 439 lines removed, 29-line decrease
src/main/java/com/scrivenvar/definition/yaml/YamlDefinitionSource.java
public class YamlDefinitionSource extends FileDefinitionSource {
- private final YamlParser mYamlParser;
private final YamlTreeAdapter mYamlTreeAdapter;
/**
* Constructs a new YAML definition source, populated from the given file.
*
* @param path Path to the YAML definition file.
*/
public YamlDefinitionSource( final Path path ) {
super( path );
- mYamlParser = createYamlParser( path );
- mYamlTreeAdapter = createTreeAdapter( mYamlParser );
+ mYamlTreeAdapter = new YamlTreeAdapter( path );
}
public String getError() {
return getYamlParser().getError();
- }
-
- private YamlParser createYamlParser( final Path path ) {
- return new YamlParser( path );
}
private YamlParser getYamlParser() {
- return mYamlParser;
- }
-
- private YamlTreeAdapter createTreeAdapter( final YamlParser parser ) {
- return new YamlTreeAdapter( parser );
+ return mYamlTreeAdapter.getYamlParser();
}
}
src/main/java/com/scrivenvar/definition/yaml/YamlParser.java
import org.yaml.snakeyaml.DumperOptions;
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.Writer;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * <p>
- * This program loads a YAML document into memory, scans for variable
- * declarations, then substitutes any self-referential values back into the
- * document. Its output is the given YAML document without any variables.
- * Variables in the YAML document are denoted using a bracketed dollar symbol
- * syntax. For example: $field.name$. Some nomenclature to keep from going
- * squirrely, consider:
- * </p>
- *
- * <pre>
- * root:
- * node:
- * name: $field.name$
- * field:
- * name: Alan Turing
- * </pre>
- * <p>
- * The various components of the given YAML are called:
- *
- * <ul>
- * <li><code>$field.name$</code> - delimited reference</li>
- * <li><code>field.name</code> - reference</li>
- * <li><code>name</code> - YAML field</li>
- * <li><code>Alan Turing</code> - (dereferenced) field value</li>
- * </ul>
- *
- * @author White Magic Software, Ltd.
- */
-public class YamlParser implements DocumentParser<JsonNode> {
-
- private final static VariableDecorator VARIABLE_DECORATOR
- = new YamlVariableDecorator();
-
- /**
- * Separates YAML variable nodes (e.g., the dots in
- * <code>$root.node.var$</code>).
- */
- public static final String SEPARATOR = ".";
-
- /**
- * Should be JsonPointer.SEPARATOR, but Jackson YAML uses magic values.
- */
- private final static char SEPARATOR_YAML = '/';
-
- private final static int GROUP_DELIMITED = 1;
- private final static int GROUP_REFERENCE = 2;
-
- /**
- * Compiled regular expression for matching delimited references.
- */
- private final static Pattern REGEX_PATTERN
- = Pattern.compile( YamlVariableDecorator.REGEX );
-
- /**
- * Map of references to dereferenced field values.
- */
- private final Map<String, String> mReferences = new HashMap<>( 64 );
-
- /**
- * Path to the YAML resource to parse.
- */
- private final Path mPath;
-
- /**
- * Error that occurred while parsing.
- */
- private String mError;
-
- /**
- * Start of the Universe (the YAML document node that contains all others).
- */
- private JsonNode mDocumentRoot;
-
- /**
- * Creates a new YamlParser instance that attempts to parse the contents
- * of the YAML document given from a path. The file does not have to exist
- * and can be empty.
- *
- * @param path Path to a file containing YAML data to parse.
- */
- public YamlParser( final Path path ) {
- assert path != null;
- mPath = path;
- }
-
- /**
- * Returns the parent node for the entire YAML document tree.
- *
- * @return The parent node.
- */
- @Override
- public JsonNode parse() {
- final var path = getPath();
-
- try( final InputStream in = Files.newInputStream( path ) ) {
- process( in );
- } catch( final Exception e ) {
- // Ensure that a document root node exists by relying on the
- // default failure condition when processing. This is required
- // because the input stream could not be read.
- process( new ByteArrayInputStream( new byte[]{} ) );
- }
-
- return getDocumentRoot();
- }
-
- /**
- * Returns the given string with all the delimited references swapped with
- * their recursively resolved values.
- *
- * @param text The text to parse with zero or more delimited references to
- * replace.
- * @return The substituted value.
- */
- public String substitute( String text ) {
- final Matcher matcher = patternMatch( text );
- final Map<String, String> map = getReferences();
-
- while( matcher.find() ) {
- final String key = matcher.group( GROUP_DELIMITED );
- final String value = map.getOrDefault( key, key );
-
- text = text.replace( key, value );
- }
-
- return text;
- }
-
- /**
- * Returns all the strings with their values resolved in a flat hierarchy.
- * This copies all the keys and resolved values into a new map.
- *
- * @return The new map created with all values having been resolved,
- * recursively.
- */
- public Map<String, String> createResolvedMap() {
- final Map<String, String> map = new HashMap<>( 1024 );
-
- resolve( getDocumentRoot(), "", map );
-
- return map;
- }
-
- /**
- * Iterate over a given root node (at any level of the tree) and adapt each
- * leaf node.
- *
- * @param rootNode A JSON node (YAML node) to adapt.
- * @param map Container that associates definitions with values.
- */
- private void resolve(
- final JsonNode rootNode,
- final String path,
- final Map<String, String> map ) {
-
- if( rootNode != null ) {
- rootNode.fields().forEachRemaining(
- ( Entry<String, JsonNode> leaf ) -> resolve( leaf, path, map )
- );
- }
- }
-
- /**
- * Look up the value for a given node.
- *
- * @param root The node to resolve (contains a key to find).
- * @param path The path to the node.
- * @param map Flat map of existing key/value pairs.
- */
- private void resolve(
- final Entry<String, JsonNode> root,
- final String path,
- final Map<String, String> map ) {
- final JsonNode leaf = root.getValue();
- final String key = root.getKey();
-
- if( leaf.isValueNode() ) {
- map.put(
- VARIABLE_DECORATOR.decorate( path + key ),
- substitute(
- leaf instanceof NullNode ? "" : leaf.asText()
- )
- );
- }
- else if( leaf.isObject() ) {
- resolve( leaf, path + key + SEPARATOR, map );
- }
- }
-
- /**
- * Reads the first document from the given stream of YAML data and returns a
- * corresponding object that represents the YAML hierarchy. The calling class
- * is responsible for closing the stream. Calling classes should use
- * <code>JsonNode.fields()</code> to walk through the YAML tree of fields.
- *
- * @param in The input stream containing YAML content.
- */
- private void process( final InputStream in ) {
- setError( Messages.get( "Main.statusbar.state.default" ) );
-
- try {
- final YAMLFactory factory = new ResolverYamlFactory();
- final ObjectMapper mapper = new ObjectMapper( factory );
- final JsonNode root = mapper.readTree( in );
- setDocumentRoot( root );
- process( root );
- } catch( final Exception e ) {
- setDocumentRoot( new ObjectMapper().createObjectNode() );
- setError( Messages.get( "yaml.error.open" ) );
- }
- }
-
- /**
- * Iterate over a given root node (at any level of the tree) and process each
- * leaf node.
- *
- * @param root A node to process.
- */
- private void process( final JsonNode root ) {
- root.fields().forEachRemaining( this::process );
- }
-
- /**
- * Process the given field, which is a named node. This is where the
- * application does the up-front work of mapping references to their fully
- * recursively dereferenced values.
- *
- * @param field The named node.
- */
- private void process( final Entry<String, JsonNode> field ) {
- final JsonNode node = field.getValue();
-
- if( node.isObject() ) {
- process( node );
- }
- else {
- final JsonNode fieldValue = field.getValue();
-
- // Only basic data types can be parsed into variable values. For
- // node structures, YAML has a built-in mechanism.
- if( fieldValue.isValueNode() ) {
- try {
- resolve( fieldValue.asText() );
- } catch( StackOverflowError e ) {
- final String msg = Messages.get(
- "yaml.error.unresolvable", node.textValue(), fieldValue );
- setError( msg );
- }
- }
- }
- }
-
- /**
- * Inserts the delimited references and field values into the cache. This will
- * overwrite existing references.
- *
- * @param fieldValue YAML field containing zero or more delimited references.
- * If it contains a delimited reference, the parameter is
- * modified with the
- * dereferenced value before it is returned.
- * @return fieldValue without delimited references.
- */
- private String resolve( String fieldValue ) {
- final Matcher matcher = patternMatch( fieldValue );
-
- while( matcher.find() ) {
- final String delimited = matcher.group( GROUP_DELIMITED );
- final String reference = matcher.group( GROUP_REFERENCE );
- final String dereference = resolve( lookup( reference ) );
-
- fieldValue = fieldValue.replace( delimited, dereference );
-
- // This will perform some superfluous calls by overwriting existing
- // items in the delimited reference map.
- put( delimited, dereference );
- }
-
- return fieldValue;
- }
-
- /**
- * Inserts a key/value pair into the references map. The map retains
- * references and dereferenced values found in the YAML. If the reference
- * already exists, this will overwrite with a new value.
- *
- * @param delimited The variable name.
- * @param dereferenced The resolved value.
- */
- private void put( final String delimited, final String dereferenced ) {
- if( dereferenced.isEmpty() ) {
- missing( delimited );
- }
- else {
- getReferences().put( delimited, dereferenced );
- }
- }
-
- /**
- * Called when a delimited reference is dereferenced to an empty string. This
- * should produce a warning for the user.
- *
- * @param delimited Delimited reference with no derived value.
- */
- private void missing( final String delimited ) {
- setError( Messages.get( "yaml.error.missing", delimited ) );
- }
-
- /**
- * Returns a REGEX_PATTERN matcher for the given text.
- *
- * @param text The text that contains zero or more instances of a
- * REGEX_PATTERN that can be found using the regular expression.
- */
- private Matcher patternMatch( final String text ) {
- return REGEX_PATTERN.matcher( text );
- }
-
- /**
- * Finds the YAML value for a reference.
- *
- * @param reference References a value in the YAML document.
- * @return The dereferenced value.
- */
- private String lookup( final String reference ) {
- return getDocumentRoot().at( asPath( reference ) ).asText();
- }
-
- /**
- * Converts a reference (not delimited) to a path that can be used to find a
- * value that should exist inside the YAML document.
- *
- * @param reference The reference to convert to a YAML document path.
- * @return The reference with a leading slash and its separator characters
- * converted to slashes.
- */
- private String asPath( final String reference ) {
- return SEPARATOR_YAML + reference.replace(
- getDelimitedSeparator(), SEPARATOR_YAML );
- }
-
- /**
- * Sets the parent node for the entire YAML document tree.
- *
- * @param documentRoot The parent node.
- */
- private void setDocumentRoot( final JsonNode documentRoot ) {
- mDocumentRoot = documentRoot;
- }
-
- private JsonNode getDocumentRoot() {
- return mDocumentRoot;
- }
-
- /**
- * @return The list of references mapped to dereferenced values.
- */
- private Map<String, String> getReferences() {
- return mReferences;
- }
-
- private final class ResolverYamlFactory extends YAMLFactory {
-
- private static final long serialVersionUID = 1L;
-
- @Override
- protected YAMLGenerator _createGenerator(
- final Writer out, final IOContext ctxt ) throws IOException {
-
- return new ResolverYamlGenerator(
- ctxt, _generatorFeatures, _yamlGeneratorFeatures, _objectCodec,
- out, _version );
- }
- }
-
- private class ResolverYamlGenerator extends YAMLGenerator {
-
- public ResolverYamlGenerator(
- final IOContext ctxt,
- final int jsonFeatures,
- final int yamlFeatures,
- final ObjectCodec codec,
- final Writer out,
- final DumperOptions.Version version ) throws IOException {
- super( ctxt, jsonFeatures, yamlFeatures, codec, out, version );
- }
-
- @Override
- public void writeString( final String text ) throws IOException {
- super.writeString( substitute( text ) );
- }
- }
-
- /**
- * Returns the {@link Path} to the YAML contents to parse.
- *
- * @return A resource path.
- */
- private Path getPath() {
- return mPath;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Writer;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * <p>
+ * This program loads a YAML document into memory, scans for variable
+ * declarations, then substitutes any self-referential values back into the
+ * document. Its output is the given YAML document without any variables.
+ * Variables in the YAML document are denoted using a bracketed dollar symbol
+ * syntax. For example: $field.name$. Some nomenclature to keep from going
+ * squirrely, consider:
+ * </p>
+ *
+ * <pre>
+ * root:
+ * node:
+ * name: $field.name$
+ * field:
+ * name: Alan Turing
+ * </pre>
+ * <p>
+ * The various components of the given YAML are called:
+ *
+ * <ul>
+ * <li><code>$field.name$</code> - delimited reference</li>
+ * <li><code>field.name</code> - reference</li>
+ * <li><code>name</code> - YAML field</li>
+ * <li><code>Alan Turing</code> - (dereferenced) field value</li>
+ * </ul>
+ *
+ * @author White Magic Software, Ltd.
+ */
+public class YamlParser implements DocumentParser<JsonNode> {
+
+ private final static VariableDecorator VARIABLE_DECORATOR
+ = new YamlVariableDecorator();
+
+ /**
+ * Separates YAML variable nodes (e.g., the dots in
+ * <code>$root.node.var$</code>).
+ */
+ public static final String SEPARATOR = ".";
+
+ /**
+ * Should be JsonPointer.SEPARATOR, but Jackson YAML uses magic values.
+ */
+ private final static char SEPARATOR_YAML = '/';
+
+ private final static int GROUP_DELIMITED = 1;
+ private final static int GROUP_REFERENCE = 2;
+
+ /**
+ * Compiled regular expression for matching delimited references.
+ */
+ private final static Pattern REGEX_PATTERN
+ = Pattern.compile( YamlVariableDecorator.REGEX );
+
+ /**
+ * Map of references to dereferenced field values.
+ */
+ private final Map<String, String> mReferences = new HashMap<>( 64 );
+
+ /**
+ * Error that occurred while parsing.
+ */
+ private String mError;
+
+ /**
+ * Start of the Universe (the YAML document node that contains all others).
+ */
+ private final JsonNode mDocumentRoot;
+
+ /**
+ * Creates a new YamlParser instance that attempts to parse the contents
+ * of the YAML document given from a path. In the event that the file either
+ * does not exist or is empty, a fake
+ *
+ * @param path Path to a file containing YAML data to parse.
+ */
+ public YamlParser( final Path path ) {
+ assert path != null;
+ mDocumentRoot = parse( path );
+ interpolate( mDocumentRoot );
+ }
+
+ /**
+ * Parses the given path containing YAML data into an object hierarchy.
+ *
+ * @param path {@link Path} to the YAML resource to parse.
+ * @return The parsed contents, or an empty object hierarchy.
+ */
+ private JsonNode parse( final Path path ) {
+ try( final InputStream in = Files.newInputStream( path ) ) {
+ return parse( in );
+ } catch( final Exception e ) {
+ setError( Messages.get( "yaml.error.open" ) );
+
+ // Ensure that a document root node exists by relying on the
+ // default failure condition when processing. This is required
+ // because the input stream could not be read.
+ return new ObjectMapper().createObjectNode();
+ }
+ }
+
+ /**
+ * Returns the parent node for the entire YAML document tree.
+ *
+ * @return The document root, never {@code null}.
+ */
+ @Override
+ public JsonNode getDocumentRoot() {
+ return mDocumentRoot;
+ }
+
+ /**
+ * Returns the given string with all the delimited references swapped with
+ * their recursively resolved values.
+ *
+ * @param text The text to parse with zero or more delimited references to
+ * replace.
+ * @return The substituted value.
+ */
+ public String substitute( String text ) {
+ final Matcher matcher = patternMatch( text );
+ final Map<String, String> map = getReferences();
+
+ while( matcher.find() ) {
+ final String key = matcher.group( GROUP_DELIMITED );
+ final String value = map.getOrDefault( key, key );
+
+ text = text.replace( key, value );
+ }
+
+ return text;
+ }
+
+ /**
+ * Returns all the strings with their values resolved in a flat hierarchy.
+ * This copies all the keys and resolved values into a new map.
+ *
+ * @return The new map created with all values having been resolved,
+ * recursively.
+ */
+ public Map<String, String> createResolvedMap() {
+ final Map<String, String> map = new HashMap<>( 1024 );
+
+ resolve( getDocumentRoot(), "", map );
+
+ return map;
+ }
+
+ /**
+ * Iterate over a given root node (at any level of the tree) and adapt each
+ * leaf node.
+ *
+ * @param rootNode A JSON node (YAML node) to adapt.
+ * @param map Container that associates definitions with values.
+ */
+ private void resolve(
+ final JsonNode rootNode,
+ final String path,
+ final Map<String, String> map ) {
+
+ if( rootNode != null ) {
+ rootNode.fields().forEachRemaining(
+ ( Entry<String, JsonNode> leaf ) -> resolve( leaf, path, map )
+ );
+ }
+ }
+
+ /**
+ * Look up the value for a given node.
+ *
+ * @param root The node to resolve (contains a key to find).
+ * @param path The path to the node.
+ * @param map Flat map of existing key/value pairs.
+ */
+ private void resolve(
+ final Entry<String, JsonNode> root,
+ final String path,
+ final Map<String, String> map ) {
+ final JsonNode leaf = root.getValue();
+ final String key = root.getKey();
+
+ if( leaf.isValueNode() ) {
+ map.put(
+ VARIABLE_DECORATOR.decorate( path + key ),
+ substitute(
+ leaf instanceof NullNode ? "" : leaf.asText()
+ )
+ );
+ }
+ else if( leaf.isObject() ) {
+ resolve( leaf, path + key + SEPARATOR, map );
+ }
+ }
+
+ /**
+ * Reads the first document from the given stream of YAML data and returns a
+ * corresponding object that represents the YAML hierarchy. The calling class
+ * is responsible for closing the stream. Calling classes should use
+ * <code>JsonNode.fields()</code> to walk through the YAML tree of fields.
+ *
+ * @param in The input stream containing YAML content.
+ */
+ private JsonNode parse( final InputStream in ) throws IOException {
+ setError( Messages.get( "Main.statusbar.state.default" ) );
+
+ final YAMLFactory factory = new ResolverYamlFactory();
+ final ObjectMapper mapper = new ObjectMapper( factory );
+ return mapper.readTree( in );
+ }
+
+ /**
+ * Iterate over a given root node (at any level of the tree) and process each
+ * leaf node.
+ *
+ * @param root A node to process.
+ */
+ private void interpolate( final JsonNode root ) {
+ root.fields().forEachRemaining( this::interpolate );
+ }
+
+ /**
+ * Process the given field, which is a named node. This is where the
+ * application does the up-front work of mapping references to their fully
+ * recursively dereferenced values.
+ *
+ * @param field The named node.
+ */
+ private void interpolate( final Entry<String, JsonNode> field ) {
+ final JsonNode node = field.getValue();
+
+ if( node.isObject() ) {
+ interpolate( node );
+ }
+ else {
+ final JsonNode fieldValue = field.getValue();
+
+ // Only basic data types can be parsed into variable values. For
+ // node structures, YAML has a built-in mechanism.
+ if( fieldValue.isValueNode() ) {
+ try {
+ resolve( fieldValue.asText() );
+ } catch( final StackOverflowError e ) {
+ final String msg = Messages.get(
+ "yaml.error.unresolvable", node.textValue(), fieldValue );
+ setError( msg );
+ }
+ }
+ }
+ }
+
+ /**
+ * Inserts the delimited references and field values into the cache. This will
+ * overwrite existing references.
+ *
+ * @param fieldValue YAML field containing zero or more delimited references.
+ * If it contains a delimited reference, the parameter is
+ * modified with the
+ * dereferenced value before it is returned.
+ * @return fieldValue without delimited references.
+ */
+ private String resolve( String fieldValue ) {
+ final Matcher matcher = patternMatch( fieldValue );
+
+ while( matcher.find() ) {
+ final String delimited = matcher.group( GROUP_DELIMITED );
+ final String reference = matcher.group( GROUP_REFERENCE );
+ final String dereference = resolve( lookup( reference ) );
+
+ fieldValue = fieldValue.replace( delimited, dereference );
+
+ // This will perform some superfluous calls by overwriting existing
+ // items in the delimited reference map.
+ put( delimited, dereference );
+ }
+
+ return fieldValue;
+ }
+
+ /**
+ * Inserts a key/value pair into the references map. The map retains
+ * references and dereferenced values found in the YAML. If the reference
+ * already exists, this will overwrite with a new value.
+ *
+ * @param delimited The variable name.
+ * @param dereferenced The resolved value.
+ */
+ private void put( final String delimited, final String dereferenced ) {
+ if( dereferenced.isEmpty() ) {
+ missing( delimited );
+ }
+ else {
+ getReferences().put( delimited, dereferenced );
+ }
+ }
+
+ /**
+ * Called when a delimited reference is dereferenced to an empty string. This
+ * should produce a warning for the user.
+ *
+ * @param delimited Delimited reference with no derived value.
+ */
+ private void missing( final String delimited ) {
+ setError( Messages.get( "yaml.error.missing", delimited ) );
+ }
+
+ /**
+ * Returns a REGEX_PATTERN matcher for the given text.
+ *
+ * @param text The text that contains zero or more instances of a
+ * REGEX_PATTERN that can be found using the regular expression.
+ */
+ private Matcher patternMatch( final String text ) {
+ return REGEX_PATTERN.matcher( text );
+ }
+
+ /**
+ * Finds the YAML value for a reference.
+ *
+ * @param reference References a value in the YAML document.
+ * @return The dereferenced value.
+ */
+ private String lookup( final String reference ) {
+ return getDocumentRoot().at( asPath( reference ) ).asText();
+ }
+
+ /**
+ * Converts a reference (not delimited) to a path that can be used to find a
+ * value that should exist inside the YAML document.
+ *
+ * @param reference The reference to convert to a YAML document path.
+ * @return The reference with a leading slash and its separator characters
+ * converted to slashes.
+ */
+ private String asPath( final String reference ) {
+ return SEPARATOR_YAML + reference.replace(
+ getDelimitedSeparator(), SEPARATOR_YAML );
+ }
+
+ /**
+ * @return The list of references mapped to dereferenced values.
+ */
+ private Map<String, String> getReferences() {
+ return mReferences;
+ }
+
+ private final class ResolverYamlFactory extends YAMLFactory {
+
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ protected YAMLGenerator _createGenerator(
+ final Writer out, final IOContext ctxt ) throws IOException {
+
+ return new ResolverYamlGenerator(
+ ctxt, _generatorFeatures, _yamlGeneratorFeatures, _objectCodec,
+ out, _version );
+ }
+ }
+
+ private class ResolverYamlGenerator extends YAMLGenerator {
+
+ public ResolverYamlGenerator(
+ final IOContext ctxt,
+ final int jsonFeatures,
+ final int yamlFeatures,
+ final ObjectCodec codec,
+ final Writer out,
+ final DumperOptions.Version version ) throws IOException {
+ super( ctxt, jsonFeatures, yamlFeatures, codec, out, version );
+ }
+
+ @Override
+ public void writeString( final String text ) throws IOException {
+ super.writeString( substitute( text ) );
+ }
}
src/main/java/com/scrivenvar/definition/yaml/YamlTreeAdapter.java
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.dataformat.yaml.YAMLMapper;
-import com.scrivenvar.definition.DocumentParser;
import com.scrivenvar.definition.TreeAdapter;
import com.scrivenvar.definition.VariableTreeItem;
*/
public class YamlTreeAdapter implements TreeAdapter {
- private final DocumentParser<JsonNode> mParser;
+ private final YamlParser mParser;
/**
- * Constructs a new instance that will use the given parser to read
+ * Constructs a new instance that will use the given path to read
* the object hierarchy from a data source.
*
- * @param parser Provides the ability to read data into an object hierarchy.
+ * @param path Path to YAML contents to parse.
*/
- public YamlTreeAdapter( final DocumentParser<JsonNode> parser ) {
- mParser = parser;
+ public YamlTreeAdapter( final Path path ) {
+ mParser = new YamlParser( path );
}
@Override
- public void export( final TreeItem<String> root, final Path path )
+ public void export( final TreeItem<String> treeItem, final Path path )
throws IOException {
-
final YAMLMapper mapper = new YAMLMapper();
- final ObjectNode node = mapper.createObjectNode();
+ final ObjectNode root = mapper.createObjectNode();
// Iterate over the root item's children. The root item is used by the
- // application to ensure definitions can always be added to a tree.
- for( final TreeItem<String> child : root.getChildren() ) {
- export( child, node );
+ // application to ensure definitions can always be added to a tree, as
+ // such it is not meant to be exported, only its children.
+ for( final TreeItem<String> child : treeItem.getChildren() ) {
+ export( child, root );
}
// Writes as UTF8 by default.
- mapper.writeValue( path.toFile(), node );
+ mapper.writeValue( path.toFile(), root );
}
+ /**
+ * Recursive method to generate an object hierarchy that represents the
+ * given {@link TreeItem} hierarchy.
+ *
+ * @param item The {@link TreeItem} to reproduce as an object hierarchy.
+ * @param node The {@link ObjectNode} to update to reflect the
+ * {@link TreeItem} hierarchy.
+ */
private void export( final TreeItem<String> item, ObjectNode node ) {
final var children = item.getChildren();
*/
public TreeItem<String> adapt( final String root ) {
- final JsonNode rootNode = getParser().parse();
+ final JsonNode rootNode = getYamlParser().getDocumentRoot();
final TreeItem<String> rootItem = createTreeItem( root );
}
- private DocumentParser<JsonNode> getParser() {
+ public YamlParser getYamlParser() {
return mParser;
}