From 76c8e0205250e2289417ccc7063c0e94b442037c Mon Sep 17 00:00:00 2001
From: Rawvoid
Date: Sun, 2 Aug 2026 15:37:20 +0800
Subject: [PATCH 01/10] fix(rename-class): improve conflict and rename log
readability
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Aggregate rename conflicts into one multi-line WARN with old→new detail
lines (simple-name, ancestor-nested, object-factory). Log each applied
rename at DEBUG and keep INFO as a count only. Enrich invalid mapping
warnings with the rule pattern.
---
.../jaxb/plugin/RenameClassPlugin.java | 131 ++++++++++++------
1 file changed, 90 insertions(+), 41 deletions(-)
diff --git a/plugins/src/main/java/io/github/rawvoid/jaxb/plugin/RenameClassPlugin.java b/plugins/src/main/java/io/github/rawvoid/jaxb/plugin/RenameClassPlugin.java
index 4c94f0b..1e22d73 100644
--- a/plugins/src/main/java/io/github/rawvoid/jaxb/plugin/RenameClassPlugin.java
+++ b/plugins/src/main/java/io/github/rawvoid/jaxb/plugin/RenameClassPlugin.java
@@ -72,7 +72,8 @@
*
*
* Conflict policy. Conflicting types keep their original names; non-conflicting
- * renames still apply. Conflicts are reported as warnings (build does not fail). Checks cover:
+ * renames still apply. Conflicts are reported as a single non-fatal warning with one detail
+ * line per clash ({@code old→new}). Checks cover:
*
*
* - Same simple name under one parent (beans / enums / element classes)
@@ -85,6 +86,10 @@
* {@code getSqueezedName()} after writing provisional short names onto the model
*
*
+ * Logging: each applied rename is {@code DEBUG}; the total count is {@code INFO}. Conflicts
+ * are one {@code WARN} (summary + detail lines). Invalid mapping/strip results are {@code WARN}.
+ *
+ *
* When both this plugin and {@link PromoteNestedClassPlugin} are active, running rename
* before promote lets named global types claim short names first; promote-first is
* safer for some ObjectFactory edge cases but can leave dual names ({@code Foo} + {@code FooType}).
@@ -136,7 +141,6 @@ private static List collect(Model model) {
var result = new ArrayList();
for (var bean : model.beans().values()) {
result.add(new Candidate(
- "bean",
bean.shortName,
bean.fullName(),
bean.parent(),
@@ -148,7 +152,6 @@ private static List collect(Model model) {
}
for (var enumInfo : model.enums().values()) {
result.add(new Candidate(
- "enum",
enumInfo.shortName,
enumInfo.fullName(),
enumInfo.parent,
@@ -163,7 +166,6 @@ private static List collect(Model model) {
continue;
}
result.add(new Candidate(
- "element",
element.shortName(),
element.fullName(),
element.parent,
@@ -176,6 +178,33 @@ private static List collect(Model model) {
return result;
}
+ /** {@code Original→Desired} for a provisional rename (or unchanged name). */
+ private static String arrow(Candidate candidate, Map names) {
+ var desired = names.get(candidate);
+ return candidate.shortName.equals(desired)
+ ? candidate.shortName
+ : candidate.shortName + "→" + desired;
+ }
+
+ private static String joinArrows(Collection group, Map names) {
+ var parts = new ArrayList(group.size());
+ for (var candidate : group) {
+ parts.add(arrow(candidate, names));
+ }
+ return String.join(", ", parts);
+ }
+
+ private static void reportConflicts(List conflicts) {
+ if (conflicts.isEmpty()) {
+ return;
+ }
+ log.warn(
+ "Blocked {} rename conflict(s); kept original name(s):\n {}",
+ conflicts.size(),
+ String.join("\n ", conflicts)
+ );
+ }
+
private static String localPart(QName typeName) {
return typeName == null ? null : typeName.getLocalPart();
}
@@ -241,9 +270,11 @@ public void postProcessModel(Model model, ErrorHandler errorHandler) {
names.put(candidate, mapName(candidate));
}
- blockDuplicateSimpleNames(model, candidates, names);
- blockParentChildClashes(candidates, names);
- blockObjectFactoryClashes(model, candidates, names);
+ var conflicts = new ArrayList();
+ blockDuplicateSimpleNames(model, candidates, names, conflicts);
+ blockParentChildClashes(candidates, names, conflicts);
+ blockObjectFactoryClashes(model, candidates, names, conflicts);
+ reportConflicts(conflicts);
var renamed = 0;
for (var candidate : candidates) {
@@ -251,6 +282,7 @@ public void postProcessModel(Model model, ErrorHandler errorHandler) {
if (!next.equals(candidate.shortName)) {
candidate.apply.accept(next);
renamed++;
+ log.debug("Renamed {} → {}", candidate.shortName, next);
}
}
if (renamed > 0) {
@@ -270,7 +302,8 @@ public boolean run(Outline outline, Options opt, ErrorHandler errorHandler) {
private void blockDuplicateSimpleNames(
Model model,
List candidates,
- Map names
+ Map names,
+ List conflicts
) {
// Slot: (parent, case-insensitive desired name). size > 1 → conflict group.
Map> bySlot = new LinkedHashMap<>();
@@ -285,22 +318,15 @@ private void blockDuplicateSimpleNames(
if (group.size() <= 1 || !anyPending(group, names)) {
continue;
}
- // Prefer a desired name that was actually produced by a rename (original case).
- var desired = group.stream()
- .filter(c -> isPending(c, names))
- .map(names::get)
- .findFirst()
- .orElseGet(() -> names.get(group.getFirst()));
- var involved = group.stream().map(c -> c.fullName).toList();
+ conflicts.add(
+ "simple-name under '"
+ + parentLabel(group.getFirst().parent)
+ + "': "
+ + joinArrows(group, names)
+ );
for (var candidate : group) {
names.put(candidate, candidate.shortName);
}
- log.warn(
- "Class name conflict after rename under '{}': desired '{}' for {}; keeping original names",
- parentLabel(group.getFirst().parent),
- desired,
- involved
- );
}
}
@@ -313,14 +339,15 @@ private void blockDuplicateSimpleNames(
*/
private void blockParentChildClashes(
List candidates,
- Map names
+ Map names,
+ List conflicts
) {
var beans = beansByClass(candidates);
boolean changed;
do {
changed = false;
for (var child : candidates) {
- if (revertAncestorNameClash(child, beans, names)) {
+ if (revertAncestorNameClash(child, beans, names, conflicts)) {
changed = true;
}
}
@@ -329,14 +356,15 @@ private void blockParentChildClashes(
/**
* When {@code child} and any enclosing bean would share a simple name after rename,
- * reverts one of them (prefer the ancestor) and reports a warning.
+ * reverts one of them (prefer the ancestor) and records a conflict detail.
*
* @return {@code true} if a rename was reverted
*/
private boolean revertAncestorNameClash(
Candidate child,
Map beans,
- Map names
+ Map names,
+ List conflicts
) {
var childName = normalize(names.get(child));
CClassInfoParent current = child.parent;
@@ -348,13 +376,31 @@ private boolean revertAncestorNameClash(
if (undo == null) {
return false;
}
+ var undoDesired = names.get(undo);
+ if (undo == ancestor) {
+ conflicts.add(
+ "ancestor-nested: "
+ + ancestor.shortName
+ + "→"
+ + undoDesired
+ + " conflicts with nested "
+ + child.fullName
+ + "; kept "
+ + ancestor.shortName
+ );
+ } else {
+ conflicts.add(
+ "ancestor-nested: nested "
+ + child.fullName
+ + "→"
+ + undoDesired
+ + " conflicts with ancestor "
+ + ancestor.fullName
+ + "; kept "
+ + child.shortName
+ );
+ }
names.put(undo, undo.shortName);
- log.warn(
- "Ancestor-nested name conflict after rename ('{}' / '{}'); keeping original name for {}",
- ancestor.fullName,
- child.fullName,
- undo.fullName
- );
return true;
}
current = parentBean.parent();
@@ -377,7 +423,8 @@ private boolean revertAncestorNameClash(
private void blockObjectFactoryClashes(
Model model,
List candidates,
- Map names
+ Map names,
+ List conflicts
) {
var beans = beansByClass(candidates);
if (beans.isEmpty()) {
@@ -402,17 +449,18 @@ private void blockObjectFactoryClashes(
// Clash already present with original names — XJC will report it; nothing we can undo.
continue;
}
- // Capture squeezed name before reverts change short names on the model.
+ // Capture squeezed name and arrows before reverts change short names on the model.
var squeezed = group.getFirst().getSqueezedName();
+ conflicts.add(
+ "object-factory: squeezed '"
+ + squeezed
+ + "'; "
+ + joinArrows(toRevert, names)
+ );
for (var candidate : toRevert) {
names.put(candidate, candidate.shortName);
setFieldValue(CCLASSINFO_SHORTNAME_FIELD, candidate.bean, candidate.shortName);
}
- log.warn(
- "ObjectFactory name conflict '{}'; keeping original name(s) for {}",
- squeezed,
- toRevert.stream().map(c -> c.fullName).toList()
- );
changed = true;
}
} while (changed);
@@ -435,8 +483,10 @@ private String mapName(Candidate candidate) {
}
if (!JJavaName.isJavaIdentifier(next)) {
log.warn(
- "Invalid Java class name after mapping: '{}' (from {}); skipping rule",
+ "Invalid Java class name '{}' after mapping /{}/->{} on {}; skipping rule",
next,
+ mapping.from.pattern(),
+ mapping.to,
candidate.fullName
);
continue;
@@ -449,7 +499,7 @@ private String mapName(Candidate candidate) {
if (stripped != null && !stripped.equals(current)) {
if (!JJavaName.isJavaIdentifier(stripped)) {
log.warn(
- "Invalid Java class name after Type suffix strip: '{}' (from {}); skipping strip",
+ "Invalid Java class name '{}' after Type suffix strip on {}; skipping strip",
stripped,
candidate.fullName
);
@@ -522,7 +572,6 @@ public static class MappingConfig {
* named; {@code null} for anonymous beans and element classes.
*/
private record Candidate(
- String kind,
String shortName,
String fullName,
CClassInfoParent parent,
From 52b072bb46897038af441d50626dd5957a08aae7 Mon Sep 17 00:00:00 2001
From: Rawvoid
Date: Sun, 2 Aug 2026 16:05:22 +0800
Subject: [PATCH 02/10] fix(element-wrapper): align logging with rename-class
style
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Use DEBUG for each flatten with Owner.prop → Wrapper, INFO summaries with
counts for flatten/remove, and multi-line WARN for kept wrappers (with
reason) and stale annotation owners after later model merges.
---
.../jaxb/plugin/ElementWrapperPlugin.java | 73 ++++++++++++++-----
1 file changed, 53 insertions(+), 20 deletions(-)
diff --git a/plugins/src/main/java/io/github/rawvoid/jaxb/plugin/ElementWrapperPlugin.java b/plugins/src/main/java/io/github/rawvoid/jaxb/plugin/ElementWrapperPlugin.java
index 2ef0eef..7045170 100644
--- a/plugins/src/main/java/io/github/rawvoid/jaxb/plugin/ElementWrapperPlugin.java
+++ b/plugins/src/main/java/io/github/rawvoid/jaxb/plugin/ElementWrapperPlugin.java
@@ -76,6 +76,12 @@
* rewrites that shape into a repeated element list with
* {@code @XmlElementWrapper(nillable = true)} and drops the synthetic local element info.
*
+ *
+ * Logging: each flattened field is {@code DEBUG}; the flatten count and removed wrapper list
+ * are {@code INFO}. Skipped wrapper removals and stale annotation owners (plugin-order
+ * issues) are one multi-line {@code WARN} each. Per-field flatten failures stay single-line
+ * {@code WARN}.
+ *
*
* @author Rawvoid
*/
@@ -136,22 +142,25 @@ public void postProcessModel(Model model, ErrorHandler errorHandler) {
@Override
public boolean run(Outline outline, Options opt, ErrorHandler errorHandler) throws SAXException {
+ var skipped = new ArrayList();
for (var flattened : flattenedFields) {
// Never use Outline#getClazz to test liveness: it lazily creates ClassOutline for
// beans already removed from the model and desynchronizes beans vs classes.
if (!outline.getModel().beans().containsValue(flattened.owner())) {
// Stale after a later merge (e.g. dedupe): the class is not generated. Isomorphic
// hosts already have their own FlattenedField from this plugin's model pass.
- log.info(
- "Skipping @XmlElementWrapper for removed flatten owner '{}' property '{}' "
- + "(prefer -Xelement-wrapper after other model-mutating plugins)",
- flattened.owner().fullName(),
- flattened.propertyName()
- );
+ skipped.add("%s.%s".formatted(flattened.owner().fullName(), flattened.propertyName()));
continue;
}
annotateXmlElementWrapper(outline, flattened);
}
+ if (!skipped.isEmpty()) {
+ log.warn(
+ "Skipped {} @XmlElementWrapper annotation(s); owner removed (prefer -Xelement-wrapper after other model-mutating plugins):\n {}",
+ skipped.size(),
+ String.join("\n ", skipped)
+ );
+ }
return true;
}
@@ -205,12 +214,19 @@ private void flattenOwner(
if (resolved.orphanElementInfo() != null
&& !removeElementInfo(model, resolved.orphanElementInfo())) {
- log.warn("Could not remove synthetic element info for {}.{}",
- owner.fullName(), outer.getName(false));
+ log.warn(
+ "Could not remove synthetic element info for {}.{}",
+ owner.fullName(),
+ outer.getName(false)
+ );
}
- log.debug("Flattened {}.{} (wrapper {})",
- owner.fullName(), outer.getName(false), resolved.wrapper().fullName());
+ log.debug(
+ "Flattened {}.{} → {}",
+ owner.fullName(),
+ outer.getName(false),
+ resolved.wrapper().fullName()
+ );
}
}
@@ -367,8 +383,11 @@ private boolean replaceProperty(
CElementPropertyInfo replacement
) {
if (replacement.ref().isEmpty()) {
- log.warn("Skip flattening {}.{}: replacement has no type refs",
- owner.fullName(), outer.getName(false));
+ log.warn(
+ "Skip flattening {}.{}: replacement has no type refs",
+ owner.fullName(),
+ outer.getName(false)
+ );
return false;
}
@@ -378,8 +397,11 @@ private boolean replaceProperty(
owner.addProperty(replacement);
if (properties.size() != sizeBefore + 1 || properties.getLast() != replacement) {
// addProperty no-op'd — model unchanged.
- log.warn("Skip flattening {}.{}: addProperty did not append the replacement",
- owner.fullName(), outer.getName(false));
+ log.warn(
+ "Skip flattening {}.{}: addProperty did not append the replacement",
+ owner.fullName(),
+ outer.getName(false)
+ );
return false;
}
@@ -402,21 +424,29 @@ private void removeUnusedWrappers(Model model, Set wrappers) {
continue;
}
if (isReferenced(model, wrapper)) {
- kept.add(wrapper.fullName());
+ kept.add("%s (still referenced)".formatted(wrapper.fullName()));
continue;
}
if (removeClass(model, wrapper)) {
removed.add(wrapper.fullName());
} else {
- kept.add(wrapper.fullName());
+ kept.add("%s (removeClass failed)".formatted(wrapper.fullName()));
}
}
if (!removed.isEmpty()) {
- log.info("Removed wrapper classes:\n {}", String.join("\n ", removed));
+ log.info(
+ "Removed {} wrapper class(es):\n {}",
+ removed.size(),
+ String.join("\n ", removed)
+ );
}
if (!kept.isEmpty()) {
- log.warn("Skipped removing wrapper classes:\n {}", String.join("\n ", kept));
+ log.warn(
+ "Skipped removing {} wrapper class(es):\n {}",
+ kept.size(),
+ String.join("\n ", kept)
+ );
}
}
@@ -467,8 +497,11 @@ private void annotateXmlElementWrapper(Outline outline, FlattenedField flattened
var classOutline = outline.getClazz(flattened.owner());
var field = classOutline.implClass.fields().get(flattened.propertyName());
if (field == null) {
- log.warn("Could not find field {} on {}",
- flattened.propertyName(), flattened.owner().fullName());
+ log.warn(
+ "Could not find field {} on {}",
+ flattened.propertyName(),
+ flattened.owner().fullName()
+ );
return;
}
From cc5f575e661b113238ba12767483ae1e23e5176a Mon Sep 17 00:00:00 2001
From: Rawvoid
Date: Sun, 2 Aug 2026 15:51:32 +0800
Subject: [PATCH 03/10] refactor(rename-class): prefer formatted templates in
conflict messages
Replace string concatenation with String.formatted for conflict detail
lines and arrow formatting; keep SLF4J placeholders for actual log calls.
---
.../jaxb/plugin/RenameClassPlugin.java | 43 ++++++-------------
1 file changed, 14 insertions(+), 29 deletions(-)
diff --git a/plugins/src/main/java/io/github/rawvoid/jaxb/plugin/RenameClassPlugin.java b/plugins/src/main/java/io/github/rawvoid/jaxb/plugin/RenameClassPlugin.java
index 1e22d73..a9cedeb 100644
--- a/plugins/src/main/java/io/github/rawvoid/jaxb/plugin/RenameClassPlugin.java
+++ b/plugins/src/main/java/io/github/rawvoid/jaxb/plugin/RenameClassPlugin.java
@@ -183,7 +183,7 @@ private static String arrow(Candidate candidate, Map names) {
var desired = names.get(candidate);
return candidate.shortName.equals(desired)
? candidate.shortName
- : candidate.shortName + "→" + desired;
+ : "%s→%s".formatted(candidate.shortName, desired);
}
private static String joinArrows(Collection group, Map names) {
@@ -318,12 +318,10 @@ private void blockDuplicateSimpleNames(
if (group.size() <= 1 || !anyPending(group, names)) {
continue;
}
- conflicts.add(
- "simple-name under '"
- + parentLabel(group.getFirst().parent)
- + "': "
- + joinArrows(group, names)
- );
+ conflicts.add("simple-name under '%s': %s".formatted(
+ parentLabel(group.getFirst().parent),
+ joinArrows(group, names)
+ ));
for (var candidate : group) {
names.put(candidate, candidate.shortName);
}
@@ -379,25 +377,15 @@ private boolean revertAncestorNameClash(
var undoDesired = names.get(undo);
if (undo == ancestor) {
conflicts.add(
- "ancestor-nested: "
- + ancestor.shortName
- + "→"
- + undoDesired
- + " conflicts with nested "
- + child.fullName
- + "; kept "
- + ancestor.shortName
+ "ancestor-nested: %s→%s conflicts with nested %s; kept %s".formatted(
+ ancestor.shortName, undoDesired, child.fullName, ancestor.shortName
+ )
);
} else {
conflicts.add(
- "ancestor-nested: nested "
- + child.fullName
- + "→"
- + undoDesired
- + " conflicts with ancestor "
- + ancestor.fullName
- + "; kept "
- + child.shortName
+ "ancestor-nested: nested %s→%s conflicts with ancestor %s; kept %s".formatted(
+ child.fullName, undoDesired, ancestor.fullName, child.shortName
+ )
);
}
names.put(undo, undo.shortName);
@@ -451,12 +439,9 @@ private void blockObjectFactoryClashes(
}
// Capture squeezed name and arrows before reverts change short names on the model.
var squeezed = group.getFirst().getSqueezedName();
- conflicts.add(
- "object-factory: squeezed '"
- + squeezed
- + "'; "
- + joinArrows(toRevert, names)
- );
+ conflicts.add("object-factory: squeezed '%s'; %s".formatted(
+ squeezed, joinArrows(toRevert, names)
+ ));
for (var candidate : toRevert) {
names.put(candidate, candidate.shortName);
setFieldValue(CCLASSINFO_SHORTNAME_FIELD, candidate.bean, candidate.shortName);
From b58a6841d0b4a38d792a8cbcc72a8d67fa399c8a Mon Sep 17 00:00:00 2001
From: Rawvoid
Date: Sun, 2 Aug 2026 16:14:51 +0800
Subject: [PATCH 04/10] fix(element-wrapper): log removed wrapper names at
DEBUG
Keep INFO as the removed count only; emit the class list at DEBUG so default
Maven builds stay quiet while details remain available when debugging.
---
.../rawvoid/jaxb/plugin/ElementWrapperPlugin.java | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/plugins/src/main/java/io/github/rawvoid/jaxb/plugin/ElementWrapperPlugin.java b/plugins/src/main/java/io/github/rawvoid/jaxb/plugin/ElementWrapperPlugin.java
index 7045170..bfc2105 100644
--- a/plugins/src/main/java/io/github/rawvoid/jaxb/plugin/ElementWrapperPlugin.java
+++ b/plugins/src/main/java/io/github/rawvoid/jaxb/plugin/ElementWrapperPlugin.java
@@ -77,10 +77,10 @@
* {@code @XmlElementWrapper(nillable = true)} and drops the synthetic local element info.
*
*
- * Logging: each flattened field is {@code DEBUG}; the flatten count and removed wrapper list
- * are {@code INFO}. Skipped wrapper removals and stale annotation owners (plugin-order
- * issues) are one multi-line {@code WARN} each. Per-field flatten failures stay single-line
- * {@code WARN}.
+ * Logging: each flattened field and the removed-wrapper name list are {@code DEBUG}; the
+ * flatten count and removed-wrapper count are {@code INFO}. Skipped wrapper removals and
+ * stale annotation owners (plugin-order issues) are one multi-line {@code WARN} each.
+ * Per-field flatten failures stay single-line {@code WARN}.
*
*
* @author Rawvoid
@@ -435,9 +435,9 @@ private void removeUnusedWrappers(Model model, Set wrappers) {
}
if (!removed.isEmpty()) {
- log.info(
- "Removed {} wrapper class(es):\n {}",
- removed.size(),
+ log.info("Removed {} wrapper class(es)", removed.size());
+ log.debug(
+ "Removed wrapper class(es):\n {}",
String.join("\n ", removed)
);
}
From 2b9a05209adbf4c258766e5a70084e6838bc8c32 Mon Sep 17 00:00:00 2001
From: Rawvoid
Date: Sun, 2 Aug 2026 16:18:55 +0800
Subject: [PATCH 05/10] fix(dedupe-class): align logging with
rename/element-wrapper style
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Log each accepted merge and enum merge at DEBUG with victim → host form;
keep INFO for merge and element-class-clear counts only. Aggregate
ObjectFactory collisions into one multi-line WARN.
---
.../jaxb/plugin/DedupeClassPlugin.java | 60 +++++++++++++------
1 file changed, 43 insertions(+), 17 deletions(-)
diff --git a/plugins/src/main/java/io/github/rawvoid/jaxb/plugin/DedupeClassPlugin.java b/plugins/src/main/java/io/github/rawvoid/jaxb/plugin/DedupeClassPlugin.java
index fca2b9c..d6394d7 100644
--- a/plugins/src/main/java/io/github/rawvoid/jaxb/plugin/DedupeClassPlugin.java
+++ b/plugins/src/main/java/io/github/rawvoid/jaxb/plugin/DedupeClassPlugin.java
@@ -93,6 +93,12 @@
* Shell-to-shell exact merges remain allowed. Default is auto: on when
* {@code -Xelement-wrapper} is also active; force with {@code true}/{@code false}.
*
+ *
+ * Logging: each accepted merge is {@code DEBUG}; merge and element-class-clear counts are
+ * {@code INFO}. Routine skips stay {@code DEBUG}; element-class root mismatches and
+ * ObjectFactory collisions after dedupe are {@code WARN} (ObjectFactory: one multi-line
+ * summary).
+ *
*
* @author Rawvoid
*/
@@ -869,7 +875,11 @@ public void postProcessModel(Model model, ErrorHandler errorHandler) {
warnObjectFactoryCollisions(model);
}
if (merged > 0) {
- log.info("Deduped {} bean merge(s){}", merged, session.dry ? " (dry-run)" : "");
+ if (session.dry) {
+ log.info("Deduped {} bean merge(s) (dry-run)", merged);
+ } else {
+ log.info("Deduped {} bean merge(s)", merged);
+ }
}
}
@@ -1019,7 +1029,7 @@ private boolean tryMerge(
if (!isPackageLevel(host) && host.parent() != victim.parent() && !allowCrossNestedParent) {
log.debug(
- "Skip dedupe {}: cross-hierarchy nested '{}' vs '{}'",
+ "Skip dedupe {}: cross-hierarchy nested {} vs {}",
reason, victim.fullName(), host.fullName()
);
return false;
@@ -1028,11 +1038,11 @@ private boolean tryMerge(
if (victim.isElement() && host.isElement()
&& !Objects.equals(victim.getElementName(), host.getElementName())) {
log.warn(
- "Skip dedupe {}: both '{}' and '{}' are element-classes with different roots ({} vs {})",
+ "Skip dedupe {}: both element-classes with different roots: {} ({}) vs {} ({})",
reason,
victim.fullName(),
- host.fullName(),
victim.getElementName(),
+ host.fullName(),
host.getElementName()
);
return false;
@@ -1044,7 +1054,7 @@ private boolean tryMerge(
&& ModelUtils.isPureCollectionShell(victim)
&& !ModelUtils.isPureCollectionShell(host)) {
log.debug(
- "Skip dedupe {}: pure collection shell '{}' must not merge into non-shell '{}'",
+ "Skip dedupe {}: pure collection shell {} must not merge into non-shell {}",
reason, victim.fullName(), host.fullName()
);
return false;
@@ -1057,8 +1067,8 @@ private boolean tryMerge(
return false;
}
- log.info(
- "Dedupe {}: '{}' -> '{}' (nameKey={})",
+ log.debug(
+ "Dedupe {}: {} → {} (nameKey={})",
reason, victim.fullName(), host.fullName(), nameKey(victim.shortName)
);
@@ -1102,7 +1112,11 @@ private boolean prepareNestedMerges(Model model, Session session, CClassInfo vic
var childNorm = child.shortName.toLowerCase(Locale.ROOT);
for (var hc : directNestedBeans(model, host)) {
if (hc.shortName.toLowerCase(Locale.ROOT).equals(childNorm)) {
- log.debug("Skip dedupe: nested name clash {} under {}", child.shortName, host.fullName());
+ log.debug(
+ "Skip dedupe: nested name clash {} under {}",
+ child.shortName,
+ host.fullName()
+ );
return false;
}
}
@@ -1165,9 +1179,10 @@ private boolean prepareNestedEnums(Model model, Session session, CClassInfo vict
}
}
if (match != null) {
- log.info(
- "Dedupe exact-enum: '{}' -> '{}'",
- fullEnumName(victimEnum), fullEnumName(match)
+ log.debug(
+ "Dedupe exact-enum: {} → {}",
+ fullEnumName(victimEnum),
+ fullEnumName(match)
);
session.countedMerges.add(IdentityPair.directed(victimEnum, match));
if (!session.dry) {
@@ -1298,7 +1313,7 @@ private static void collapseRedundantElementClasses(Model model, Set mer
if (mergedPackageNameKeys.isEmpty()) {
return;
}
- var cleared = 0;
+ var cleared = new ArrayList();
for (var elementInfo : model.getAllElements()) {
if (!elementInfo.hasClass()) {
continue;
@@ -1319,18 +1334,29 @@ private static void collapseRedundantElementClasses(Model model, Set mer
continue;
}
setFieldValue(CELEMENTINFO_CLASSNAME_FIELD, elementInfo, null);
- cleared++;
+ cleared.add(elementInfo.fullName());
}
- if (cleared > 0) {
- log.info("Cleared {} redundant element class name(s) after dedupe", cleared);
+ if (!cleared.isEmpty()) {
+ log.info("Cleared {} redundant element class name(s) after dedupe", cleared.size());
+ log.debug(
+ "Cleared element class name(s):\n {}",
+ String.join("\n ", cleared)
+ );
}
}
private static void warnObjectFactoryCollisions(Model model) {
+ var collisions = new ArrayList();
for (var group : ModelUtils.objectFactorySqueezedCollisions(model)) {
+ var squeezed = group.getFirst().getSqueezedName();
+ var names = group.stream().map(CClassInfo::fullName).toList();
+ collisions.add("squeezed '%s': %s".formatted(squeezed, names));
+ }
+ if (!collisions.isEmpty()) {
log.warn(
- "ObjectFactory squeezed-name collision after dedupe (package-local createXxx): {}",
- group.stream().map(CClassInfo::fullName).toList()
+ "ObjectFactory name collision(s) after dedupe ({}):\n {}",
+ collisions.size(),
+ String.join("\n ", collisions)
);
}
}
From 68d96243d49b258c3a93d73dd58e858994da7f94 Mon Sep 17 00:00:00 2001
From: Rawvoid
Date: Sun, 2 Aug 2026 16:24:49 +0800
Subject: [PATCH 06/10] fix(promote-nested-class): align logging with
rename/element-wrapper style
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Log each successful one-level lift at DEBUG as type (from → to); keep INFO
as the hop count only. Polish ObjectFactory skip wording for consistency.
---
.../jaxb/plugin/PromoteNestedClassPlugin.java | 32 +++++++++++++++++--
1 file changed, 29 insertions(+), 3 deletions(-)
diff --git a/plugins/src/main/java/io/github/rawvoid/jaxb/plugin/PromoteNestedClassPlugin.java b/plugins/src/main/java/io/github/rawvoid/jaxb/plugin/PromoteNestedClassPlugin.java
index 224acde..d64ce9b 100644
--- a/plugins/src/main/java/io/github/rawvoid/jaxb/plugin/PromoteNestedClassPlugin.java
+++ b/plugins/src/main/java/io/github/rawvoid/jaxb/plugin/PromoteNestedClassPlugin.java
@@ -89,6 +89,11 @@
* is also why a lift can collide with another type whose squeezed name already
* equals the shortened form — those lifts are undone.
*
+ *
+ * Logging: each successful one-level lift is {@code DEBUG}; the hop count is
+ * {@code INFO}. ObjectFactory collision rollbacks stay {@code DEBUG}. Name-slot
+ * contention is silent (types simply stop).
+ *
*
* @author Rawvoid
*/
@@ -129,6 +134,11 @@ private static String normalize(String name) {
return name.toLowerCase(Locale.ROOT);
}
+ private static String parentLabel(CClassInfoParent parent) {
+ var label = parent.fullName();
+ return label == null || label.isEmpty() ? "(default package)" : label;
+ }
+
/**
* Nesting is defined on the model; changing parents here is enough for
* BeanGenerator to emit the right containers. {@link #run} is a no-op.
@@ -145,7 +155,7 @@ public void postProcessModel(Model model, ErrorHandler errorHandler) {
}
if (hops > 0) {
// Counts one-level moves, not distinct types (a deep type may hop several times).
- log.info("Promoted {} nested type placement(s) (beans and enums)", hops);
+ log.info("Promoted {} nested type placement(s)", hops);
}
}
@@ -213,17 +223,33 @@ private int promoteOneLevel(Model model) {
for (var move : shortNameOk) {
if (move.bean != null) {
var previous = move.bean.parent();
+ // fullName still reflects the old parent until re-parent succeeds.
+ var typeName = move.bean.fullName();
setFieldValue(CCLASSINFO_PARENT_FIELD, move.bean, move.target);
if (ModelUtils.hasObjectFactorySqueezedCollision(model)) {
setFieldValue(CCLASSINFO_PARENT_FIELD, move.bean, previous);
log.debug(
- "Skip promoting {} — ObjectFactory squeezed name collision",
- move.bean.fullName()
+ "Skip promote {}: ObjectFactory name collision",
+ typeName
);
continue;
}
+ log.debug(
+ "Promoted {} ({} → {})",
+ typeName,
+ parentLabel(previous),
+ parentLabel(move.target)
+ );
} else {
+ var previous = move.enumInfo.parent;
+ var typeName = move.enumInfo.fullName();
setFieldValue(CENUMLEAFINFO_PARENT_FIELD, move.enumInfo, move.target);
+ log.debug(
+ "Promoted {} ({} → {})",
+ typeName,
+ parentLabel(previous),
+ parentLabel(move.target)
+ );
}
moved++;
}
From f70780f1a528c217d6612d865e209066b956cc02 Mon Sep 17 00:00:00 2001
From: Rawvoid
Date: Sun, 2 Aug 2026 16:28:20 +0800
Subject: [PATCH 07/10] fix(remove-unused-class): align logging with
rename/element-wrapper style
Always log removed counts at INFO and name lists at DEBUG; drop the custom
-verbose flag in favor of SLF4J levels. Update the test and wiki accordingly.
---
.../jaxb/plugin/RemoveUnusedClassPlugin.java | 47 +++++++++++++------
.../plugin/RemoveUnusedClassPluginTest.java | 2 +-
wiki/remove-unused-class.md | 5 +-
3 files changed, 36 insertions(+), 18 deletions(-)
diff --git a/plugins/src/main/java/io/github/rawvoid/jaxb/plugin/RemoveUnusedClassPlugin.java b/plugins/src/main/java/io/github/rawvoid/jaxb/plugin/RemoveUnusedClassPlugin.java
index 84d5daa..2d87325 100644
--- a/plugins/src/main/java/io/github/rawvoid/jaxb/plugin/RemoveUnusedClassPlugin.java
+++ b/plugins/src/main/java/io/github/rawvoid/jaxb/plugin/RemoveUnusedClassPlugin.java
@@ -32,9 +32,14 @@
/**
* XJC plugin that removes unreferenced JAXB classes and enums from the {@link Model}
* during {@link #postProcessModel(Model, ErrorHandler)}.
- *
- * Uses a graph reachability analysis (Mark & Sweep) starting from global XML root elements
- * and user-configured white-list patterns to identify and prune unreachable classes and enums.
+ *
+ * Uses a graph reachability analysis (Mark & Sweep) starting from global XML root elements
+ * and user-configured white-list patterns to identify and prune unreachable classes and enums.
+ *
+ *
+ * Logging: the removed count is {@code INFO}; the class/enum name list is {@code DEBUG}.
+ * When nothing is removed, only a {@code DEBUG} line is emitted.
+ *
*
* @author Rawvoid
*/
@@ -49,9 +54,6 @@ public class RemoveUnusedClassPlugin extends OptionPlugin {
@Option(name = "preserve-polymorphism", defaultValue = "false", description = "Whether to treat subclasses of a reachable base class as reachable (default: false)")
Boolean preservePolymorphism = false;
- @Option(name = "verbose", defaultValue = "false", description = "Enable detailed logging of reachability and deleted classes (default: false)")
- Boolean verbose = false;
-
@Override
public boolean run(Outline outline, Options opt, ErrorHandler errorHandler) {
return true;
@@ -86,30 +88,45 @@ public void postProcessModel(Model model, ErrorHandler errorHandler) {
.toList();
if (deadClasses.isEmpty() && deadEnums.isEmpty()) {
- if (Boolean.TRUE.equals(verbose)) {
- log.info("[Xremove-unused-class] No unreferenced classes or enums found.");
- }
+ log.debug("No unreferenced classes or enums found");
return;
}
// 4. Remove dead classes
+ var removedClasses = new ArrayList(deadClasses.size());
for (var deadClass : deadClasses) {
ModelUtils.removeClass(model, deadClass);
- if (Boolean.TRUE.equals(verbose)) {
- log.info("[Xremove-unused-class] Removed unreferenced class: {}", deadClass.fullName());
- }
+ removedClasses.add(deadClass.fullName());
}
// 5. Remove dead enums
+ var removedEnums = new ArrayList(deadEnums.size());
for (var deadEnum : deadEnums) {
ModelUtils.removeEnum(model, deadEnum);
- if (Boolean.TRUE.equals(verbose)) {
- log.info("[Xremove-unused-class] Removed unreferenced enum: {}", deadEnum.fullName());
- }
+ removedEnums.add(deadEnum.fullName());
}
// 6. Clean up orphan CElementInfo objects pointing to dead classes/enums
cleanOrphanElements(model, deadClasses, deadEnums);
+
+ log.info(
+ "Removed {} unreferenced type(s) ({} class(es), {} enum(s))",
+ removedClasses.size() + removedEnums.size(),
+ removedClasses.size(),
+ removedEnums.size()
+ );
+ if (!removedClasses.isEmpty()) {
+ log.debug(
+ "Removed unreferenced class(es):\n {}",
+ String.join("\n ", removedClasses)
+ );
+ }
+ if (!removedEnums.isEmpty()) {
+ log.debug(
+ "Removed unreferenced enum(s):\n {}",
+ String.join("\n ", removedEnums)
+ );
+ }
}
private void collectRoots(Model model, Set roots, Queue queue) {
diff --git a/plugins/src/test/java/io/github/rawvoid/jaxb/plugin/RemoveUnusedClassPluginTest.java b/plugins/src/test/java/io/github/rawvoid/jaxb/plugin/RemoveUnusedClassPluginTest.java
index d759fd7..eddadce 100644
--- a/plugins/src/test/java/io/github/rawvoid/jaxb/plugin/RemoveUnusedClassPluginTest.java
+++ b/plugins/src/test/java/io/github/rawvoid/jaxb/plugin/RemoveUnusedClassPluginTest.java
@@ -65,7 +65,7 @@ void baselineGeneratesAllClasses() throws Exception {
@Test
void removesUnusedClassesAndEnums() throws Exception {
- var args = List.of(optionCmd, "-verbose");
+ var args = List.of(optionCmd);
var classes = testExecute(args, ".*", null);
var names = classes.stream().map(Class::getName).toList();
diff --git a/wiki/remove-unused-class.md b/wiki/remove-unused-class.md
index 922a726..424f996 100644
--- a/wiki/remove-unused-class.md
+++ b/wiki/remove-unused-class.md
@@ -18,7 +18,6 @@ Removes unreferenced JAXB classes and enums from the model during `postProcessMo
| `-Xremove-unused-class` | flag | — | Enable the plugin |
| `-keep-classes` | regex (repeatable) | — | Forcibly keep matching classes or enums as roots (`find` on full name or short name) |
| `-preserve-polymorphism` | boolean | `false` | Treat subclasses of a reachable base class as reachable |
-| `-verbose` | boolean | `false` | Detailed logging of reachability and deleted types |
## Behavior
@@ -52,9 +51,11 @@ Only `CClassInfo`, `CEnumLeafInfo`, and `CElementInfo` targets are tracked as re
```text
-Xremove-unused-class
-Xremove-unused-class -keep-classes=com\.example\.KeepMe
--Xremove-unused-class -preserve-polymorphism=true -verbose=true
+-Xremove-unused-class -preserve-polymorphism=true
```
+Logging: removed count is `INFO`; the class/enum name list is `DEBUG` (enable the logger for details).
+
## Limitations / notes
- Without `-preserve-polymorphism`, unused subclasses of a reachable base are pruned even if the base is kept.
From 1df365b97bb606e800912dac28de747b4035ce67 Mon Sep 17 00:00:00 2001
From: Rawvoid
Date: Sun, 2 Aug 2026 16:30:25 +0800
Subject: [PATCH 08/10] fix(flatten-multi-element-prop): align logging with
rename/element-wrapper style
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Log each successful property split at DEBUG as Owner.prop → [fields]; keep
INFO as the flatten count only.
---
.../plugin/FlattenMultiElementPropPlugin.java | 27 +++++++++++++++----
1 file changed, 22 insertions(+), 5 deletions(-)
diff --git a/plugins/src/main/java/io/github/rawvoid/jaxb/plugin/FlattenMultiElementPropPlugin.java b/plugins/src/main/java/io/github/rawvoid/jaxb/plugin/FlattenMultiElementPropPlugin.java
index fd0b754..77ef408 100644
--- a/plugins/src/main/java/io/github/rawvoid/jaxb/plugin/FlattenMultiElementPropPlugin.java
+++ b/plugins/src/main/java/io/github/rawvoid/jaxb/plugin/FlattenMultiElementPropPlugin.java
@@ -60,6 +60,10 @@
* Mutual exclusion: do not enable this plugin together with
* {@link RenameMultiElementPropPlugin} — one renames while the other splits.
*
+ *
+ * Logging: each successful split is {@code DEBUG}; the property count is {@code INFO}.
+ * Failed {@code addProperty} / empty replacement cases are single-line {@code WARN}.
+ *
*
* @author Rawvoid
*/
@@ -112,7 +116,7 @@ public void postProcessModel(Model model, ErrorHandler errorHandler) {
flattened += handleClass(bean);
}
if (flattened > 0) {
- log.info("Flattened {} multi-element property(ies) into individual fields", flattened);
+ log.info("Flattened {} multi-element property(ies)", flattened);
}
}
@@ -137,12 +141,19 @@ private int handleClass(CClassInfo bean) {
continue;
}
+ var originalName = prop.getName(false);
// Replace the original property at position i with all the new ones.
if (replaceProperty(bean, i, prop, replacements)) {
// After replacement, i now points at the first new property.
// Advance past all inserted properties so the loop continues correctly.
i += replacements.size() - 1;
count++;
+ log.debug(
+ "Flattened {}.{} → {}",
+ bean.fullName(),
+ originalName,
+ replacements.stream().map(r -> r.getName(false)).toList()
+ );
}
}
return count;
@@ -375,14 +386,20 @@ private boolean replaceProperty(
if (properties.size() == sizeBefore + added + 1) {
added++;
} else {
- log.warn("Skip adding {}.{}: addProperty did not append",
- owner.fullName(), replacement.getName(false));
+ log.warn(
+ "Skip adding {}.{}: addProperty did not append",
+ owner.fullName(),
+ replacement.getName(false)
+ );
}
}
if (added == 0) {
- log.warn("Skip flattening {}.{}: no replacements were added",
- owner.fullName(), original.getName(false));
+ log.warn(
+ "Skip flattening {}.{}: no replacements were added",
+ owner.fullName(),
+ original.getName(false)
+ );
return false;
}
From af9dcb9f33d7b474f976e0e27ac13690d5e8fdc4 Mon Sep 17 00:00:00 2001
From: Rawvoid
Date: Sun, 2 Aug 2026 17:01:50 +0800
Subject: [PATCH 09/10] fix(plugins): address logging review findings
Capture element FQCNs before clearing className in dedupe; log renames and
conflict arrows with full names; DEBUG only fields actually added by flatten;
use labeled wrapper wording in element-wrapper DEBUG lines.
---
.../jaxb/plugin/DedupeClassPlugin.java | 4 ++-
.../jaxb/plugin/ElementWrapperPlugin.java | 2 +-
.../plugin/FlattenMultiElementPropPlugin.java | 27 ++++++++++---------
.../jaxb/plugin/RenameClassPlugin.java | 15 ++++++-----
4 files changed, 28 insertions(+), 20 deletions(-)
diff --git a/plugins/src/main/java/io/github/rawvoid/jaxb/plugin/DedupeClassPlugin.java b/plugins/src/main/java/io/github/rawvoid/jaxb/plugin/DedupeClassPlugin.java
index d6394d7..f0139b8 100644
--- a/plugins/src/main/java/io/github/rawvoid/jaxb/plugin/DedupeClassPlugin.java
+++ b/plugins/src/main/java/io/github/rawvoid/jaxb/plugin/DedupeClassPlugin.java
@@ -1333,8 +1333,10 @@ private static void collapseRedundantElementClasses(Model model, Set mer
&& !mergedPackageNameKeys.contains(pkg + '\0' + contentKey)) {
continue;
}
- setFieldValue(CELEMENTINFO_CLASSNAME_FIELD, elementInfo, null);
+ // Capture before clearing className: fullName() falls back to type.fullName()
+ // (JAXBElement<…>) once className is null.
cleared.add(elementInfo.fullName());
+ setFieldValue(CELEMENTINFO_CLASSNAME_FIELD, elementInfo, null);
}
if (!cleared.isEmpty()) {
log.info("Cleared {} redundant element class name(s) after dedupe", cleared.size());
diff --git a/plugins/src/main/java/io/github/rawvoid/jaxb/plugin/ElementWrapperPlugin.java b/plugins/src/main/java/io/github/rawvoid/jaxb/plugin/ElementWrapperPlugin.java
index bfc2105..ee4189b 100644
--- a/plugins/src/main/java/io/github/rawvoid/jaxb/plugin/ElementWrapperPlugin.java
+++ b/plugins/src/main/java/io/github/rawvoid/jaxb/plugin/ElementWrapperPlugin.java
@@ -222,7 +222,7 @@ private void flattenOwner(
}
log.debug(
- "Flattened {}.{} → {}",
+ "Flattened {}.{} (wrapper {})",
owner.fullName(),
outer.getName(false),
resolved.wrapper().fullName()
diff --git a/plugins/src/main/java/io/github/rawvoid/jaxb/plugin/FlattenMultiElementPropPlugin.java b/plugins/src/main/java/io/github/rawvoid/jaxb/plugin/FlattenMultiElementPropPlugin.java
index 77ef408..6d81b8d 100644
--- a/plugins/src/main/java/io/github/rawvoid/jaxb/plugin/FlattenMultiElementPropPlugin.java
+++ b/plugins/src/main/java/io/github/rawvoid/jaxb/plugin/FlattenMultiElementPropPlugin.java
@@ -143,16 +143,17 @@ private int handleClass(CClassInfo bean) {
var originalName = prop.getName(false);
// Replace the original property at position i with all the new ones.
- if (replaceProperty(bean, i, prop, replacements)) {
+ var addedNames = replaceProperty(bean, i, prop, replacements);
+ if (!addedNames.isEmpty()) {
// After replacement, i now points at the first new property.
// Advance past all inserted properties so the loop continues correctly.
- i += replacements.size() - 1;
+ i += addedNames.size() - 1;
count++;
log.debug(
"Flattened {}.{} → {}",
bean.fullName(),
originalName,
- replacements.stream().map(r -> r.getName(false)).toList()
+ addedNames
);
}
}
@@ -371,8 +372,10 @@ private static String resolveJavadoc(QName elementName, CElement element, CClass
* new property. The appended properties are then moved from the tail back to
* the original position.
*
+ *
+ * @return short names of properties that were actually appended (empty if none)
*/
- private boolean replaceProperty(
+ private List replaceProperty(
CClassInfo owner, int index, CPropertyInfo original,
List replacements
) {
@@ -380,11 +383,11 @@ private boolean replaceProperty(
var sizeBefore = properties.size();
// 1. Append all replacements via addProperty (triggers setParent).
- var added = 0;
+ var addedNames = new ArrayList();
for (var replacement : replacements) {
owner.addProperty(replacement);
- if (properties.size() == sizeBefore + added + 1) {
- added++;
+ if (properties.size() == sizeBefore + addedNames.size() + 1) {
+ addedNames.add(replacement.getName(false));
} else {
log.warn(
"Skip adding {}.{}: addProperty did not append",
@@ -394,26 +397,26 @@ private boolean replaceProperty(
}
}
- if (added == 0) {
+ if (addedNames.isEmpty()) {
log.warn(
"Skip flattening {}.{}: no replacements were added",
owner.fullName(),
original.getName(false)
);
- return false;
+ return List.of();
}
// 2. Remove original at index.
properties.remove(index);
- // 3. Move the `added` properties from the tail to index.
+ // 3. Move the appended properties from the tail to index.
// Since removeLast() retrieves the last added property first, inserting
// them successively at `index` naturally restores their original order.
- for (var j = 0; j < added; j++) {
+ for (var j = 0; j < addedNames.size(); j++) {
properties.add(index, properties.removeLast());
}
- return true;
+ return addedNames;
}
/**
diff --git a/plugins/src/main/java/io/github/rawvoid/jaxb/plugin/RenameClassPlugin.java b/plugins/src/main/java/io/github/rawvoid/jaxb/plugin/RenameClassPlugin.java
index a9cedeb..281a34c 100644
--- a/plugins/src/main/java/io/github/rawvoid/jaxb/plugin/RenameClassPlugin.java
+++ b/plugins/src/main/java/io/github/rawvoid/jaxb/plugin/RenameClassPlugin.java
@@ -178,12 +178,14 @@ private static List collect(Model model) {
return result;
}
- /** {@code Original→Desired} for a provisional rename (or unchanged name). */
+ /**
+ * Label for conflict details: FQCN when unchanged, otherwise {@code fullName→desiredShort}.
+ */
private static String arrow(Candidate candidate, Map names) {
var desired = names.get(candidate);
return candidate.shortName.equals(desired)
- ? candidate.shortName
- : "%s→%s".formatted(candidate.shortName, desired);
+ ? candidate.fullName
+ : "%s→%s".formatted(candidate.fullName, desired);
}
private static String joinArrows(Collection group, Map names) {
@@ -280,9 +282,10 @@ public void postProcessModel(Model model, ErrorHandler errorHandler) {
for (var candidate : candidates) {
var next = names.get(candidate);
if (!next.equals(candidate.shortName)) {
+ // fullName is the pre-rename FQCN (shortName is not rewritten on Candidate).
+ log.debug("Renamed {} → {}", candidate.fullName, next);
candidate.apply.accept(next);
renamed++;
- log.debug("Renamed {} → {}", candidate.shortName, next);
}
}
if (renamed > 0) {
@@ -378,13 +381,13 @@ private boolean revertAncestorNameClash(
if (undo == ancestor) {
conflicts.add(
"ancestor-nested: %s→%s conflicts with nested %s; kept %s".formatted(
- ancestor.shortName, undoDesired, child.fullName, ancestor.shortName
+ ancestor.fullName, undoDesired, child.fullName, ancestor.fullName
)
);
} else {
conflicts.add(
"ancestor-nested: nested %s→%s conflicts with ancestor %s; kept %s".formatted(
- child.fullName, undoDesired, ancestor.fullName, child.shortName
+ child.fullName, undoDesired, ancestor.fullName, child.fullName
)
);
}
From 78571fddbdcbb25b734eef80d9a83e4b05285357 Mon Sep 17 00:00:00 2001
From: Rawvoid
Date: Sun, 2 Aug 2026 17:50:23 +0800
Subject: [PATCH 10/10] fix(rename-multi-element-prop): align logging style
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Log each property rename at DEBUG as Owner.prop → newName; keep INFO as the
rename count only. Document logging in the class Javadoc.
---
.../jaxb/plugin/RenameMultiElementPropPlugin.java | 15 +++++++++++++--
1 file changed, 13 insertions(+), 2 deletions(-)
diff --git a/plugins/src/main/java/io/github/rawvoid/jaxb/plugin/RenameMultiElementPropPlugin.java b/plugins/src/main/java/io/github/rawvoid/jaxb/plugin/RenameMultiElementPropPlugin.java
index d27209b..a6a911c 100644
--- a/plugins/src/main/java/io/github/rawvoid/jaxb/plugin/RenameMultiElementPropPlugin.java
+++ b/plugins/src/main/java/io/github/rawvoid/jaxb/plugin/RenameMultiElementPropPlugin.java
@@ -50,6 +50,10 @@
*
* Field renames do not affect {@code ObjectFactory} (which keys on class squeezed names).
*
+ *
+ * Logging: each renamed property is {@code DEBUG}; the rename count is {@code INFO}.
+ * Invalid {@code -name} values are a single {@code WARN} before falling back to {@code items}.
+ *
*
* @author Rawvoid
*/
@@ -102,7 +106,7 @@ public void postProcessModel(Model model, ErrorHandler errorHandler) {
renamed += handleClass(bean);
}
if (renamed > 0) {
- log.info("Renamed {} multi-element property name(s) using base '{}'", renamed, name);
+ log.info("Renamed {} multi-element property name(s)", renamed);
}
}
@@ -132,7 +136,8 @@ private int handleClass(CClassInfo bean) {
var count = 0;
for (var prop : targets) {
- occupied.remove(normalize(prop.getName(false)));
+ var originalName = prop.getName(false);
+ occupied.remove(normalize(originalName));
var seed = allocateName(occupied);
var privateName = NAMES.toVariableName(seed);
var publicName = NAMES.toPropertyName(seed);
@@ -140,6 +145,12 @@ private int handleClass(CClassInfo bean) {
prop.setName(false, privateName);
prop.setName(true, publicName);
count++;
+ log.debug(
+ "Renamed {}.{} → {}",
+ bean.fullName(),
+ originalName,
+ privateName
+ );
}
return count;
}