Sharang Gupta

Open source

Everything that landed upstream

38 pull requests that landed in 24 projects, each with what the problem was and how it was fixed.

127 more are in review: open pull requests on GitHub.

Bugs fixed

Each one was reproduced with a test that fails on the base branch and passes with the fix.

Fix buffer leak in ProtobufDecoder on cancel

Spring FrameworkLanded

Problem
ProtobufDecoder released the buffer of a partially read message only when the input completed or failed. When a subscriber cancelled while a message was split across data buffers, for example right after receiving the previous message, that buffer was never released. With pooled buffers, such as Netty's, it leaked.
Fix
The decoder now releases the buffer in doFinally, as the character-sequence decoders already did, so cancellation releases it too. A new test decodes a buffer that holds one message and half of the next, cancels after the first message, and asserts that the leak-aware buffer factory reports no leak. It reports one leak without the change.

Treat a null Request.Body as a request with no body

OpenFeignLanded Issue #1210

Problem
Request.create documents that the body can be null, but the constructor stored the null and body(), charset(), isBinary() and length() dereferenced it, so any body-less Request built outside RequestTemplate threw a NullPointerException on first use.
Fix
The constructor normalises a null body to Body.empty(), the default RequestTemplate already uses, which gives exactly the documented contract so clients that branch on body() != null keep working. toString() checks the body's bytes so a body-less request still prints only the request line and headers. Two tests pin the contract and the changelog has an entry.

Ignore Accept-Charset when reading String request bodies

Micronaut CoreLanded Issue #13739

Problem
The String and text/plain body readers decoded the request body with a charset lookup that falls back to the Accept-Charset header when the Content-Type has none. For a request, those are the request's own headers, so Content-Type application/json with Accept-Charset Big5 made a UTF-8 body decode as Big5 and corrupted non-ASCII text. Accept-Charset states a preference for the response, not the encoding of the request body.
Fix
The readers now use only the charset parameter of the Content-Type, falling back to the configured default charset. Eleven tests cover buffered, streamed and chunked reads with Accept-Charset Big5 and ISO-8859-1, a missing media type, text/plain, and that an explicit Content-Type charset still wins. Nine of them fail on the release branch with the garbled output from the report.

Issue #14127 - Deploy directories whose names contain dots

Eclipse JettyLanded Issue #14127

Problem
The deployment scanner grouped scanned paths into apps by their basename, which drops everything after the last dot, for directories too. A webapp directory foo.com became the app foo, separate from the app foo.com of foo.com.properties, so the context deployed empty and answered 404. The code meant to strip .d from nominated directories never ran, because the extension check is always false for a directory.
Fix
A new helper gives the app name of a scanned path: a file keeps its name without extension, a directory keeps its whole name (dropping only a .d suffix), and a path that no longer exists maps to the app that already holds it, so removing foo.com undeploys foo.com. Tests cover directories with dots, nominated directories and the removal case.

Fix RV_RETURN_VALUE_IGNORED_NO_SIDE_EFFECT false negative for Arrays.copyOf

SpotBugsLanded Issue #3900

Problem
Ignoring the result of Arrays.copyOf was never reported, and neither was Arrays.binarySearch, which is on the allow-list. The cause was not the allow-list. java.util.Arrays uses assert, so javac gives it a static initializer that calls Class.desiredAssertionStatus(). That call was taken for a side effect, so every static method of the class was recorded as possibly called only to trigger class initialization, which the checker never reports. The same happened to the pure static methods and constructors of any analysed class containing an assert.
Fix
Class.desiredAssertionStatus() is now treated as side-effect free, which fixes the root cause. Arrays.copyOf and copyOfRange are also listed explicitly, because copyOfRange throws on an invalid range, which the bytecode analysis takes for a side effect. A reproducer covers both overloads, a user class with assert, and used results.

