test_class.declarator: cake
test_class.modifier: private
test_class.original_string: private Cake cake;
test_class.type: Cake
test_class.var_name: cake
test_class.file: recipe-java-runtime/src/test/java/ca/derekcormier/recipe/CakeTest.java
test_class.identifier: CakeTest
test_case.body: @Test(expected = IllegalArgumentException.class)
    public void testGet_throwsOnNullKey() {
      cake.get(null);
    }
test_case.class_method_signature: CakeTest.testGet_throwsOnNullKey()
test_case.full_signature: @Test(expected = IllegalArgumentException.class) public void testGet_throwsOnNullKey()
test_case.identifier: testGet_throwsOnNullKey
test_case.invocations: get
test_case.modifiers: @Test(expected = IllegalArgumentException.class) public
test_case.parameters: ()
test_case.return: void
test_case.signature: void testGet_throwsOnNullKey()
focal_class.declarator: SEPARATOR = "."
focal_class.modifier: public static final
focal_class.original_string: public static final String SEPARATOR = ".";
focal_class.type: String
focal_class.var_name: SEPARATOR
focal_class.declarator: entries = new HashMap<>()
focal_class.modifier: private final
focal_class.original_string: private final Map<String, Object> entries = new HashMap<>();
focal_class.type: Map<String, Object>
focal_class.var_name: entries
focal_class.declarator: prefixStack = new LinkedList<>()
focal_class.modifier: private final
focal_class.original_string: private final LinkedList<String> prefixStack = new LinkedList<>();
focal_class.type: LinkedList<String>
focal_class.var_name: prefixStack
focal_class.file: recipe-java-runtime/src/main/java/ca/derekcormier/recipe/Cake.java
focal_class.identifier: Cake
focal_class.class_method_signature: Cake.Cake()
focal_class.full_signature: public  Cake()
focal_class.identifier: Cake
focal_class.modifiers: public
focal_class.parameters: ()
focal_class.signature:  Cake()
focal_class.class_method_signature: Cake.Cake(Cake other)
focal_class.full_signature: public  Cake(Cake other)
focal_class.identifier: Cake
focal_class.modifiers: public
focal_class.parameters: (Cake other)
focal_class.signature:  Cake(Cake other)
focal_class.class_method_signature: Cake.key(String... subKeys)
focal_class.full_signature: public static String key(String... subKeys)
focal_class.identifier: key
focal_class.modifiers: public static
focal_class.parameters: (String... subKeys)
focal_class.return: String
focal_class.signature: String key(String... subKeys)
focal_class.class_method_signature: Cake.validateKey(String key)
focal_class.full_signature: private static void validateKey(String key)
focal_class.identifier: validateKey
focal_class.modifiers: private static
focal_class.parameters: (String key)
focal_class.return: void
focal_class.signature: void validateKey(String key)
focal_class.class_method_signature: Cake.get(String... key)
focal_class.full_signature: @SuppressWarnings("unchecked") public T get(String... key)
focal_class.identifier: get
focal_class.modifiers: @SuppressWarnings("unchecked") public
focal_class.parameters: (String... key)
focal_class.return: T
focal_class.signature: T get(String... key)
focal_class.class_method_signature: Cake.get(Class<T> clazz, String... key)
focal_class.full_signature: @SuppressWarnings("unchecked") public T get(Class<T> clazz, String... key)
focal_class.identifier: get
focal_class.modifiers: @SuppressWarnings("unchecked") public
focal_class.parameters: (Class<T> clazz, String... key)
focal_class.return: T
focal_class.signature: T get(Class<T> clazz, String... key)
focal_class.class_method_signature: Cake.publish(String key, Object value)
focal_class.full_signature: public void publish(String key, Object value)
focal_class.identifier: publish
focal_class.modifiers: public
focal_class.parameters: (String key, Object value)
focal_class.return: void
focal_class.signature: void publish(String key, Object value)
focal_class.class_method_signature: Cake.inNamespace(String key, Runnable runnable)
focal_class.full_signature: public void inNamespace(String key, Runnable runnable)
focal_class.identifier: inNamespace
focal_class.modifiers: public
focal_class.parameters: (String key, Runnable runnable)
focal_class.return: void
focal_class.signature: void inNamespace(String key, Runnable runnable)
focal_class.class_method_signature: Cake.getPublishedKeyForValue(Object value, boolean fullyQualified)
focal_class.full_signature: public String getPublishedKeyForValue(Object value, boolean fullyQualified)
focal_class.identifier: getPublishedKeyForValue
focal_class.modifiers: public
focal_class.parameters: (Object value, boolean fullyQualified)
focal_class.return: String
focal_class.signature: String getPublishedKeyForValue(Object value, boolean fullyQualified)
focal_class.class_method_signature: Cake.getNamespace()
focal_class.full_signature: @JsonIgnore public String getNamespace()
focal_class.identifier: getNamespace
focal_class.modifiers: @JsonIgnore public
focal_class.parameters: ()
focal_class.return: String
focal_class.signature: String getNamespace()
focal_class.class_method_signature: Cake.hasContext()
focal_class.full_signature: public boolean hasContext()
focal_class.identifier: hasContext
focal_class.modifiers: public
focal_class.parameters: ()
focal_class.return: boolean
focal_class.signature: boolean hasContext()
focal_class.class_method_signature: Cake.getContext()
focal_class.full_signature: @JsonIgnore public T getContext()
focal_class.identifier: getContext
focal_class.modifiers: @JsonIgnore public
focal_class.parameters: ()
focal_class.return: T
focal_class.signature: T getContext()
focal_class.class_method_signature: Cake.getContext(Class<T> clazz)
focal_class.full_signature: @JsonIgnore @SuppressWarnings("unchecked") public T getContext(Class<T> clazz)
focal_class.identifier: getContext
focal_class.modifiers: @JsonIgnore @SuppressWarnings("unchecked") public
focal_class.parameters: (Class<T> clazz)
focal_class.return: T
focal_class.signature: T getContext(Class<T> clazz)
focal_class.class_method_signature: Cake.getOrGetContext(String... key)
focal_class.full_signature: @JsonIgnore public T getOrGetContext(String... key)
focal_class.identifier: getOrGetContext
focal_class.modifiers: @JsonIgnore public
focal_class.parameters: (String... key)
focal_class.return: T
focal_class.signature: T getOrGetContext(String... key)
focal_class.class_method_signature: Cake.getOrGetContext(Class<T> clazz, String... key)
focal_class.full_signature: @JsonIgnore public T getOrGetContext(Class<T> clazz, String... key)
focal_class.identifier: getOrGetContext
focal_class.modifiers: @JsonIgnore public
focal_class.parameters: (Class<T> clazz, String... key)
focal_class.return: T
focal_class.signature: T getOrGetContext(Class<T> clazz, String... key)
focal_class.class_method_signature: Cake.getSubKeysAndValidateFullKey(String fullKey)
focal_class.full_signature: private List<String> getSubKeysAndValidateFullKey(String fullKey)
focal_class.identifier: getSubKeysAndValidateFullKey
focal_class.modifiers: private
focal_class.parameters: (String fullKey)
focal_class.return: List<String>
focal_class.signature: List<String> getSubKeysAndValidateFullKey(String fullKey)
focal_class.class_method_signature: Cake.getPrefixWithSeparator(List<String> namespaces)
focal_class.full_signature: private String getPrefixWithSeparator(List<String> namespaces)
focal_class.identifier: getPrefixWithSeparator
focal_class.modifiers: private
focal_class.parameters: (List<String> namespaces)
focal_class.return: String
focal_class.signature: String getPrefixWithSeparator(List<String> namespaces)
focal_class.class_method_signature: Cake.getEntries()
focal_class.full_signature: @JsonAnyGetter protected Map<String, Object> getEntries()
focal_class.identifier: getEntries
focal_class.modifiers: @JsonAnyGetter protected
focal_class.parameters: ()
focal_class.return: Map<String, Object>
focal_class.signature: Map<String, Object> getEntries()
focal_class.class_method_signature: Cake.setEntry(String key, Object value)
focal_class.full_signature: @JsonAnySetter private void setEntry(String key, Object value)
focal_class.identifier: setEntry
focal_class.modifiers: @JsonAnySetter private
focal_class.parameters: (String key, Object value)
focal_class.return: void
focal_class.signature: void setEntry(String key, Object value)
focal_method.body: @SuppressWarnings("unchecked")
    public <T> T get(String... key) {
      List<String> keys =
          ((key == null) ? new ArrayList<String>() : Arrays.asList(key))
              .stream()
                  .flatMap(
                      k ->
                          Arrays.stream(
                              k == null ? new String[] {null} : StringUtils.split(k, Cake.SEPARATOR)))
                  .collect(Collectors.toList());
  
      if (keys.isEmpty()) {
        throw new IllegalArgumentException("cannot get value for empty key");
      }
  
      keys.forEach(Cake::validateKey);
      String fullKey = StringUtils.join(keys, Cake.SEPARATOR);
  
      // search within current namespace
      String searchKey = getPrefixWithSeparator(prefixStack) + fullKey;
      if (entries.containsKey(searchKey)) {
        return (T) entries.get(searchKey);
      }
  
      // search within each ancestor namespace up to the root
      LinkedList<String> namespaces = new LinkedList<>(prefixStack);
      while (!namespaces.isEmpty()) {
        namespaces.removeLast();
        searchKey = getPrefixWithSeparator(namespaces) + fullKey;
        if (entries.containsKey(searchKey)) {
          return (T) entries.get(searchKey);
        }
      }
  
      // search within any other namespace (if unambiguous)
      List<String> candidates =
          entries.keySet().stream()
              .filter(
                  k -> {
                    String[] subkeys = StringUtils.split(k, SEPARATOR);
                    if (keys.size() > subkeys.length) {
                      return false;
                    }
                    for (int i = 0; i < keys.size(); i++) {
                      if (!keys.get(keys.size() - 1 - i).equals(subkeys[subkeys.length - 1 - i])) {
                        return false;
                      }
                    }
                    return true;
                  })
              .collect(Collectors.toList());
  
      if (candidates.size() == 1) {
        return (T) entries.get(candidates.get(0));
      } else if (candidates.isEmpty()) {
        throw new RuntimeException(
            "cake does not contain key '" + fullKey + "; current keys: " + this.entries.keySet());
      } else {
        throw new RuntimeException(
            "cannot retrieve ambiguous key '" + fullKey + "'; candidates: " + candidates);
      }
    }
focal_method.class_method_signature: Cake.get(String... key)
focal_method.full_signature: @SuppressWarnings("unchecked") public T get(String... key)
focal_method.identifier: get
focal_method.invocations: collect flatMap stream asList stream split toList isEmpty forEach join getPrefixWithSeparator containsKey get isEmpty removeLast getPrefixWithSeparator containsKey get collect filter stream keySet split size size equals get size toList size get get isEmpty keySet
focal_method.modifiers: @SuppressWarnings("unchecked") public
focal_method.parameters: (String... key)
focal_method.return: T
focal_method.signature: T get(String... key)