You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@logging.apache.org by Chris Hegarty <ch...@gmail.com> on 2022/05/12 16:00:00 UTC

o.a.l.log4j.util.Supplier versus j.u.f.Supplier.

Hi,

I want to pick up an old thread [1], for which I cannot find a 
conclusion. Apologies if this has already been discussed, but I cannot 
find it anywhere (and I have looked!).

It relates to the potential of dropping o.a.l.log4j.util.Supplier in 
favour of the standard j.u.f.Supplier. I think that such is a great 
idea, but I want to ensure that some details are not overlooked.

log4j.Supplier shows up in public API methods like, say, 
Logger.info(Supplier<?>). If this, and others, were migrated to say, 
Logger.info(util.Supplier<?>), then this would be a,

   - source compatible change, but a
   - binary incompatible change

Source compatible, since type inference will infer the similarly shaped 
util.Supplier method variant when recompiling the consuming call sites 
against the new method signature.

Binary incompatible, since existing classes compiled against the 
existing info(log4j.Supplier) will have method descriptors in their byte 
code referencing the log4j.Supplier signature variant, which will not be 
resolvable at runtime.

For clarity, here is a brief, somewhat contrived, minimal example:

// Fake Logger interface
$ cat Logger.java
public interface Logger {
     void info(org.apache.logging.log4j.util.Supplier<?> messageSupplier);
}

// Fake LogManager: factory for loggers that log to stdout
$ cat LogManager.java
public class LogManager {
     public static Logger getLogger() {
         return new Logger() {
             @Override
             public void info(org.apache.logging.log4j.util.Supplier<?> 
messageSupplier) {
                 System.out.println(messageSupplier.get());
             }
         };
     }
}

// Compile these
$ javac -cp log4j-api-2.17.1.jar Logger.java LogManager.java


// Minimal app that does some logging
$ cat Main.java
public class Main {
     public static void main(String... args) {
         LogManager.getLogger().info(() -> "log msg");
     }
}

$ javac -cp log4j-api-2.17.1.jar:. Main.java
$ java -cp log4j-api-2.17.1.jar:. Main
log msg


// Now migrate the logging framework to util.Supplier

$ cat Logger.java
public interface Logger {
     void info(java.util.function.Supplier<?> messageSupplier);
}
$ cat LogManager.java
public class LogManager {
     public static Logger getLogger() {
         return new Logger() {
             @Override
             public void info(java.util.function.Supplier<?> 
messageSupplier) {
                 System.out.println(messageSupplier.get());
             }
         };
     }
}

// recompile the logging framework
$ javac Logger.java LogManager.java

// Now rerun the app code (without recompiling) - binary incompatible

$ java -cp log4j-api-2.17.1.jar:. Main
Exception in thread "main" java.lang.NoSuchMethodError: 'void 
Logger.info(org.apache.logging.log4j.util.Supplier)'
	at Main.main(Main.java:4)

// Recompile the app code - source compatible
$ javac Main.java
$ java Main
log msg

-Chris.

[1] https://www.mail-archive.com/dev@logging.apache.org/msg07967.html


Re: o.a.l.log4j.util.Supplier versus j.u.f.Supplier.

Posted by Chris Hegarty <ch...@gmail.com>.
Hi,

Sorry for the delayed response.

Clearly there are many more considerations, when considering v3, beyond 
just the Supplier interface, which is completely understandable and as 
it should be.

On 13/05/2022 18:35, Matt Sicker wrote:
 > If the v3 API was introduced purely to remove MessageSupplier (which
 > can be replaced with Supplier<Message> or Supplier<? extends Message>
 > as we already support) and our custom Supplier<T> interface, then I
 > don't think that's enough changes to warrant the introduction of a
 > brand new API. On the other hand, if we could aggregate enough changes
 > that break compatibility to warrant a v3 API, then I could support
 > that idea more.

This seems like a pragmatic approach, and FWIW, one which I agree.

There is no "silver bullet" or "magic beans" that can be leveraged to 
teach the JVM to automagically consider log4j.Supplier as a j.u.f.Supplier.

This leaves the usual set of less-than-ideal options (enumerated here 
for completeness):

  1. A new v3.Logger interface - which just uses j.u.f.Supplier.

  2. A v2.Logger with additional poorly named j.u.f.Supplier accepting 
