From bb4fb7d220da8d49aea93087b92dcb8adbbb7f99 Mon Sep 17 00:00:00 2001 From: Roel Spilker Date: Thu, 16 Jan 2020 15:02:00 +0100 Subject: Config import: move responsibilities --- src/core/lombok/core/LombokConfiguration.java | 3 +- .../BubblingConfigurationResolver.java | 1 + .../core/configuration/ConfigurationApp.java | 14 +- .../core/configuration/ConfigurationFile.java | 164 +++++++++++++++++++++ .../core/configuration/ConfigurationParser.java | 30 +++- .../core/configuration/ConfigurationSource.java | 3 + .../core/configuration/FileSystemSourceCache.java | 29 ++-- .../configuration/SingleConfigurationSource.java | 100 +++++++++++++ .../configuration/StringConfigurationSource.java | 89 ----------- 9 files changed, 318 insertions(+), 115 deletions(-) create mode 100644 src/core/lombok/core/configuration/ConfigurationFile.java create mode 100644 src/core/lombok/core/configuration/SingleConfigurationSource.java delete mode 100644 src/core/lombok/core/configuration/StringConfigurationSource.java (limited to 'src') diff --git a/src/core/lombok/core/LombokConfiguration.java b/src/core/lombok/core/LombokConfiguration.java index 4a79c797..7b4cd154 100644 --- a/src/core/lombok/core/LombokConfiguration.java +++ b/src/core/lombok/core/LombokConfiguration.java @@ -26,6 +26,7 @@ import java.util.Collections; import lombok.core.configuration.BubblingConfigurationResolver; import lombok.core.configuration.ConfigurationKey; +import lombok.core.configuration.ConfigurationParser; import lombok.core.configuration.ConfigurationProblemReporter; import lombok.core.configuration.ConfigurationResolver; import lombok.core.configuration.ConfigurationResolverFactory; @@ -74,7 +75,7 @@ public class LombokConfiguration { private static ConfigurationResolverFactory createFileSystemBubblingResolverFactory() { return new ConfigurationResolverFactory() { @Override public ConfigurationResolver createResolver(URI sourceLocation) { - return new BubblingConfigurationResolver(cache.sourcesForJavaFile(sourceLocation, ConfigurationProblemReporter.CONSOLE)); + return new BubblingConfigurationResolver(cache.sourcesForJavaFile(sourceLocation, new ConfigurationParser(ConfigurationProblemReporter.CONSOLE))); } }; } diff --git a/src/core/lombok/core/configuration/BubblingConfigurationResolver.java b/src/core/lombok/core/configuration/BubblingConfigurationResolver.java index a5a5f1d6..20a94477 100644 --- a/src/core/lombok/core/configuration/BubblingConfigurationResolver.java +++ b/src/core/lombok/core/configuration/BubblingConfigurationResolver.java @@ -43,6 +43,7 @@ public class BubblingConfigurationResolver implements ConfigurationResolver { List> listModificationsList = null; outer: for (ConfigurationSource source : sources) { + source.imports(); Result result = source.resolve(key); if (result == null) continue; if (isList) { diff --git a/src/core/lombok/core/configuration/ConfigurationApp.java b/src/core/lombok/core/configuration/ConfigurationApp.java index e3b18408..8ff2307a 100644 --- a/src/core/lombok/core/configuration/ConfigurationApp.java +++ b/src/core/lombok/core/configuration/ConfigurationApp.java @@ -22,6 +22,7 @@ package lombok.core.configuration; import java.io.File; +import java.io.IOException; import java.io.PrintStream; import java.net.URI; import java.util.ArrayList; @@ -188,6 +189,7 @@ public class ConfigurationApp extends LombokApp { }; FileSystemSourceCache cache = new FileSystemSourceCache(); + ConfigurationParser parser = new ConfigurationParser(reporter); boolean first = true; for (Entry> entry : sharedDirectories.entrySet()) { if (!first) { @@ -202,7 +204,7 @@ public class ConfigurationApp extends LombokApp { out.println(); } URI directory = entry.getKey(); - ConfigurationResolver resolver = new BubblingConfigurationResolver(cache.sourcesForDirectory(directory, reporter)); + ConfigurationResolver resolver = new BubblingConfigurationResolver(cache.sourcesForDirectory(directory, parser)); Map, ? extends Collection> traces = trace(keys, directory); boolean printed = false; for (ConfigurationKey key : keys) { @@ -257,7 +259,7 @@ public class ConfigurationApp extends LombokApp { if (!configFile.exists() || !configFile.isFile()) continue; ConfigurationFile context = ConfigurationFile.fromFile(configFile); - Map, List> traces = trace(context.contents(), context, keys); + Map, List> traces = trace(context, keys); stopBubbling = stopBubbling(traces.get(ConfigurationKeys.STOP_BUBBLING)); for (ConfigurationKey key : keys) { @@ -286,10 +288,13 @@ public class ConfigurationApp extends LombokApp { return result; } - private Map, List> trace(String content, ConfigurationFile context, final Collection> keys) { + private Map, List> trace(ConfigurationFile context, final Collection> keys) throws IOException { final Map, List> result = new HashMap, List>(); Collector collector = new Collector() { + @Override public void addImport(ConfigurationFile importFile, ConfigurationFile context, int lineNumber) { + // TODO Trace imports + } @Override public void clear(ConfigurationKey key, ConfigurationFile context, int lineNumber) { trace(key, "clear " + key.getKeyName(), lineNumber); } @@ -315,8 +320,9 @@ public class ConfigurationApp extends LombokApp { } traces.add(String.format("%4d: %s", lineNumber, message)); } + }; - new ConfigurationParser(VOID).parse(content, context, collector); + new ConfigurationParser(VOID).parse(context, collector); return result; } diff --git a/src/core/lombok/core/configuration/ConfigurationFile.java b/src/core/lombok/core/configuration/ConfigurationFile.java new file mode 100644 index 00000000..eed2e6c4 --- /dev/null +++ b/src/core/lombok/core/configuration/ConfigurationFile.java @@ -0,0 +1,164 @@ +/* + * Copyright (C) 2020 The Project Lombok Authors. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package lombok.core.configuration; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; + +public abstract class ConfigurationFile { + private static final ThreadLocal buffers = new ThreadLocal() { + protected byte[] initialValue() { + return new byte[65536]; + } + }; + + private final String identifier; + + public static ConfigurationFile fromFile(File file) { + return new RegularConfigurationFile(file); + } + + public static ConfigurationFile fromCharSequence(String identifier, CharSequence contents, long lastModified) { + return new CharSequenceConfigurationFile(identifier, contents, lastModified); + } + + private ConfigurationFile(String identifier) { + this.identifier = identifier; + } + + abstract long getLastModifiedOrMissing(); + abstract boolean exists(); + abstract CharSequence contents() throws IOException; + public abstract ConfigurationFile resolve(String path); + + final String description() { + return identifier; + } + + @Override public boolean equals(Object obj) { + if (!(obj instanceof ConfigurationFile)) return false; + return identifier.equals(((ConfigurationFile)obj).identifier); + } + + @Override public int hashCode() { + return identifier.hashCode(); + } + + public static long getLastModifiedOrMissing(File file) { + if (!fileExists(file)) return FileSystemSourceCache.MISSING; + return file.lastModified(); + } + + private static boolean fileExists(File file) { + return file.exists() && file.isFile(); + } + + private static String read(InputStream is) throws IOException { + byte[] b = buffers.get(); + try { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + while (true) { + int r = is.read(b); + if (r == -1) break; + out.write(b, 0, r); + } + return new String(out.toByteArray(), "UTF-8"); + } finally { + is.close(); + } + } + + private static class RegularConfigurationFile extends ConfigurationFile { + private final File file; + + private RegularConfigurationFile(File file) { + super(file.getPath()); + this.file = file; + } + + @Override boolean exists() { + return fileExists(file); + } + + public ConfigurationFile resolve(String path) { + File file = resolveFile(path); + return file == null ? null : fromFile(file); + } + + private File resolveFile(String path) { + boolean absolute = false; + int colon = path.indexOf(':'); + if (colon != -1) { + if (colon != 1 || path.indexOf(':', colon + 1) != -1) return null; + char firstCharacter = Character.toLowerCase(path.charAt(0)); + if (firstCharacter < 'a' || firstCharacter > 'z') return null; + absolute = true; + } + if (path.charAt(0) == '/') absolute = true; + try { + return absolute ? new File(path) : new File(file.toURI().resolve(path)); + } catch (Exception e) { + return null; + } + } + + @Override + long getLastModifiedOrMissing() { + return getLastModifiedOrMissing(file); + } + + @Override + CharSequence contents() throws IOException { + return read(new FileInputStream(file)); + } + } + + private static class CharSequenceConfigurationFile extends ConfigurationFile { + private final CharSequence contents; + private final long lastModified; + + private CharSequenceConfigurationFile(String identifier, CharSequence contents, long lastModified) { + super(identifier); + this.contents = contents; + this.lastModified = lastModified; + } + + @Override long getLastModifiedOrMissing() { + return lastModified; + } + + @Override CharSequence contents() throws IOException { + return contents; + } + + @Override boolean exists() { + return true; + } + + @Override public ConfigurationFile resolve(String path) { + return null; + } + } +} \ No newline at end of file diff --git a/src/core/lombok/core/configuration/ConfigurationParser.java b/src/core/lombok/core/configuration/ConfigurationParser.java index a19e48d8..4b9846d9 100644 --- a/src/core/lombok/core/configuration/ConfigurationParser.java +++ b/src/core/lombok/core/configuration/ConfigurationParser.java @@ -21,6 +21,7 @@ */ package lombok.core.configuration; +import java.io.IOException; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -37,13 +38,17 @@ public class ConfigurationParser { this.reporter = reporter; } - public void parse(CharSequence content, ConfigurationFile context, Collector collector) { + public void parse(ConfigurationFile context, Collector collector) { + CharSequence contents = contents(context); + if (contents == null) { + return; + } Map> registeredKeys = ConfigurationKey.registeredKeys(); int lineNumber = 0; - Matcher lineMatcher = NEWLINE_FINDER.matcher(content); + Matcher lineMatcher = NEWLINE_FINDER.matcher(contents); boolean importsAllowed = true; while (lineMatcher.find()) { - CharSequence line = content.subSequence(lineMatcher.start(1), lineMatcher.end(1)); + CharSequence line = contents.subSequence(lineMatcher.start(1), lineMatcher.end(1)); lineNumber++; if (line.length() == 0 || line.charAt(0) == '#') continue; @@ -54,9 +59,16 @@ public class ConfigurationParser { continue; } String imported = importMatcher.group(1); - if (!context.importResolves(imported)) { + ConfigurationFile importFile = context.resolve(imported); + if (importFile == null) { + reporter.report(context.description(), "Import is not valid", lineNumber, line); + continue; + } + if (!importFile.exists()) { reporter.report(context.description(), "Imported file does not exist", lineNumber, line); + continue; } + collector.addImport(importFile, context, lineNumber); continue; } @@ -116,7 +128,17 @@ public class ConfigurationParser { } } + private CharSequence contents(ConfigurationFile context) { + try { + return context.contents(); + } catch (IOException e) { + reporter.report(context.description(), "Exception while reading file: " + e.getMessage(), 0, null); + } + return null; + } + public interface Collector { + void addImport(ConfigurationFile importFile, ConfigurationFile context, int lineNumber); void clear(ConfigurationKey key, ConfigurationFile context, int lineNumber); void set(ConfigurationKey key, Object value, ConfigurationFile context, int lineNumber); void add(ConfigurationKey key, Object value, ConfigurationFile context, int lineNumber); diff --git a/src/core/lombok/core/configuration/ConfigurationSource.java b/src/core/lombok/core/configuration/ConfigurationSource.java index 1e7f9150..7fcfc0fd 100644 --- a/src/core/lombok/core/configuration/ConfigurationSource.java +++ b/src/core/lombok/core/configuration/ConfigurationSource.java @@ -21,9 +21,12 @@ */ package lombok.core.configuration; +import java.util.List; + public interface ConfigurationSource { Result resolve(ConfigurationKey key); + List imports(); public static final class Result { private final Object value; diff --git a/src/core/lombok/core/configuration/FileSystemSourceCache.java b/src/core/lombok/core/configuration/FileSystemSourceCache.java index 0dfc54ab..e18cf9c9 100644 --- a/src/core/lombok/core/configuration/FileSystemSourceCache.java +++ b/src/core/lombok/core/configuration/FileSystemSourceCache.java @@ -57,7 +57,7 @@ public class FileSystemSourceCache { } } - public Iterable sourcesForJavaFile(URI javaFile, ConfigurationProblemReporter reporter) { + public Iterable sourcesForJavaFile(URI javaFile, ConfigurationParser parser) { if (javaFile == null) return Collections.emptyList(); cacheClear(); File dir = uriCache.get(javaFile); @@ -86,7 +86,7 @@ public class FileSystemSourceCache { if (dir != null) { try { - return sourcesForDirectory(dir, reporter); + return sourcesForDirectory(dir, parser); } catch (Exception e) { // Especially for eclipse's sake, exceptions here make eclipse borderline unusable, so let's play nice. ProblemReporter.error("Can't resolve config stack for dir: " + dir.getAbsolutePath(), e); @@ -96,11 +96,11 @@ public class FileSystemSourceCache { return Collections.emptyList(); } - public Iterable sourcesForDirectory(URI directory, ConfigurationProblemReporter reporter) { - return sourcesForJavaFile(directory, reporter); + public Iterable sourcesForDirectory(URI directory, ConfigurationParser parser) { + return sourcesForJavaFile(directory, parser); } - private Iterable sourcesForDirectory(final File directory, final ConfigurationProblemReporter reporter) { + private Iterable sourcesForDirectory(final File directory, final ConfigurationParser parser) { return new Iterable() { @Override public Iterator iterator() { @@ -127,7 +127,7 @@ public class FileSystemSourceCache { private ConfigurationSource findNext() { while (currentDirectory != null && next == null) { - next = getSourceForDirectory(currentDirectory, reporter); + next = getSourceForDirectory(currentDirectory, parser); currentDirectory = currentDirectory.getParentFile(); } if (next != null) { @@ -146,11 +146,11 @@ public class FileSystemSourceCache { }; } - ConfigurationSource getSourceForDirectory(File directory, ConfigurationProblemReporter reporter) { - return getSourceForConfigFile(ConfigurationFile.fromFile(new File(directory, LOMBOK_CONFIG_FILENAME)), reporter); + ConfigurationSource getSourceForDirectory(File directory,ConfigurationParser parser) { + return getSourceForConfigFile(ConfigurationFile.fromFile(new File(directory, LOMBOK_CONFIG_FILENAME)), parser); } - private ConfigurationSource getSourceForConfigFile(ConfigurationFile context, ConfigurationProblemReporter reporter) { + private ConfigurationSource getSourceForConfigFile(ConfigurationFile context, ConfigurationParser parser) { long now = System.currentTimeMillis(); Content content = ensureContent(context); synchronized (content) { @@ -160,7 +160,7 @@ public class FileSystemSourceCache { content.lastChecked = now; long previouslyModified = content.lastModified; content.lastModified = context.getLastModifiedOrMissing(); - if (content.lastModified != previouslyModified) content.source = content.lastModified == MISSING ? null : parse(context, reporter); + if (content.lastModified != previouslyModified) content.source = content.lastModified == MISSING ? null : parse(context, parser); return content.source; } } @@ -174,13 +174,8 @@ public class FileSystemSourceCache { return fileCache.get(context); } - private ConfigurationSource parse(ConfigurationFile context, ConfigurationProblemReporter reporter) { - try { - return StringConfigurationSource.forString(context.contents(), reporter, context); - } catch (Exception e) { - reporter.report(context.description(), "Exception while reading file: " + e.getMessage(), 0, null); - return null; - } + private ConfigurationSource parse(ConfigurationFile context, ConfigurationParser parser) { + return SingleConfigurationSource.parse(context, parser); } private static class Content { diff --git a/src/core/lombok/core/configuration/SingleConfigurationSource.java b/src/core/lombok/core/configuration/SingleConfigurationSource.java new file mode 100644 index 00000000..a5298339 --- /dev/null +++ b/src/core/lombok/core/configuration/SingleConfigurationSource.java @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2014-2020 The Project Lombok Authors. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package lombok.core.configuration; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import lombok.core.configuration.ConfigurationParser.Collector; + +public final class SingleConfigurationSource implements ConfigurationSource { + private final Map, Result> values; + private final List imports; + + public static ConfigurationSource parse(ConfigurationFile context, ConfigurationParser parser) { + final Map, Result> values = new HashMap, Result>(); + final List imports = new ArrayList(); + Collector collector = new Collector() { + @Override public void addImport(ConfigurationFile importFile, ConfigurationFile context, int lineNumber) { + imports.add(importFile); + } + + @Override public void clear(ConfigurationKey key, ConfigurationFile context, int lineNumber) { + values.put(key, new Result(null, true)); + } + + @Override public void set(ConfigurationKey key, Object value, ConfigurationFile context, int lineNumber) { + values.put(key, new Result(value, true)); + } + + @Override public void add(ConfigurationKey key, Object value, ConfigurationFile context, int lineNumber) { + modifyList(key, value, true); + } + + @Override public void remove(ConfigurationKey key, Object value, ConfigurationFile context, int lineNumber) { + modifyList(key, value, false); + } + + @SuppressWarnings("unchecked") + private void modifyList(ConfigurationKey key, Object value, boolean add) { + Result result = values.get(key); + List list; + if (result == null || result.getValue() == null) { + list = new ArrayList(); + values.put(key, new Result(list, result != null)); + } else { + list = (List) result.getValue(); + } + list.add(new ListModification(value, add)); + } + }; + parser.parse(context, collector); + return new SingleConfigurationSource(values, imports); + } + + private SingleConfigurationSource(Map, Result> values, List imports) { + this.values = new HashMap, Result>(); + for (Entry, Result> entry : values.entrySet()) { + Result result = entry.getValue(); + if (result.getValue() instanceof List) { + this.values.put(entry.getKey(), new Result(Collections.unmodifiableList((List) result.getValue()), result.isAuthoritative())); + } else { + this.values.put(entry.getKey(), result); + } + } + this.imports = Collections.unmodifiableList(imports); + } + + @Override + public Result resolve(ConfigurationKey key) { + return values.get(key); + } + + @Override + public List imports() { + return imports; + } +} diff --git a/src/core/lombok/core/configuration/StringConfigurationSource.java b/src/core/lombok/core/configuration/StringConfigurationSource.java deleted file mode 100644 index c1bd498e..00000000 --- a/src/core/lombok/core/configuration/StringConfigurationSource.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (C) 2014-2020 The Project Lombok Authors. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package lombok.core.configuration; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; - -import lombok.core.configuration.ConfigurationParser.Collector; - -public class StringConfigurationSource implements ConfigurationSource { - private final Map, Result> values; - - public static ConfigurationSource forString(CharSequence content, ConfigurationProblemReporter reporter, ConfigurationFile context) { - final Map, Result> values = new HashMap, Result>(); - - Collector collector = new Collector() { - @Override public void clear(ConfigurationKey key, ConfigurationFile context, int lineNumber) { - values.put(key, new Result(null, true)); - } - - @Override public void set(ConfigurationKey key, Object value, ConfigurationFile context, int lineNumber) { - values.put(key, new Result(value, true)); - } - - @Override public void add(ConfigurationKey key, Object value, ConfigurationFile context, int lineNumber) { - modifyList(key, value, true); - } - - @Override public void remove(ConfigurationKey key, Object value, ConfigurationFile context, int lineNumber) { - modifyList(key, value, false); - } - - @SuppressWarnings("unchecked") - private void modifyList(ConfigurationKey key, Object value, boolean add) { - Result result = values.get(key); - List list; - if (result == null || result.getValue() == null) { - list = new ArrayList(); - values.put(key, new Result(list, result != null)); - } else { - list = (List) result.getValue(); - } - list.add(new ListModification(value, add)); - } - }; - new ConfigurationParser(reporter).parse(content, context, collector); - return new StringConfigurationSource(values); - } - - private StringConfigurationSource(Map, Result> values) { - this.values = new HashMap, Result>(); - for (Entry, Result> entry : values.entrySet()) { - Result result = entry.getValue(); - if (result.getValue() instanceof List) { - this.values.put(entry.getKey(), new Result(Collections.unmodifiableList((List) result.getValue()), result.isAuthoritative())); - } else { - this.values.put(entry.getKey(), result); - } - } - } - - @Override - public Result resolve(ConfigurationKey key) { - return values.get(key); - } -} -- cgit