### Question:
CodestartPathProcessor { static String process(String relativePath, Map<String, Object> data) { if (!relativePath.contains("{")) { return relativePath; } Matcher m = EXPRESSION_PATTERN.matcher(relativePath); StringBuffer result = new StringBuffer(); while (m.find()) { String found = m.group(1); String key = found.replace(PACKAGE_NAME_DIR_EXPRESSION, PACKAGE_NAME_KEY); String value = NestedMaps.<String> getValue(data, key) .orElseThrow(() -> new CodestartStructureException("Missing required data for PathGen: {" + key + "}")); if (found.contains(PACKAGE_NAME_DIR_EXPRESSION) && value.contains(".")) { value = value.replace(".", "/"); } m.appendReplacement(result, value); } m.appendTail(result); return result.toString(); } private  CodestartPathProcessor();   }### Answer:
@Test void testProcess() { Map<String, Object> dataFlat = new HashMap<>(); dataFlat.put("foo.bar", "vfoobar"); dataFlat.put("baz", "vbaz"); dataFlat.put("package-name", "org.acme.andy"); dataFlat.put("class-name", "MyResource"); final Map<String, Object> data = unflatten(dataFlat); assertThat(CodestartPathProcessor.process("/foo/bar/{foo.bar}/baz", data)) .isEqualTo("/foo/bar/vfoobar/baz"); assertThat(CodestartPathProcessor.process("{foo.bar}", data)) .isEqualTo("vfoobar"); assertThat(CodestartPathProcessor.process("{foo.bar}/{foo.bar}", data)) .isEqualTo("vfoobar/vfoobar"); assertThat(CodestartPathProcessor.process("{foo.bar}/{baz}", data)) .isEqualTo("vfoobar/vbaz"); assertThat(CodestartPathProcessor.process("{foo.bar}/{baz}.txt", data)) .isEqualTo("vfoobar/vbaz.txt"); assertThat(CodestartPathProcessor.process("src/main/java/{package-name.dir}/{class-name}.java", data)) .isEqualTo("src/main/java/org/acme/andy/MyResource.java"); assertThat(CodestartPathProcessor.process("src/main/java/{package-name}/{class-name}.java", data)) .isEqualTo("src/main/java/org.acme.andy/MyResource.java"); assertThat(CodestartPathProcessor.process("foo/bar.txt", data)) .isEqualTo("foo/bar.txt"); assertThatExceptionOfType(CodestartStructureException.class) .isThrownBy(() -> CodestartPathProcessor.process("{foo.bar}/{baz}/{foo.baz}.txt", data)) .withMessageContaining("{foo.baz}"); }