Skip to content

Add NamedInstantPattern support to DatePatternConverter and tests#4128

Open
ashr123 wants to merge 4 commits into
apache:mainfrom
ashr123:feature/3.x/named-instant-pattern
Open

Add NamedInstantPattern support to DatePatternConverter and tests#4128
ashr123 wants to merge 4 commits into
apache:mainfrom
ashr123:feature/3.x/named-instant-pattern

Conversation

@ashr123
Copy link
Copy Markdown
Contributor

@ashr123 ashr123 commented May 23, 2026

I've created an enum for named patterns, that way I think it will be easier to maintain.
In addition the enum modifier is public because it lets users to reuse those patterns in their application, this is. continuation to PR

Checklist

  • Base your changes on 2.x branch if you are targeting Log4j 2; use main otherwise
  • ./mvnw verify succeeds (the build instructions)
  • Non-trivial changes contain an entry file in the src/changelog/.2.x.x directory
  • Tests are provided

Signed-off-by: Roy Ash <roy.ash456@gmail.com>
@ashr123 ashr123 changed the title Add NamedInstantPattern support to DatePatternConverter and tests Add NamedInstantPattern support to DatePatternConverter and tests May 23, 2026
@ashr123
Copy link
Copy Markdown
Contributor Author

ashr123 commented May 23, 2026

@vy, @ppkarwasz 🙂

…tern

Signed-off-by: Roy Ash <roy.ash456@gmail.com>
@ramanathan1504
Copy link
Copy Markdown
Contributor

@ashr123

Thanks for this work and the continuation from #3789! The internal refactoring in DatePatternConverter looks much cleaner now.

However, from a backward-compatibility and public API perspective, introducing NamedInstantPattern as a public enum is a heavy commitment. It permanently locks the public API into this specific Enum and prevents users from easily extending named patterns via plugins (since Enums are strictly final at compile-time).

To achieve both your goal (making patterns programmatically accessible) and protecting the public API, I suggest a hybrid approach:

  1. Hide the Enum: Remove the public modifier from NamedInstantPattern so it becomes package-private. It remains a great internal routing tool for DatePatternConverter.

  2. Expose Public String Constants Instead: Create a simple public utility class to hold the strings. This gives users the exact IDE auto-complete/compile-time safety they had with FixedDateFormat, but strings are inlined by the compiler, meaning zero backward-compatibility burden for Log4j in the future.

public final class InstantPatterns {
    private InstantPatterns() {} // prevent instantiation

    public static final String ABSOLUTE = "HH:mm:ss,SSS";
    public static final String DEFAULT = "yyyy-MM-dd HH:mm:ss,SSS";
    public static final String ISO8601 = "yyyy-MM-dd'T'HH:mm:ss,SSS";
    // ...
}

This approach gives users the programmatic access they need (InstantPatterns.ISO8601) while keeping our public API surface as flat and safe as possible."

@ashr123
Copy link
Copy Markdown
Contributor Author

ashr123 commented May 25, 2026

@ramanathan1504 the thing is that they can do it by themselves, inside their own projects for patterns that do not exist in this project… I don't think we need to create the "literals" twice

The Enum will represent the "known" patterns, any project who wants to add patterns to it can create it's own constants/Enum and concatenate it into %d{...}

@ashr123
Copy link
Copy Markdown
Contributor Author

ashr123 commented May 25, 2026

in addition, there is another way… but it is a bigger change… the user can optionally "supply" an enum (Supplier?) who implements getPattern and from there we can extract the proper pattern. if it is null we extract it from our Enum

@ramanathan1504
Copy link
Copy Markdown
Contributor

ramanathan1504 commented May 25, 2026

@ashr123 I completely understand where you are coming from regarding avoiding duplication of the literals. It makes sense that users can just define their own custom patterns in their own codebase.

My main concern with the public enum wasn't just about user extensibility, but rather the long-term API lock-in for the Log4j project.

When we introduce a new public type (like an Enum) into org.apache.logging.log4j.core, it becomes a permanent contract. If the Log4j architecture changes in the future (for example, completely refactoring the date engine in 3.x to rely purely on java.time objects rather than string mapping), deprecating and removing a public Enum breaks backward compatibility.

The beauty of exposing public static final String constants is that the Java compiler inlines the strings directly into the user's compiled .class files. This means Log4j provides the convenience of the pattern without strictly binding the framework's runtime API to the Enum structure forever.

Regarding the Supplier idea—that's a very interesting concept for extensibility! But I agree with you that it might be a bit too heavy/over-engineered just for this specific PR.

Since introducing new public API types is ultimately an architectural decision, perhaps we can leave the PR as it is for now and see what the core maintainers (like @pkarwasz or @vy ) prefer for the API surface? If they are comfortable committing to the public enum long-term, then your current approach is already perfectly clean!

@ashr123
Copy link
Copy Markdown
Contributor Author

ashr123 commented May 25, 2026

@ramanathan1504 see #3789 it is in version 2.26, if so, the current version (3.0.0) doesn't include those named patterns so it's now technically breaking compatibility

I agree that if it will be pure static final will literally embed the strings into the compiled classes so if you supply log4j2-core as a separate jar the compiled project won't be affected, but, for wars and fat jars you still need to preserve compatibility, as it compiles together so it should be fine for other needs (like using values() or other things) and it won't be possible with "regular" fields and I do love the capabilities that enum supplies (👀)
in addition, in the future we can always add new enum literals (as OpenJDK did in HttpClient.Version (in version 26 they've added HTTP_3 and you can even use it if the project compiles with version 25 if you're using valueOf() and catching IllegalArgumentException and there returning the builder without a change)

private static HttpClient.Builder configureHttpClientVersion(HttpClient.Builder httpClientBuilder) {
    try {
        return httpClientBuilder.version(HttpClient.Version.valueOf("HTTP_3"));
    } catch (IllegalArgumentException ignored) {
        return httpClientBuilder;
    }
}

Again, compiled for Java 25, this will work on JRE 25 (it will use the default HttpClient.Version.HTTP_2, but on JRE 26 it will use HttpClient.Version.HTTP_3 (if the request host supports it of course))

@ramanathan1504
Copy link
Copy Markdown
Contributor

@ashr123 Thanks for the detailed explanation! I've been analyzing the whole picture based on our discussion, and I want to clarify my stance.

We have a classic architectural trade-off here:
On one hand, avoiding a new public class (perhaps by nesting it inside DatePatternConverter) keeps our public API surface small.
On the other hand, keeping NamedInstantPattern as a brand-new, isolated enum keeps the code very clean, avoids bloating the old class, and seamlessly handles the 2.x compatibility you mentioned.

For me, I am completely fine with either approach. Both have valid merits.

Since this deals with the core public API structure, let's just wait for the core maintainers (like @ppkarwasz or @vy ) to weigh in. Whichever direction they align with—whether keeping the new class or nesting it in the old one—I will happily support it.

Once they give the green light on the final structure, I'll gladly finish up the review and merge this. Thanks again for the great discussion and all your work on this!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Development

Successfully merging this pull request may close these issues.

2 participants