Fix the formatting of instants before the epoch (#4399)

Apache Log4j 2Landed Issue #4399

Problem
Found by differential fuzzing against java.time, with no prior report. Splitting a negative epoch millisecond value with a truncating division gave a negative nanosecond-of-second, breaking an invariant every consumer relies on. The per-minute formatter cache was keyed with a truncating division as well and rendered seconds with a truncating remainder, so the wrong cached minute was chosen and a date pattern printed 23:59:+'.000 for a time one minute before the epoch.
Fix
Both places now use Math.floorDiv and Math.floorMod, which agree with the truncating operators for every instant after the epoch, so nothing changes there. Tests cover seven epoch-millisecond values around the boundary and the formatter's cached-minute path, which the reviewer asked for; reverting the division makes that test fail.

Respect logger-name hierarchy boundary in LoggerNameLevelRewritePolicy

Apache Log4j 2Landed Issue #4412

Problem
The policy matched the configured logger name with startsWith, so a rule for com.foo also matched com.foobar.Baz, which merely shares a character prefix. Every other logger-name feature in Log4j resolves by truncating at dots, and the mismatch silently demoted levels for packages the operator never meant to touch.
Fix
A match now requires the exact name or a dot-separated descendant. Review found that an empty name (catch-all) and a name ending in a dot had worked before and would have stopped; both are kept working and tested, alongside the sibling, child and exact cases.

[LANG-1836] Make TypeUtils.containsTypeVariables and unrollVariables honor the owner type of a ParameterizedType

Apache Commons LangLanded Issue LANG-1836

Problem
containsTypeVariables ignored the owner type of a ParameterizedType, so Outer<T>.Inner was reported as containing no type variables, against its own Javadoc. unrollVariables never unrolled the owner, and for Outer<T>.Inner<T> it merged the raw type's own parameters over the caller's map, discarding the caller's T to String. A guard from an earlier fix also stopped a variable that occurs twice from being unrolled everywhere, so Map<T, T> became Map<String, T>.
Fix
Both methods now recurse into the owner type, unrolling the type arguments against the caller's map and rebuilding the type with its unrolled owner. The guard is released once a variable is resolved, so repeated variables unroll while genuine cycles are still cut; review added identity-based cycle detection through owners and type arguments. A new fixture gives regression tests that fail on master, and the default Maven build, over 85,000 tests with Checkstyle, PMD, SpotBugs and japicmp, passed before each round.

Try the next config server URI after an unreadable response

Spring Cloud ConfigLanded Issue #1723

Problem
When a config server answered with a body the client could not read as an Environment, such as the HTML login page of a misconfigured security setup, RestTemplate threw UnknownContentTypeException. That exception stopped the client at the first URI even with the strategy set to always, while a 4xx or 5xx response moved on to the next one.
Fix
Both the config data loader and the bootstrap property source locator now try the next URI after an unreadable response when the strategy is always, logging it like the other failures. The last URI, and any URI with connection-timeout-only, rethrows as before so fail-fast behaviour is unchanged. Written test first: the new tests failed on main with a fail-fast exception.

Do not start running binder contexts from DefaultBinderFactory

Spring Cloud StreamLanded Issue gh-3155Applied as commit 124562e

Problem
DefaultBinderFactory became a SmartLifecycle so that a CRaC checkpoint can stop the binder child contexts and a restore can start them again. Its start() also ran on the regular refresh, after the binder contexts were already running, and start() on a running context starts every Lifecycle bean, including the plain ones a refresh deliberately leaves alone, such as the header channel registry and its reaper task.
Fix
start() now starts only binder contexts that are not running, that is the ones stopped for a checkpoint. A freshly refreshed context is left alone, so auto-startup beans behave as before and plain Lifecycle beans are no longer started. One test fails on main and passes with the change; another guards the stop-and-restart path. The maintainers rebased it onto main as their own commit with the authorship kept, which is why GitHub shows the pull request as closed, and backported it to 5.0.x.

Fix #651: Support TIME_IN_MILLIS and locale-only @JsonbDateFormat on creator parameters

Eclipse YassonLanded Issue #651

Problem
The creator-parameter path passed the annotation value straight to DateTimeFormatter.ofPattern, including the ##time-in-millis and ##default markers, so records and @JsonbCreator parameters using them failed with "Pattern includes reserved character: '#'".
Fix
The creator path now treats the two markers the way the property path already did, creating a formatter without a pattern so the converters use epoch millis or their defaults. A record test round-trips a TIME_IN_MILLIS Instant, a locale-only LocalDate and a plain Instant.

Fix #627: Reuse registered serializer and deserializer instances

Eclipse YassonLanded Issue #627

Problem
The component matcher is documented to reuse a registered instance for the same type, but it compared the class of the binding wrapper with the serializer class, so the check never matched. Every annotated property got a new instance, and a stateful or specially constructed registered instance was ignored.
Fix
The two checks compare the class of the wrapped serializer or deserializer, as the adapter check already did. A test registers components whose output depends on how they were constructed and checks that annotated properties use them, and still get a new instance when none is registered.

Fix #609: Reject a JSON array or object where a value is expected

Eclipse YassonLanded Issue #609

Problem
Since Yasson 3, {"test": ["a", "b", "c"]} bound to a String property gave "c". The position checker advanced the parser by one event when the current event was unexpected, a step meant for user deserializers that stop just before a value. At START_ARRAY that step entered the array, so the first element was read as the value and the rest were read as further values for the same property.
Fix
The checker no longer steps into an array or object that is not expected, and the document is rejected with the existing exception. The skip still applies to every other event, so user-defined deserializers keep working, including the KEY_NAME case the reviewer pointed at.

Fix #652: Apply a class adapter to values of a type known at runtime

Eclipse YassonLanded Issue #652

Problem
Serialising List.of(annotated) wrote the element field by field, ignoring its class-level adapter. The element type of a raw collection is Object, so the runtime-type serializer passed the customisation of Object down and never looked at the class customisation of the actual type. The serializer built that way was cached for the class, so a later toJson of the object itself ignored the adapter too.
Fix
The runtime serializer chain keeps the given customisation only when it binds a serializer or an adapter, and otherwise uses the class customisation of the runtime type. Tests cover the adapter and serializer cases inside a collection and then directly, with a fresh Jsonb.

Fix #456: Do not call toString() of an object whose setter fails

Eclipse YassonLanded Issue #456

Problem
The message for a failing setter was built by concatenating the half-deserialised object, which called its toString(). If that failed, for example because a later field was still null, its exception replaced the setter's, and the real cause was lost.
Fix
The message uses the class name, as the getter path already did after an earlier fix, and keeps the setter's exception as the cause. It also copes with a null instance from a creator method. Two tests deserialise a class whose setter and toString() both throw.

FELIX-6861 Propagate IOExceptions of stream handlers invoked reflectively

Apache FelixLanded Issue FELIX-6861

Problem
The URL handler proxy invokes a stream handler from another class loader through reflection. Method.invoke wraps the handler's IOException in an InvocationTargetException, which a generic catch then wrapped in IllegalStateException("Stream handler unavailable due to: null"). A FileNotFoundException from URL.openConnection therefore escaped catch (IOException) blocks.
Fix
A small helper rethrows the handler's IOException on the four reflective paths, keeping the original type and stack trace. Other invocation failures are handled as before. A test opens a connection through the proxy with a handler that throws FileNotFoundException, with and without a Proxy.

Fix #165: Do not modify the response when parsing a quoted string

Eclipse Angus MailLanded Issue #165

Problem
Unescaping a quoted string shifted the bytes of the response buffer in place. The buffer is shared by every copy of the response, and several FetchResponse objects are built from the same bytes, so once one had read the string the others saw the shifted bytes and returned a corrupted value.
Fix
A quoted string with escape characters is unescaped into a new array and the buffer is left unchanged; one without escapes is still returned as a view without copying. Three tests read the string twice, from a copy, and as a ByteArray.

Fix #155, #201: Send a long SMTP initial response after the challenge

Eclipse Angus MailLanded Issue #155

Problem
The initial response of an authentication mechanism was always sent on the AUTH command line. An XOAUTH2 access token of a thousand characters or more, as Google Workspace issues, pushed the line over the 512-octet limit of RFC 5321, and servers answered 500 or 555 'line too long'.
Fix
As RFC 4954 requires, an initial response that would not fit is sent in reply to the server's first empty 334 challenge, for both the built-in mechanisms and SASL. A response that fits is sent as before. Tests drive a fake server through both paths.

Fix #104: Send IMAP search text in UTF-8 when UTF8=ACCEPT is enabled

Eclipse Angus MailLanded Issue #104

Problem
After enabling UTF8=ACCEPT, the SEARCH command was correctly sent without a CHARSET, but the search text was still written byte-wise as ASCII, keeping only the low byte of each character. The server rejected the invalid UTF-8, and the client fell back to a search on the client that fetched the whole folder, which took minutes on a large mailbox.
Fix
The search sequence is generated in UTF-8 when no charset is given and UTF-8 has been enabled, with non-ASCII text sent as a quoted string, which RFC 6855 allows. Without UTF-8 support nothing changes. The maintainer's own draft was abandoned in favour of this one after a discussion of the RFC's quoted-string rules.

Features added

Requests that had been open for years, built test-first with reference documentation.

add haveOnlyFinalNonSyntheticFields() to ignore synthetic fields

ArchUnitLanded Issue #1313

Problem
Some compilers create non-final synthetic fields, for example a $SWITCH_TABLE$ field for every switch over an enum. haveOnlyFinalFields() reported them as violations although they appear nowhere in the source and cannot be declared final.
Fix
After discussing with the maintainer whether to change the existing condition, it was kept exactly as it is and an explicit alternative, haveOnlyFinalNonSyntheticFields(), was added and linked from its Javadoc. Because javac never emits such a field, the regression test generates a class file with ASM and imports it.

GH-6485: Add proxy support to the FTP session factories

Spring IntegrationLanded Issue #6485

Problem
An FTP server behind a proxy could only be reached with the JVM's proxy system properties, which affect every connection of the application, or with a custom session factory. The SFTP factory had proxy support; the FTP one did not. The request had been open since 2012.
Fix
AbstractFtpSessionFactory gains setProxy(java.net.Proxy) for SOCKS and HTTP CONNECT proxies, failing fast unless the client is in passive mode, since a server cannot connect back through a proxy. A new FtpHttpProxySessionFactory covers HTTP proxies that require credentials. Reference documentation and a What's New entry are included, and the tests did not compile against main before the change.

GH-8337: Add outbound header name patterns to the DefaultJmsHeaderMapper

Spring IntegrationLanded Issue #8337

Problem
The mapper could restrict which JMS properties were mapped inbound, but outbound it copied every eligible header. Keeping internal headers out of a JMS message needed a HeaderFilter in front of every JMS endpoint.
Fix
setOutboundHeaderNames takes the same simple wildcard and negation patterns as the inbound side; the first match decides, the default is everything, and the JMS API headers are always mapped. Documented in the JMS chapter and the What's New page.

GH-2392: Add batch declaration methods to the AmqpAdmin

Spring AMQPLanded Issue #2392

Problem
RabbitAdmin already declared the context's exchanges, queues and bindings on one channel internally, but the programmatic API exposed one object per call, each on its own channel. The request had been open since 2018, with the maintainer open to it provided the exception handling was thought through.
Fix
declareExchanges, declareQueues and declareBindings are default methods on AmqpAdmin that declare one by one, so other implementations keep working, and RabbitAdmin overrides them to use a single channel. Each object follows the existing per-declaration exception handling, including ignoreDeclarationExceptions and DeclarationExceptionEvent, and manual declarables are recorded as for single declarations.

Documentation

Behaviour that was undocumented, pinned by a test where there was none.

Document the session-only PluginParameterExpressionEvaluator constructor

Apache MavenLanded Issue #8052

Problem
An evaluator created with only a MavenSession failed with a NullPointerException for every expression, even ${project} or ${session}, because evaluation started by reading the mojo descriptor. The issue, MNG-6982, was reported against Maven 3.6.3.
Fix
The pull request proposed looking up the mojo descriptor only when there is a mojo execution, with a test that failed on master. A maintainer fixed the same code on master while it was under review, so the duplicate test and null check were removed and the Javadoc of the session-only constructor, which now explains the behaviour, is what landed.

Document the order of application and profile specific files

Spring Cloud ConfigLanded Issue #1868

Problem
The Environment Repository page explained precedence in general terms but not where a file named after both the application and a profile ranked, which the issue asked and users were relying on without knowing whether it was supported.
Fix
An ordered list for the page's sample client, from highest to lowest precedence, scoped to the native, Git and SVN backends. A test with the six files in one location asserts the order of the property sources, so the documentation is pinned to the behaviour.

Fix #134: Add a FAQ entry for "Got bad greeting from SMTP host"

Eclipse Angus MailLanded Issue #134

Problem
The error 'Got bad greeting from SMTP host ... response: [EOF]' usually means the server closed the connection before greeting, because port 465 expects SSL from the start, and the FAQ did not cover it.
Fix
A FAQ entry after the STARTTLS one explains the cause, gives the properties to set for SSL, and the alternative of a STARTTLS port.

Tests and build

Tests that had silently stopped running, found across many projects, made to run again. Where a test then failed, it was fixed.

Run the tests that have no @Test

Apache DubboLanded

Problem
ParametersTest extended JUnit 3's TestCase until the JUnit 5 upgrade removed that without adding @Test, so the class had had no running test since. A third method in RegistryConfigTest lacked the annotation its twin had.
Fix
@Test added to the three methods, which pass.

Run the varargs test that was ignored for #1593

MockitoLanded

Problem
The test was ignored with 'Fails due to #1593'. That issue was closed in Mockito 5, where any(String.class) matches exactly one value passed to a varargs parameter, so the test had been passing silently ignored.
Fix
The @Ignore is removed and the test is kept as the regression test for that behaviour.

Run four tests that were missing @Test

Apache TomcatLanded

Problem
Four test methods had no @Test annotation, so they never ran. Once they did, each failed: two asserted null where the code returns String.class, one shared a log filter with another test and tripped on a record without a throwable, and one reopened a user database before the file writer was closed and overwrote a file shared with other tests.
Fix
Each test is fixed to assert what the code does, with its own log filter or its own temporary file. The log validation filter no longer fails on a record without a throwable.

Run RollingAppenderCountTest on 2.x again

Apache Log4j 2Landed Issue LOG4J2-3522

Problem
The test had been ignored on 2.x since it was found flaky. The fix on main replaced the sleeps between log events with a rollover listener and a latch, but was never ported to 2.x.
Fix
The approach from main is ported to the JUnit 4 test on 2.x: it registers as a rollover listener, logs without sleeping and waits for the rollovers, with fixed-size payloads so the count is deterministic.

Add missing @Test in FileTimesTest

Apache Commons IOLanded

Problem
CharsetsTest.testIsUTF8CharsetUTF8 and FileTimesTest.testIsUnixTimeFileTimeNull were written without the @Test annotation. JUnit therefore never executed them. They appeared in the source tree and passed compilation, but they provided no coverage and any regression they were meant to catch would go unnoticed.
Fix
The change adds @Test to both methods. With the annotation present, the Maven build runs them and both pass. Because there is no behavioural change to production code, no additional tests are needed; the methods themselves are the verification that the annotation is correct.

Fix the local antora task

Spring AMQPLanded

Problem
The Gradle task passed its options as strings, which the Antora plugin turned into three extra arguments, and the Node plugin it pulled in broke Gradle's configuration cache by starting a process during configuration.
Fix
The options are booleans, so they become flags, and a newer Node Gradle plugin that supports the configuration cache is declared. A second run reuses the cache.

Add missing @Test to CSVFormatTest.testEqualsSkipHeaderRecord#testEqualsSkipHeaderRecord()

Apache Commons CSVLanded

Problem
When CSVFormat.Builder was introduced, the builder version of testEqualsSkipHeaderRecord in CSVFormatTest was written without the @Test annotation. JUnit therefore never ran it, and the builder path for comparing formats that differ in the skip header record setting had no running check. Its sibling tests, including testEqualsSkipHeaderRecord_Deprecated, all carried the annotation, so the gap was easy to miss: the method looked like a test but reported nothing.
Fix
The change adds the missing @Test annotation to testEqualsSkipHeaderRecord, so the method now runs with the rest of CSVFormatTest. No production code changes. The test, which builds a format with setSkipHeaderRecord(true) and checks that it is not equal to its counterpart in either direction, passes against the current code, and the default Maven build passes with it enabled.

Rename DerivedKeyTests so Surefire runs it

Apache WSS4JLanded

Problem
The build includes only classes ending in Test; this one ended in Tests, unlike its 35 siblings, so its nine tests had never run.
Fix
The class is renamed; all nine tests pass and the module's test count goes from 189 to 198.

Back to the home page