import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
// pom.xml の「書いていない値が埋まる」仕組みの模型(Maven の実装ではない)。
// 子 POM → 親 POM → その親 → Super POM の順にたどり、
// (1) properties は子が親を上書きし、${X} は値に置き換える
// (2) dependencies に version / scope が無ければ dependencyManagement から補う
// (3) packaging が無ければ jar
// (4) repositories は連鎖の全部を集める(central は Super POM の <repositories> にある)
// 値は、Boot 4.1.1 の雛形と親 POM に実際に書かれていたもの(effective-pom で確認)。
class Main {
record Dep(String artifactId, String version, String scope) {}
record Pom(String name, Map<String, String> properties, Map<String, String> managedVersions,
List<Dep> dependencies, List<String> repositories, String packaging, Pom parent) {}
// 親の連鎖を根(Super POM)まで並べる: [子, 親, 親の親, Super POM]
static List<Pom> chain(Pom pom) {
var list = new java.util.ArrayList<Pom>();
for (Pom p = pom; p != null; p = p.parent()) list.add(p);
return list;
}
// (1) properties: 根から順に重ね、子が後から上書きする
static Map<String, String> effectiveProperties(Pom pom) {
var chain = chain(pom);
var merged = new LinkedHashMap<String, String>();
for (int i = chain.size() - 1; i >= 0; i--) merged.putAll(chain.get(i).properties());
// ${X} を値に置き換える(1段だけ。模型なので入れ子は扱わない)
for (var e : merged.entrySet()) {
String v = e.getValue();
int s = v.indexOf("${");
if (s >= 0) {
String key = v.substring(s + 2, v.indexOf('}', s));
e.setValue(v.replace("${" + key + "}", merged.getOrDefault(key, "?")));
}
}
return merged;
}
// (2) dependencyManagement: 連鎖のどこかに版があれば、それで補う
static String managedVersion(Pom pom, String artifactId) {
for (Pom p : chain(pom)) {
String v = p.managedVersions().get(artifactId);
if (v != null) return v + " (from " + p.name() + ")";
}
return "?? (no version anywhere in the chain)";
}
public static void main(String[] args) {
// Super POM: すべての POM の土台。中央リポジトリの URL はここに書かれている
Pom superPom = new Pom("Super POM", Map.of(), Map.of(), List.of(),
List.of("central = https://repo.maven.apache.org/maven2"), null, null);
// spring-boot-dependencies 4.1.1: 版の一覧表(BOM)。dependencyManagement だけを持つ
Pom bom = new Pom("spring-boot-dependencies:4.1.1", Map.of(),
Map.of("spring-boot-starter-webmvc", "4.1.1", "spring-boot-starter-webmvc-test", "4.1.1"),
List.of(), List.of(), null, superPom);
// spring-boot-starter-parent 4.1.1: 親 POM 14-17 行目に実際に書かれていた properties
var parentProps = new LinkedHashMap<String, String>(); // 親 POM に書かれている順
parentProps.put("java.version", "17");
parentProps.put("resource.delimiter", "@");
parentProps.put("maven.compiler.release", "${java.version}");
parentProps.put("project.build.sourceEncoding", "UTF-8");
Pom parent = new Pom("spring-boot-starter-parent:4.1.1", parentProps, Map.of(), List.of(), List.of(), null, bom);
// 雛形の pom.xml: java.version だけ上書きし、依存 2 本には version を書いていない
Pom demo = new Pom("com.example:demo:0.0.1-SNAPSHOT", Map.of("java.version", "25"), Map.of(),
List.of(new Dep("spring-boot-starter-webmvc", null, null),
new Dep("spring-boot-starter-webmvc-test", null, "test")),
List.of(), null, parent);
System.out.println("## parent chain (child first)");
for (Pom p : chain(demo)) System.out.println(" " + p.name());
System.out.println();
System.out.println("## (1) effective properties");
effectiveProperties(demo).forEach((k, v) -> System.out.println(" " + k + " = " + v));
System.out.println();
System.out.println("## (2) effective dependencies");
for (Dep d : demo.dependencies()) {
String version = d.version() != null ? d.version() : managedVersion(demo, d.artifactId());
String scope = d.scope() != null ? d.scope() : "compile (default when not specified)";
System.out.println(" " + d.artifactId());
System.out.println(" version: " + version);
System.out.println(" scope : " + scope);
}
System.out.println();
System.out.println("## (3) effective packaging");
String packaging = demo.packaging() != null ? demo.packaging() : "jar";
System.out.println(" " + packaging + " (the pom wrote nothing; jar is the default)");
System.out.println();
System.out.println("## (4) effective repositories");
for (Pom p : chain(demo)) for (String r : p.repositories()) System.out.println(" " + r + " (from " + p.name() + ")");
}
}
// 出力(JDK 22 で実行)
// ## parent chain (child first)
// com.example:demo:0.0.1-SNAPSHOT
// spring-boot-starter-parent:4.1.1
// spring-boot-dependencies:4.1.1
// Super POM
//
// ## (1) effective properties
// java.version = 25
// resource.delimiter = @
// maven.compiler.release = 25
// project.build.sourceEncoding = UTF-8
//
// ## (2) effective dependencies
// spring-boot-starter-webmvc
// version: 4.1.1 (from spring-boot-dependencies:4.1.1)
// scope : compile (default when not specified)
// spring-boot-starter-webmvc-test
// version: 4.1.1 (from spring-boot-dependencies:4.1.1)
// scope : test
//
// ## (3) effective packaging
// jar (the pom wrote nothing; jar is the default)
//
// ## (4) effective repositories
// central = https://repo.maven.apache.org/maven2 (from Super POM)