log methods, e.g. infoWithSupplier(..) - which avoids overload collision 
with existing methods (Yuck!).

  3. An adapter from j.u.f.Supplier to log4j.Supplier - this doesn't 
seem in any way helpful given the use-sites.

  4. log4j.Supplier extends j.u.f.Supplier - this doesn't seem in any 
way helpful given the use-sites.

  5. Break binary compatibility, since maybe there are other binary 
incompatible changes anyway, so it might not be that bad! (and in this 
specific case, recompilation will just work without any source code changes)

In the microcosm of this particular issue I don't see a forerunner, but 
maybe it's a non-issue if there are other more compelling factors for a 
v3 API, then the decision becomes much easier.

  On 13/05/2022 23:17, Matt Sicker wrote:
 > There’s @Deprecated(forRemoval = true) which can rise different 
warnings or errors from a regular deprecated element.

Yes, javac will ultimately raise an error when it encounters an API 
element that is terminally (forRemoval = true) deprecated.

-Chris.

On 13/05/2022 23:17, Matt Sicker wrote:
> There’s @Deprecated(forRemoval = true) which can rise different warnings or errors from a regular deprecated element.
> —
> Matt Sicker
> 
>> On May 13, 2022, at 16:32, Ralph Goers <ra...@dslextreme.com> wrote:
>>
>> I believe we moved the things in Foo2, Foo3, etc to the parent as default methods
>> but left empty interfaces or classes in their place so that compatibility wouldn’t be broken.
>> In an ideal world it would be nice to have a way to prevent them from being used
>> when compiling. Perhaps an annotation that causes an error?
>>
>> Ralph
>>
>>> On May 13, 2022, at 11:48 AM, Gary Gregory <ga...@gmail.com> wrote:
>>>
>>> I certainly would hope that collapsing Foo2, Foo3 into their parent is up
>>> for consideration for 3.0. Memories of Microsoft COM and DCOM...
>>>
>>> Gary
>>>
>>> On Fri, May 13, 2022, 13:36 Matt Sicker <bo...@gmail.com> wrote:
>>>
>>>> The only realistic way to break compatibility in the API is to
>>>> introduce a v3 API and make the v3 Core implement both the v2 and v3
>>>> APIs (or breaking that into two modules, but that introduces more log
>>>> bridge confusion which is already a huge mess thanks to people
>>>> continually reinventing logging APIs instead of using log4j-api (or
>>>> slf4j-api even; seen plenty of projects that introduce their own log
>>>> adaptor to further fragment things).
>>>>
>>>> If the v3 API was introduced purely to remove MessageSupplier (which
>>>> can be replaced with Supplier<Message> or Supplier<? extends Message>
>>>> as we already support) and our custom Supplier<T> interface, then I
>>>> don't think that's enough changes to warrant the introduction of a
>>>> brand new API. On the other hand, if we could aggregate enough changes
>>>> that break compatibility to warrant a v3 API, then I could support
>>>> that idea more. However, I'd hope that such a breakage would be more
>>>> than removing deprecated things or merging extension classes (such as
>>>> flattening the Foo2 classes into Foo).
>>>>
>>>> It could potentially be interesting to consider offering multiple APIs
>>>> for different use cases (e.g., having a minimal API that has a small
>>>> jar size that can use lambdas rather than parameter arguments), but
>>>> that's somewhat orthogonal here.
>>>>
>>>> On Thu, May 12, 2022 at 3:31 PM Ralph Goers <ra...@dslextreme.com>
>>>> wrote:
>>>>>
>>>>>
>>>>>
>>>>>> On May 12, 2022, at 10:15 AM, Chris Hegarty <ch...@gmail.com>
>>>> wrote:
>>>>>>
>>>>>>
>>>>>> My motivation for bringing this up now is just to explicitly highlight
>>>> the consequences and potential wide impact of such a change, not to make
>>>> any concrete suggestions. It's a difficult balancing act to weigh
>>>> compatibility against making progress, but ultimately j.u.f.Supplier is the
>>>> right choice (there are just different ways to get there).
>>>>>
>>>>> Any ideas on how to get there? The one proposal Gary made was to require
>>>> log4j3 artifacts and renaming all packages to org.apache.logging.log4j3.
>>>> The consequences of this would be:
>>>>> a. Both are on the classpath - unless we change log4j2.xml to log4j3.xml
>>>> and change all our property names then both will try to load the same
>>>> logging configuration, which is bound to be problematic.
>>>>> b. We create a bridge in log4j3 for the log4j 2 api. I just see this as
>>>> a mess and confusing to users.
>>>>>
>>>>> FWIW, the impact of us using our own Supplier seems non-existent since
>>>> anyone using those methods would be providing a lambda expression.
>>>>>
>>>>> Ralph
>>>>
>>
> 
> 

Re: o.a.l.log4j.util.Supplier versus j.u.f.Supplier.

Posted by Matt Sicker <bo...@gmail.com>.
There’s @Deprecated(forRemoval = true) which can rise different warnings or errors from a regular deprecated element.
—
Matt Sicker

> On May 13, 2022, at 16:32, Ralph Goers <ra...@dslextreme.com> wrote:
> 
> I believe we moved the things in Foo2, Foo3, etc to the parent as default methods 
> but left empty interfaces or classes in their place so that compatibility wouldn’t be broken.
> In an ideal world it would be nice to have a way to prevent them from being used 
> when compiling. Perhaps an annotation that causes an error?
> 
> Ralph
> 
>> On May 13, 2022, at 11:48 AM, Gary Gregory <ga...@gmail.com> wrote:
>> 
>> I certainly would hope that collapsing Foo2, Foo3 into their parent is up
>> for consideration for 3.0. Memories of Microsoft COM and DCOM...
>> 
>> Gary
>> 
>> On Fri, May 13, 2022, 13:36 Matt Sicker <bo...@gmail.com> wrote:
>> 
>>> The only realistic way to break compatibility in the API is to
>>> introduce a v3 API and make the v3 Core implement both the v2 and v3
>>> APIs (or breaking that into two modules, but that introduces more log
>>> bridge confusion which is already a huge mess thanks to people
>>> continually reinventing logging APIs instead of using log4j-api (or
>>> slf4j-api even; seen plenty of projects that introduce their own log
>>> adaptor to further fragment things).
>>> 
>>> If the v3 API was introduced purely to remove MessageSupplier (which
>>> can be replaced with Supplier<Message> or Supplier<? extends Message>
>>> as we already support) and our custom Supplier<T> interface, then I
>>> don't think that's enough changes to warrant the introduction of a
>>> brand new API. On the other hand, if we could aggregate enough changes
>>> that break compatibility to warrant a v3 API, then I could support
>>> that idea more. However, I'd hope that such a breakage would be more
>>> than removing deprecated things or merging extension classes (such as
>>> flattening the Foo2 classes into Foo).
>>> 
>>> It could potentially be interesting to consider offering multiple APIs
>>> for different use cases (e.g., having a minimal API that has a small
>>> jar size that can use lambdas rather than parameter arguments), but
>>> that's somewhat orthogonal here.
>>> 
>>> On Thu, May 12, 2022 at 3:31 PM Ralph Goers <ra...@dslextreme.com>
>>> wrote:
>>>> 
>>>> 
>>>> 
>>>>> On May 12, 2022, at 10:15 AM, Chris Hegarty <ch...@gmail.com>
>>> wrote:
>>>>> 
>>>>> 
>>>>> My motivation for bringing this up now is just to explicitly highlight
>>> the consequences and potential wide impact of such a change, not to make
>>> any concrete suggestions. It's a difficult balancing act to weigh
>>> compatibility against making progress, but ultimately j.u.f.Supplier is the
>>> right choice (there are just different ways to get there).
>>>> 
>>>> Any ideas on how to get there? The one proposal Gary made was to require
>>> log4j3 artifacts and renaming all packages to org.apache.logging.log4j3.
>>> The consequences of this would be:
>>>> a. Both are on the classpath - unless we change log4j2.xml to log4j3.xml
>>> and change all our property names then both will try to load the same
>>> logging configuration, which is bound to be problematic.
>>>> b. We create a bridge in log4j3 for the log4j 2 api. I just see this as
>>> a mess and confusing to users.
>>>> 
>>>> FWIW, the impact of us using our own Supplier seems non-existent since
>>> anyone using those methods would be providing a lambda expression.
>>>> 
>>>> Ralph
>>> 
> 


Re: o.a.l.log4j.util.Supplier versus j.u.f.Supplier.

Posted by Ralph Goers <ra...@dslextreme.com>.
I believe we moved the things in Foo2, Foo3, etc to the parent as default methods 
but left empty interfaces or classes in their place so that compatibility wouldn’t be broken.
In an ideal world it would be nice to have a way to prevent them from being used 
when compiling. Perhaps an annotation that causes an error?

Ralph

> On May 13, 2022, at 11:48 AM, Gary Gregory <ga...@gmail.com> wrote:
> 
> I certainly would hope that collapsing Foo2, Foo3 into their parent is up
> for consideration for 3.0. Memories of Microsoft COM and DCOM...
> 
> Gary
> 
> On Fri, May 13, 2022, 13:36 Matt Sicker <bo...@gmail.com> wrote:
> 
>> The only realistic way to break compatibility in the API is to
>> introduce a v3 API and make the v3 Core implement both the v2 and v3
>> APIs (or breaking that into two modules, but that introduces more log
>> bridge confusion which is already a huge mess thanks to people
>> continually reinventing logging APIs instead of using log4j-api (or
>> slf4j-api even; seen plenty of projects that introduce their own log
>> adaptor to further fragment things).
>> 
>> If the v3 API was introduced purely to remove MessageSupplier (which
>> can be replaced with Supplier<Message> or Supplier<? extends Message>
>> as we already support) and our custom Supplier<T> interface, then I
>> don't think that's enough changes to warrant the introduction of a
>> brand new API. On the other hand, if we could aggregate enough changes
>> that break compatibility to warrant a v3 API, then I could support
>> that idea more. However, I'd hope that such a breakage would be more
>> than removing deprecated things or merging extension classes (such as
>> flattening the Foo2 classes into Foo).
>> 
>> It could potentially be interesting to consider offering multiple APIs
>> for different use cases (e.g., having a minimal API that has a small
>> jar size that can use lambdas rather than parameter arguments), but
>> that's somewhat orthogonal here.
>> 
>> On Thu, May 12, 2022 at 3:31 PM Ralph Goers <ra...@dslextreme.com>
>> wrote:
>>> 
>>> 
>>> 
>>>> On May 12, 2022, at 10:15 AM, Chris Hegarty <ch...@gmail.com>
>> wrote:
>>>> 
>>>> 
>>>> My motivation for bringing this up now is just to explicitly highlight
>> the consequences and potential wide impact of such a change, not to make
>> any concrete suggestions. It's a difficult balancing act to weigh
>> compatibility against making progress, but ultimately j.u.f.Supplier is the
>> right choice (there are just different ways to get there).
>>> 
>>> Any ideas on how to get there? The one proposal Gary made was to require
>> log4j3 artifacts and renaming all packages to org.apache.logging.log4j3.
>> The consequences of this would be:
>>> a. Both are on the classpath - unless we change log4j2.xml to log4j3.xml
>> and change all our property names then both will try to load the same
>> logging configuration, which is bound to be problematic.
>>> b. We create a bridge in log4j3 for the log4j 2 api. I just see this as
>> a mess and confusing to users.
>>> 
>>> FWIW, the impact of us using our own Supplier seems non-existent since
>> anyone using those methods would be providing a lambda expression.
>>> 
>>> Ralph
>> 


Re: o.a.l.log4j.util.Supplier versus j.u.f.Supplier.

Posted by Gary Gregory <ga...@gmail.com>.
I certainly would hope that collapsing Foo2, Foo3 into their parent is up
for consideration for 3.0. Memories of Microsoft COM and DCOM...

Gary

On Fri, May 13, 2022, 13:36 Matt Sicker <bo...@gmail.com> wrote:

> The only realistic way to break compatibility in the API is to
> introduce a v3 API and make the v3 Core implement both the v2 and v3
> APIs (or breaking that into two modules, but that introduces more log
> bridge confusion which is already a huge mess thanks to people
> continually reinventing logging APIs instead of using log4j-api (or
> slf4j-api even; seen plenty of projects that introduce their own log
> adaptor to further fragment things).
>
> If the v3 API was introduced purely to remove MessageSupplier (which
> can be replaced with Supplier<Message> or Supplier<? extends Message>
> as we already support) and our custom Supplier<T> interface, then I
> don't think that's enough changes to warrant the introduction of a
> brand new API. On the other hand, if we could aggregate enough changes
> that break compatibility to warrant a v3 API, then I could support
> that idea more. However, I'd hope that such a breakage would be more
> than removing deprecated things or merging extension classes (such as
> flattening the Foo2 classes into Foo).
>
> It could potentially be interesting to consider offering multiple APIs
> for different use cases (e.g., having a minimal API that has a small
> jar size that can use lambdas rather than parameter arguments), but
> that's somewhat orthogonal here.
>
> On Thu, May 12, 2022 at 3:31 PM Ralph Goers <ra...@dslextreme.com>
> wrote:
> >
> >
> >
> > > On May 12, 2022, at 10:15 AM, Chris Hegarty <ch...@gmail.com>
> wrote:
> > >
> > >
> > > My motivation for bringing this up now is just to explicitly highlight
> the consequences and potential wide impact of such a change, not to make
> any concrete suggestions. It's a difficult balancing act to weigh
> compatibility against making progress, but ultimately j.u.f.Supplier is the
> right choice (there are just different ways to get there).
> >
> > Any ideas on how to get there? The one proposal Gary made was to require
> log4j3 artifacts and renaming all packages to org.apache.logging.log4j3.
> The consequences of this would be:
> > a. Both are on the classpath - unless we change log4j2.xml to log4j3.xml
> and change all our property names then both will try to load the same
> logging configuration, which is bound to be problematic.
> > b. We create a bridge in log4j3 for the log4j 2 api. I just see this as
> a mess and confusing to users.
> >
> > FWIW, the impact of us using our own Supplier seems non-existent since
> anyone using those methods would be providing a lambda expression.
> >
> > Ralph
>

Re: o.a.l.log4j.util.Supplier versus j.u.f.Supplier.

Posted by Matt Sicker <bo...@gmail.com>.
The only realistic way to break compatibility in the API is to
introduce a v3 API and make the v3 Core implement both the v2 and v3
APIs (or breaking that into two modules, but that introduces more log
bridge confusion which is already a huge mess thanks to people
continually reinventing logging APIs instead of using log4j-api (or
slf4j-api even; seen plenty of projects that introduce their own log
adaptor to further fragment things).

If the v3 API was introduced purely to remove MessageSupplier (which
can be replaced with Supplier<Message> or Supplier<? extends Message>
as we already support) and our custom Supplier<T> interface, then I
don't think that's enough changes to warrant the introduction of a
brand new API. On the other hand, if we could aggregate enough changes
that break compatibility to warrant a v3 API, then I could support
that idea more. However, I'd hope that such a breakage would be more
than removing deprecated things or merging extension classes (such as
flattening the Foo2 classes into Foo).

It could potentially be interesting to consider offering multiple APIs
for different use cases (e.g., having a minimal API that has a small
jar size that can use lambdas rather than parameter arguments), but
that's somewhat orthogonal here.

On Thu, May 12, 2022 at 3:31 PM Ralph Goers <ra...@dslextreme.com> wrote:
>
>
>
> > On May 12, 2022, at 10:15 AM, Chris Hegarty <ch...@gmail.com> wrote:
> >
> >
> > My motivation for bringing this up now is just to explicitly highlight the consequences and potential wide impact of such a change, not to make any concrete suggestions. It's a difficult balancing act to weigh compatibility against making progress, but ultimately j.u.f.Supplier is the right choice (there are just different ways to get there).
>
> Any ideas on how to get there? The one proposal Gary made was to require log4j3 artifacts and renaming all packages to org.apache.logging.log4j3.  The consequences of this would be:
> a. Both are on the classpath - unless we change log4j2.xml to log4j3.xml and change all our property names then both will try to load the same logging configuration, which is bound to be problematic.
> b. We create a bridge in log4j3 for the log4j 2 api. I just see this as a mess and confusing to users.
>
> FWIW, the impact of us using our own Supplier seems non-existent since anyone using those methods would be providing a lambda expression.
>
> Ralph

Re: o.a.l.log4j.util.Supplier versus j.u.f.Supplier.

Posted by Ralph Goers <ra...@dslextreme.com>.

> On May 12, 2022, at 10:15 AM, Chris Hegarty <ch...@gmail.com> wrote:
> 
> 
> My motivation for bringing this up now is just to explicitly highlight the consequences and potential wide impact of such a change, not to make any concrete suggestions. It's a difficult balancing act to weigh compatibility against making progress, but ultimately j.u.f.Supplier is the right choice (there are just different ways to get there).

Any ideas on how to get there? The one proposal Gary made was to require log4j3 artifacts and renaming all packages to org.apache.logging.log4j3.  The consequences of this would be:
a. Both are on the classpath - unless we change log4j2.xml to log4j3.xml and change all our property names then both will try to load the same logging configuration, which is bound to be problematic.
b. We create a bridge in log4j3 for the log4j 2 api. I just see this as a mess and confusing to users.

FWIW, the impact of us using our own Supplier seems non-existent since anyone using those methods would be providing a lambda expression.

Ralph

Re: o.a.l.log4j.util.Supplier versus j.u.f.Supplier.

Posted by Chris Hegarty <ch...@gmail.com>.
Ralph,

On 12/05/2022 17:17, Ralph Goers wrote:
> Thanks,
> 
> We were just discussing this in our video call last week. It was also pointed out that there are advantages to Log4j using its own Supplier although I cannot remember what they were.
> 
> Of course, the Log4j Supplier could be modified to extend j.u.f.Supplier, although I don’t know what the point of that would be.

Right. In terms of compatibility, I do not see any benefit from 
extending j.u.f.Supplier.

> Adding new methods that use j.u.f.Supplier almost certainly would just create a mess and require casting all over the place.

Agreed. Such methods will always confuse type inference and lead to red 
squiggly lines in the IDE :-(   Not to mention the fact that there is 
already a single-arg Object accepting variant, e.g. info(Object).

Yet another alternative, would be to not overload these methods further 
but to add differently named ones, or to move into a new log4j3 package, 
etc. But these have their own trade-offs.

My motivation for bringing this up now is just to explicitly highlight 
the consequences and potential wide impact of such a change, not to make 
any concrete suggestions. It's a difficult balancing act to weigh 
compatibility against making progress, but ultimately j.u.f.Supplier is 
the right choice (there are just different ways to get there).

-Chris.

Re: o.a.l.log4j.util.Supplier versus j.u.f.Supplier.

Posted by Ralph Goers <ra...@dslextreme.com>.
Thanks,

We were just discussing this in our video call last week. It was also pointed out that there are advantages to Log4j using its own Supplier although I cannot remember what they were.

Of course, the Log4j Supplier could be modified to extend j.u.f.Supplier, although I don’t know what the point of that would be.

Adding new methods that use j.u.f.Supplier almost certainly would just create a mess and require casting all over the place.

Ralph

> On May 12, 2022, at 9:00 AM, Chris Hegarty <ch...@gmail.com> wrote:
> 
> Hi,
> 
> I want to pick up an old thread [1], for which I cannot find a conclusion. Apologies if this has already been discussed, but I cannot find it anywhere (and I have looked!).
> 
> It relates to the potential of dropping o.a.l.log4j.util.Supplier in favour of the standard j.u.f.Supplier. I think that such is a great idea, but I want to ensure that some details are not overlooked.
> 
> log4j.Supplier shows up in public API methods like, say, Logger.info(Supplier<?>). If this, and others, were migrated to say, Logger.info(util.Supplier<?>), then this would be a,
> 
>  - source compatible change, but a
>  - binary incompatible change
> 
> Source compatible, since type inference will infer the similarly shaped util.Supplier method variant when recompiling the consuming call sites against the new method signature.
> 
> Binary incompatible, since existing classes compiled against the existing info(log4j.Supplier) will have method descriptors in their byte code referencing the log4j.Supplier signature variant, which will not be resolvable at runtime.
> 
> For clarity, here is a brief, somewhat contrived, minimal example:
> 
> // Fake Logger interface
> $ cat Logger.java
> public interface Logger {
>    void info(org.apache.logging.log4j.util.Supplier<?> messageSupplier);
> }
> 
> // Fake LogManager: factory for loggers that log to stdout
> $ cat LogManager.java
> public class LogManager {
>    public static Logger getLogger() {
>        return new Logger() {
>            @Override
>            public void info(org.apache.logging.log4j.util.Supplier<?> messageSupplier) {
>                System.out.println(messageSupplier.get());
>            }
>        };
>    }
> }
> 
> // Compile these
> $ javac -cp log4j-api-2.17.1.jar Logger.java LogManager.java
> 
> 
> // Minimal app that does some logging
> $ cat Main.java
> public class Main {
>    public static void main(String... args) {
>        LogManager.getLogger().info(() -> "log msg");
>    }
> }
> 
> $ javac -cp log4j-api-2.17.1.jar:. Main.java
> $ java -cp log4j-api-2.17.1.jar:. Main
> log msg
> 
> 
> // Now migrate the logging framework to util.Supplier
> 
> $ cat Logger.java
> public interface Logger {
>    void info(java.util.function.Supplier<?> messageSupplier);
> }
> $ cat LogManager.java
> public class LogManager {
>    public static Logger getLogger() {
>        return new Logger() {
>            @Override
>            public void info(java.util.function.Supplier<?> messageSupplier) {
>                System.out.println(messageSupplier.get());
>            }
>        };
>    }
> }
> 
> // recompile the logging framework
> $ javac Logger.java LogManager.java
> 
> // Now rerun the app code (without recompiling) - binary incompatible
> 
> $ java -cp log4j-api-2.17.1.jar:. Main
> Exception in thread "main" java.lang.NoSuchMethodError: 'void Logger.info(org.apache.logging.log4j.util.Supplier)'
> 	at Main.main(Main.java:4)
> 
> // Recompile the app code - source compatible
> $ javac Main.java
> $ java Main
> log msg
> 
> -Chris.
> 
> [1] https://www.mail-archive.com/dev@logging.apache.org/msg07967.html
> 


Re: o.a.l.log4j.util.Supplier versus j.u.f.Supplier.

Posted by Ralph Goers <ra...@dslextreme.com>.
Yup. I heard that. And my view is that if we do that none of us will be employable.

Ralph

> On May 12, 2022, at 9:34 AM, Gary Gregory <ga...@gmail.com> wrote:
> 
> My view is that 3.0 is the only time we can drop old code; that's exactly
> what a major version is for imo.
> 
> Gary
> 
> On Thu, May 12, 2022, 12:00 Chris Hegarty <ch...@gmail.com> wrote:
> 
>> Hi,
>> 
>> I want to pick up an old thread [1], for which I cannot find a
>> conclusion. Apologies if this has already been discussed, but I cannot
>> find it anywhere (and I have looked!).
>> 
>> It relates to the potential of dropping o.a.l.log4j.util.Supplier in
>> favour of the standard j.u.f.Supplier. I think that such is a great
>> idea, but I want to ensure that some details are not overlooked.
>> 
>> log4j.Supplier shows up in public API methods like, say,
>> Logger.info(Supplier<?>). If this, and others, were migrated to say,
>> Logger.info(util.Supplier<?>), then this would be a,
>> 
>>   - source compatible change, but a
>>   - binary incompatible change
>> 
>> Source compatible, since type inference will infer the similarly shaped
>> util.Supplier method variant when recompiling the consuming call sites
>> against the new method signature.
>> 
>> Binary incompatible, since existing classes compiled against the
>> existing info(log4j.Supplier) will have method descriptors in their byte
>> code referencing the log4j.Supplier signature variant, which will not be
>> resolvable at runtime.
>> 
>> For clarity, here is a brief, somewhat contrived, minimal example:
>> 
>> // Fake Logger interface
>> $ cat Logger.java
>> public interface Logger {
>>     void info(org.apache.logging.log4j.util.Supplier<?> messageSupplier);
>> }
>> 
>> // Fake LogManager: factory for loggers that log to stdout
>> $ cat LogManager.java
>> public class LogManager {
>>     public static Logger getLogger() {
>>         return new Logger() {
>>             @Override
>>             public void info(org.apache.logging.log4j.util.Supplier<?>
>> messageSupplier) {
>>                 System.out.println(messageSupplier.get());
>>             }
>>         };
>>     }
>> }
>> 
>> // Compile these
>> $ javac -cp log4j-api-2.17.1.jar Logger.java LogManager.java
>> 
>> 
>> // Minimal app that does some logging
>> $ cat Main.java
>> public class Main {
>>     public static void main(String... args) {
>>         LogManager.getLogger().info(() -> "log msg");
>>     }
>> }
>> 
>> $ javac -cp log4j-api-2.17.1.jar:. Main.java
>> $ java -cp log4j-api-2.17.1.jar:. Main
>> log msg
>> 
>> 
>> // Now migrate the logging framework to util.Supplier
>> 
>> $ cat Logger.java
>> public interface Logger {
>>     void info(java.util.function.Supplier<?> messageSupplier);
>> }
>> $ cat LogManager.java
>> public class LogManager {
>>     public static Logger getLogger() {
>>         return new Logger() {
>>             @Override
>>             public void info(java.util.function.Supplier<?>
>> messageSupplier) {
>>                 System.out.println(messageSupplier.get());
>>             }
>>         };
>>     }
>> }
>> 
>> // recompile the logging framework
>> $ javac Logger.java LogManager.java
>> 
>> // Now rerun the app code (without recompiling) - binary incompatible
>> 
>> $ java -cp log4j-api-2.17.1.jar:. Main
>> Exception in thread "main" java.lang.NoSuchMethodError: 'void
>> Logger.info(org.apache.logging.log4j.util.Supplier)'
>>        at Main.main(Main.java:4)
>> 
>> // Recompile the app code - source compatible
>> $ javac Main.java
>> $ java Main
>> log msg
>> 
>> -Chris.
>> 
>> [1] https://www.mail-archive.com/dev@logging.apache.org/msg07967.html
>> 
>> 


Re: o.a.l.log4j.util.Supplier versus j.u.f.Supplier.

Posted by Gary Gregory <ga...@gmail.com>.
My view is that 3.0 is the only time we can drop old code; that's exactly
what a major version is for imo.

Gary

On Thu, May 12, 2022, 12:00 Chris Hegarty <ch...@gmail.com> wrote:

> Hi,
>
> I want to pick up an old thread [1], for which I cannot find a
> conclusion. Apologies if this has already been discussed, but I cannot
> find it anywhere (and I have looked!).
>
> It relates to the potential of dropping o.a.l.log4j.util.Supplier in
> favour of the standard j.u.f.Supplier. I think that such is a great
> idea, but I want to ensure that some details are not overlooked.
>
> log4j.Supplier shows up in public API methods like, say,
> Logger.info(Supplier<?>). If this, and others, were migrated to say,
> Logger.info(util.Supplier<?>), then this would be a,
>
>    - source compatible change, but a
>    - binary incompatible change
>
> Source compatible, since type inference will infer the similarly shaped
> util.Supplier method variant when recompiling the consuming call sites
> against the new method signature.
>
> Binary incompatible, since existing classes compiled against the
> existing info(log4j.Supplier) will have method descriptors in their byte
> code referencing the log4j.Supplier signature variant, which will not be
> resolvable at runtime.
>
> For clarity, here is a brief, somewhat contrived, minimal example:
>
> // Fake Logger interface
> $ cat Logger.java
> public interface Logger {
>      void info(org.apache.logging.log4j.util.Supplier<?> messageSupplier);
> }
>
> // Fake LogManager: factory for loggers that log to stdout
> $ cat LogManager.java
> public class LogManager {
>      public static Logger getLogger() {
>          return new Logger() {
>              @Override
>              public void info(org.apache.logging.log4j.util.Supplier<?>
> messageSupplier) {
>                  System.out.println(messageSupplier.get());
>              }
>          };
>      }
> }
>
> // Compile these
> $ javac -cp log4j-api-2.17.1.jar Logger.java LogManager.java
>
>
> // Minimal app that does some logging
> $ cat Main.java
> public class Main {
>      public static void main(String... args) {
>          LogManager.getLogger().info(() -> "log msg");
>      }
> }
>
> $ javac -cp log4j-api-2.17.1.jar:. Main.java
> $ java -cp log4j-api-2.17.1.jar:. Main
> log msg
>
>
> // Now migrate the logging framework to util.Supplier
>
> $ cat Logger.java
> public interface Logger {
>      void info(java.util.function.Supplier<?> messageSupplier);
> }
> $ cat LogManager.java
> public class LogManager {
>      public static Logger getLogger() {
>          return new Logger() {
>              @Override
>              public void info(java.util.function.Supplier<?>
> messageSupplier) {
>                  System.out.println(messageSupplier.get());
>              }
>          };
>      }
> }
>
> // recompile the logging framework
> $ javac Logger.java LogManager.java
>
> // Now rerun the app code (without recompiling) - binary incompatible
>
> $ java -cp log4j-api-2.17.1.jar:. Main
> Exception in thread "main" java.lang.NoSuchMethodError: 'void
> Logger.info(org.apache.logging.log4j.util.Supplier)'
>         at Main.main(Main.java:4)
>
> // Recompile the app code - source compatible
> $ javac Main.java
> $ java Main
> log msg
>
> -Chris.
>
> [1] https://www.mail-archive.com/dev@logging.apache.org/msg07967.html
>
>