Repository navigation
refactor(grails-encoder): idiomatic Groovy cleanup of the J2G output - #16680
Open
borinquenkid wants to merge 13 commits into
Open
borinquenkid wants to merge 13 commits into
borinquenkid wants to merge 13 commits into
Conversation
…-groovy-datamapping-validation
…tor/java-to-groovy-grails-datamapping-core
…ctor/java-to-groovy-grails-encoder
…o-groovy-datamapping-validation
…ctor/java-to-groovy-grails-datamapping-core
…actor/java-to-groovy-grails-encoder
Idiomatic-Groovy cleanup pass over the Java-to-Groovy conversion output for grails-encoder (buffer, charsequences, encoder, encoder.impl). No behaviour or public API change. Applied: - for (X x : coll) -> for (X x in coll): 32 loops across StreamCharBuffer, DefaultEncodingStateRegistry, ChainedDecoder, ChainedEncoder, ChainedEncoders, CombinedCodecIdentifier, EncodesToWriterAdapter, EncodingStateImpl, BasicCodecLookup (pure syntax, identical bytecode) - Drop casts after instanceof on locals/parameters (flow typing): AbstractEncodedAppender, AbstractCharReplacementEncoder, RawCodec, StreamCharBuffer (addChunk, writeTo, writeToEncodedAppender, startUsingConnectedWritersWriter, StreamCharBufferSubChunk.writeTo/ encodeTo, repositionChunkReader, StreamCharBufferWriter. appendCharSequence x2, FixedCharArrayEncodedAppender. appendCharSequence), GrailsPrintWriter (leftShift/print dispatch, findStreamCharBufferTarget, isUsed, getWriterForEncoder) - Property syntax for simple/accessor getters and setters on external receivers (never on self-receiver where the accessor carries lazy-init logic, to keep that logic running): CodecPrintWriter, FastStringWriter, FastStringPrintWriter, GrailsPrintWriterAdapter, GrailsPrintWriter, StreamCharBuffer, StreamingEncoderWriter, StreamingEncoderEncodedAppender, ChainedEncoder, CombinedCodecIdentifier, DefaultEncodingStateRegistry, BasicCodecLookup, EncodesToWriterAdapter - .equals( -> == for Strings outside equals(Object) bodies: DefaultCodecIdentifier#isEquivalent, HTML4Encoder, BasicJSONEncoder, JavaScriptEncoder anonymous CodecIdentifier#isEquivalent overrides - .contains( -> in: DefaultCodecIdentifier, EncodingStateImpl, StreamCharBuffer (ConnectToWriter#resolveLazyInitializers) - .size() == 0 / > 0 -> isEmpty()/!isEmpty(): ChainedEncoder, ChainedEncoders, EncodingStateImpl (x3), StreamCharBuffer, BasicCodecLookup (codecName.length() > 0 -> !isEmpty()) - list.get(i) -> list[i]; list.add( in statement position -> <<: ChainedEncoder, ChainedEncoders, StreamCharBuffer - x.toArray(new T[size]) -> x as T[]: BasicCodecLookup, StreamCharBuffer (ConnectToWriter#getWriters) - x != null ? x.foo() : null -> x?.foo(): CodecLookupHelper, EncodedAppenderWriter, StreamingEncoderWriter, StreamCharBuffer (lookupDefaultEncodingStateRegistry) - cond ? x : false -> cond && x: GrailsLazyProxyPrintWriter, GrailsRoutablePrintWriter (isAllowUnwrappingOut) - drop redundant this.: StreamCharBuffer (methodMissing), GrailsPrintWriter (constructor getClass() call) - StringBuilder .append( -> <<, string concat -> GString, for a local StringBuilder outside the hot per-char escaping loops: EncodingStateImpl#toString Deliberately left (Tier B/C exclusions): - buffer/out accessors (getOut/setOut) across the whole GrailsPrintWriter family: GrailsPrintWriter has a custom getProperty/setProperty/ getMetaClass GroovyObject implementation for GSP dynamic-dispatch speed, and the `out` field is deliberately written via `this.@out`; GrailsLazyProxyPrintWriter overrides getOut() itself. Left every .getOut()/.setOut(...) call site as an explicit method call rather than risk interacting with that machinery. - .equals( on EncodingState/EncodingStateImpl (AllocatedBuffer#spaceLeft/ applyEncoders, FixedCharArrayEncodedAppender#checkEncodingChange): EncodingStateImpl has real content equality, not identity; == would change behaviour. - .equals( inside equals(Object) bodies (StreamCharBuffer, DefaultCodecIdentifier, EncodingStateImpl): kept per the equals()-body exclusion. - map.get/put -> map[k]/map[k]=v: reads were safe (StreamCharBuffer, BasicCodecLookup, DefaultEncodingStateRegistry all compile getAt to a direct .get()), but map[k]=v on HTML4Encoder#replacements, BasicCodecLookup#registerVariationsOfName, DefaultEncodingStateRegistry #getEncodedCharSequencesForEncoder, and StreamCharBuffer#addChunk's dynamicChunkMap all compiled putAt through ScriptBytecodeAdapter.invokeMethodN (confirmed by javap) instead of a direct Map.put call; reverted those 4 sites back to .put(k, v) to avoid the dynamic-dispatch regression on a per-character/per-chunk hot path. - Did not touch AbstractCharReplacementEncoder/AbstractEncodedAppender's per-character scan loops (escapeCharSequence, encodeToWriter x2, encodeToStream) or StreamCharBuffer's AllocatedBuffer char[] read/write methods: these are the request-rendering hot paths the task flagged as off-limits for anything beyond a cast removal. - getClass() kept as a method call everywhere (Tier C); Class-equality dispatch (csqClass == String/StringBuffer/StringBuilder) casts kept since that is not instanceof-based flow typing. Verification: grails-encoder compileGroovy + compileTestGroovy clean; :grails-encoder:test 83/83 passed (0 failures/errors, verified via the test-results XML); codenarcMain 0 violations across 69 files (codenarcTest SKIPPED per existing module config, checkstyleMain NO-SOURCE, both pre-existing); javap dynamic-dispatch audit on every changed class clean except pre-existing, untouched patterns (GroovyObject plumbing in GrailsPrintWriter, methodMissing's InvokerHelper.invokeMethod in StreamCharBuffer, the Outer.this.field compound-assignment pattern in AbstractChunk/StreamCharBufferReader/StreamCharBufferSubChunk, and the Spring ReflectionUtils.invokeMethod call in HTML4Encoder's helper); no test sources changed. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…grails-encoder # Conflicts: # grails-encoder/src/main/groovy/org/grails/buffer/CodecPrintWriter.groovy # grails-encoder/src/main/groovy/org/grails/buffer/GrailsPrintWriter.groovy # grails-encoder/src/main/groovy/org/grails/buffer/GrailsPrintWriterAdapter.groovy # grails-encoder/src/main/groovy/org/grails/buffer/GrailsRoutablePrintWriter.groovy # grails-encoder/src/main/groovy/org/grails/buffer/StreamByteBuffer.groovy
borinquenkid
marked this pull request as ready for review
October 20, 2026 02:09
This branch has not been deployed
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 join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Stacks on #16589 (java-to-groovy conversion for
grails-encoder).Idiom pass over that conversion's output: the conversion PR keeps the original Java semicolons and double-quoted strings, under a
@SuppressWarnings('UnnecessarySemicolon')header and aTODO(groovyism-cleanup)comment, so git still recognizes each.java->.groovypair as a rename (see matrei's review on #16576). This PR removes that scaffolding and applies the Groovy idioms CodeNarc expects.Verification
CI note: this stacked branch inherits the temporary
CHANGEME FOR ACCEPTANCEworkflow-trigger commit from its base, so no CI runs on it. That commit must be reverted, and CI green, before this PR merges (blocker).🤖 Generated with Claude Code