[Misc] Record the deliberate SonarQube java:S2065 transient modifiers in the code - #1975
Open
claude[bot] wants to merge 1 commit into
Open
claude[bot] wants to merge 1 commit into
claude[bot] wants to merge 1 commit into
Conversation
… in the code
* SonarQube java:S2065 ("Fields in non-serializable classes should not be transient") is a false
positive on these fields: XWiki serializes job statuses, job requests and extension data with
XStream, which honours "transient" independently of java.io.Serializable.
* Records the reason in the code with @SuppressWarnings("java:S2065") plus a // comment, as the
XWiki Java Code Style prescribes, instead of removing a load-bearing modifier.
Co-Authored-By: Vincent Massol <vincent@massol.net>
Claude-Session: https://claude.ai/code/session_01N15Bod7dV3iC7kjtwhK81E
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Jira URL
None — this is a
[Misc]SonarQube cleanup commit.Changes
Description
Records, in the code, why the
transientmodifiers that SonarQube reports asjava:S2065("Fields in non-serializable classes should not be
transient") are deliberate.The 41 issues in SonarCloud
41 issues over 13 files. The diff is annotations and comments only — and
@SuppressWarningshasSOURCEretention, so the compiled bytecode is byte-for-byte identical.No behaviour can change.
Why the rule is wrong here
The rule's premise is that
transientis meaningless unless the class implementsjava.io.Serializable, becausejava.ioserialization is the only thing that reads the modifier.In XWiki it is not: job statuses, job requests and the extension data reachable from them are
persisted by the job status store, which serializes them with XStream, and XStream honours
transientwhatever the class implements.That is verifiable in
xwiki-commonsrather than taken on trust:org.xwiki.job.internal.JobStatusSerializer#writeserializes the job status withorg.xwiki.xstream.internal.SafeXStream.SafeXStream extends XStreamand installs aSafeReflectionProvider, which delegatesvisitSerializableFieldsto the JVM reflection provider — and that provider skipstransient(and
static) fields.java.io.Serializableat all.So removing a modifier this rule points at is not a cleanup: it changes what gets written into the
stored job status.
okf/sonarqube/index.mdalready listsjava:S2065as not worth fixing for thisexact reason ("load-bearing in XWiki … XWiki serializes job statuses and requests with XStream,
which honours
transient. Removing it changes what gets persisted"), but that reasoning lived onlyin the LLM knowledge base, so SonarCloud kept reporting the issues and the next developer to open
one of these files saw nothing. The resolution the XWiki Java Code Style prescribes for a false
positive is
@SuppressWarnings("java:SXXXX")plus a//comment saying why, in the code; SonarCloudthen closes the issue at the next analysis because the rule stops being raised. The idiom is already
established here —
mastercarries 26@SuppressWarnings("java:S…")in xwiki-commons today.The four arguments
What a reviewer has to check is four sentences plus which group each field belongs to.
A — an object the job status store writes out. These fields are runtime state of a job status;
transientis what keeps them out of the stored status. Several already say so in their own Javadoc — "We don't want to serialize it" (AbstractJobStatus#parentJobStatus), "Don't serialize the XDOM because it can lead to a huge XML" (PDFExportJobStatus.DocumentRenderingResult#xdom) — andDefaultExtensionPlan#treecarries aTODOabout serializing it.B — the job progress.
AbstractJobStatus#progressis not transient, so the progress tree is part of what the store serializes; these fields are the walk state inside it.D — an extension repository.
AbstractExtension#repositoryis not transient, so anyExtensionserialized inside a job status reaches its repository;transientis what stops the injected components and the repository caches being dragged into that graph.E — a derived-value cache. A memoized
toString()/hashCode()/URLthat is rebuilt on demand and must not be written out when the instance travels inside a serialized job status or request.Scope of each annotation
Following
okf/conventions/code-style.md("prefer the narrowest scope"), the annotation is on thefield where a file has one or two flagged fields, and on the class where it has three or
more and they all share one reason — repeating the same four-line comment on every field of such a class would be worse for the reader than one statement about the class.
XWikiExtensionRepositoryAbstractJobStatusDefaultJobProgressStepDefaultCoreExtensionRepositoryDefaultLocalExtensionRepositoryDefaultInstalledExtensionRepositoryAbstractCachedExtensionRepositoryAbstractInstalledExtensionRepositoryDefaultExtensionAuthorDefaultExtensionPlanDefaultExtensionRepositoryDescriptorDefaultJobProgressNamespaceClarifications
AbstractJobStatusandXWikiExtensionRepositoryalready carried@SuppressWarnings("checkstyle:ClassFanOutComplexity"); since Java does not allow two@SuppressWarningson one element, the key was merged into the existing annotation ratherthan added next to it.
This is the "judgement" half of the sweep in the sense that it asks for an opinion on suppressing
rather than fixing. Closing it costs nothing: the code keeps behaving exactly as it does today and
the issues simply stay open.
Screenshots & Video
N/A
Executed Tests
Whole-repo reactor (the batch touches
xwiki-commons-component-api, which reportsTests run: 0and then failsjacoco:checkwhen built inside a-plsubset):BUILD SUCCESS — 2394 tests, 0 failures, 0 errors, 16:56,
revapi:checkgreen in every module.The three repos were built in dependency order (commons → rendering → platform) in one chained run,
so the later legs verify against the modified commons/rendering jars rather than a downloaded
SNAPSHOT. Note that
@SuppressWarningshasSOURCEretention, so no.classfile in this diffdiffers from
master's — the build is a Checkstyle/Revapi gate here rather than a behaviour one.Expected merging strategy
Squash and merge, no backport needed (
masteronly).Related
One sweep of the same rule across the three repos, split one PR per repo:
The argument and its verification are identical in all three; each repo can be merged or closed independently.
🤖 Generated with Claude Code
https://claude.ai/code/session_01N15Bod7dV3iC7kjtwhK81E
Generated by Claude Code