Skip to content

Commit 9080ae2

Browse files
committed
First-class support for printf-style format strings in LogMessage
LogMessage is an abstract class now: with internal subclasses for Supplier bindings as well as printf-style format strings with a variable number of arguments (some fixed for efficiency, varargs array as fallback), created through corresponding static factory methods. Closes gh-22726
1 parent 5616eb2 commit 9080ae2

File tree

3 files changed

+263
-29
lines changed

3 files changed

+263
-29
lines changed

spring-core/src/main/java/org/springframework/core/log/LogAccessor.java

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ public void trace(Throwable cause, CharSequence message) {
180180
* @param messageSupplier a lazy supplier for the message to log
181181
*/
182182
public void fatal(Supplier<? extends CharSequence> messageSupplier) {
183-
this.log.fatal(new LogMessage(messageSupplier));
183+
this.log.fatal(LogMessage.lazy(messageSupplier));
184184
}
185185

186186
/**
@@ -189,15 +189,15 @@ public void fatal(Supplier<? extends CharSequence> messageSupplier) {
189189
* @param messageSupplier a lazy supplier for the message to log
190190
*/
191191
public void fatal(Throwable cause, Supplier<? extends CharSequence> messageSupplier) {
192-
this.log.fatal(new LogMessage(messageSupplier), cause);
192+
this.log.fatal(LogMessage.lazy(messageSupplier), cause);
193193
}
194194

195195
/**
196196
* Log a message with error log level.
197197
* @param messageSupplier a lazy supplier for the message to log
198198
*/
199199
public void error(Supplier<? extends CharSequence> messageSupplier) {
200-
this.log.error(new LogMessage(messageSupplier));
200+
this.log.error(LogMessage.lazy(messageSupplier));
201201
}
202202

203203
/**
@@ -206,15 +206,15 @@ public void error(Supplier<? extends CharSequence> messageSupplier) {
206206
* @param messageSupplier a lazy supplier for the message to log
207207
*/
208208
public void error(Throwable cause, Supplier<? extends CharSequence> messageSupplier) {
209-
this.log.error(new LogMessage(messageSupplier), cause);
209+
this.log.error(LogMessage.lazy(messageSupplier), cause);
210210
}
211211

212212
/**
213213
* Log a message with warn log level.
214214
* @param messageSupplier a lazy supplier for the message to log
215215
*/
216216
public void warn(Supplier<? extends CharSequence> messageSupplier) {
217-
this.log.warn(new LogMessage(messageSupplier));
217+
this.log.warn(LogMessage.lazy(messageSupplier));
218218
}
219219

220220
/**
@@ -223,15 +223,15 @@ public void warn(Supplier<? extends CharSequence> messageSupplier) {
223223
* @param messageSupplier a lazy supplier for the message to log
224224
*/
225225
public void warn(Throwable cause, Supplier<? extends CharSequence> messageSupplier) {
226-
this.log.warn(new LogMessage(messageSupplier), cause);
226+
this.log.warn(LogMessage.lazy(messageSupplier), cause);
227227
}
228228

229229
/**
230230
* Log a message with info log level.
231231
* @param messageSupplier a lazy supplier for the message to log
232232
*/
233233
public void info(Supplier<? extends CharSequence> messageSupplier) {
234-
this.log.info(new LogMessage(messageSupplier));
234+
this.log.info(LogMessage.lazy(messageSupplier));
235235
}
236236

237237
/**
@@ -240,15 +240,15 @@ public void info(Supplier<? extends CharSequence> messageSupplier) {
240240
* @param messageSupplier a lazy supplier for the message to log
241241
*/
242242
public void info(Throwable cause, Supplier<? extends CharSequence> messageSupplier) {
243-
this.log.info(new LogMessage(messageSupplier), cause);
243+
this.log.info(LogMessage.lazy(messageSupplier), cause);
244244
}
245245

246246
/**
247247
* Log a message with debug log level.
248248
* @param messageSupplier a lazy supplier for the message to log
249249
*/
250250
public void debug(Supplier<? extends CharSequence> messageSupplier) {
251-
this.log.debug(new LogMessage(messageSupplier));
251+
this.log.debug(LogMessage.lazy(messageSupplier));
252252
}
253253

254254
/**
@@ -257,15 +257,15 @@ public void debug(Supplier<? extends CharSequence> messageSupplier) {
257257
* @param messageSupplier a lazy supplier for the message to log
258258
*/
259259
public void debug(Throwable cause, Supplier<? extends CharSequence> messageSupplier) {
260-
this.log.debug(new LogMessage(messageSupplier), cause);
260+
this.log.debug(LogMessage.lazy(messageSupplier), cause);
261261
}
262262

263263
/**
264264
* Log a message with trace log level.
265265
* @param messageSupplier a lazy supplier for the message to log
266266
*/
267267
public void trace(Supplier<? extends CharSequence> messageSupplier) {
268-
this.log.trace(new LogMessage(messageSupplier));
268+
this.log.trace(LogMessage.lazy(messageSupplier));
269269
}
270270

271271
/**
@@ -274,7 +274,7 @@ public void trace(Supplier<? extends CharSequence> messageSupplier) {
274274
* @param messageSupplier a lazy supplier for the message to log
275275
*/
276276
public void trace(Throwable cause, Supplier<? extends CharSequence> messageSupplier) {
277-
this.log.trace(new LogMessage(messageSupplier), cause);
277+
this.log.trace(LogMessage.lazy(messageSupplier), cause);
278278
}
279279

280280
}

spring-core/src/main/java/org/springframework/core/log/LogMessage.java

Lines changed: 213 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -23,36 +23,42 @@
2323

2424
/**
2525
* A simple log message type for use with Commons Logging, allowing
26-
* for convenient late resolution of a given {@link Supplier} instance
27-
* (typically bound to a Java 8 lambda expression) in {@link #toString()}.
26+
* for convenient lazy resolution of a given {@link Supplier} instance
27+
* (typically bound to a Java 8 lambda expression) or a printf-style
28+
* format string ({@link String#format})in its {@link #toString()}.
2829
*
2930
* @author Juergen Hoeller
3031
* @since 5.2
32+
* @see #lazy(Supplier)
33+
* @see #format(String, Object)
34+
* @see #format(String, Object...)
3135
* @see org.apache.commons.logging.Log#fatal(Object)
3236
* @see org.apache.commons.logging.Log#error(Object)
3337
* @see org.apache.commons.logging.Log#warn(Object)
3438
* @see org.apache.commons.logging.Log#info(Object)
3539
* @see org.apache.commons.logging.Log#debug(Object)
3640
* @see org.apache.commons.logging.Log#trace(Object)
3741
*/
38-
public class LogMessage {
39-
40-
private final Supplier<? extends CharSequence> supplier;
42+
public abstract class LogMessage implements CharSequence {
4143

4244
@Nullable
4345
private String result;
4446

4547

46-
/**
47-
* Construct a new {@code LogMessage} for the given supplier.
48-
* @param supplier the lazily resolving supplier
49-
* (typically bound to a Java 8 lambda expression)
50-
*/
51-
public LogMessage(Supplier<? extends CharSequence> supplier) {
52-
Assert.notNull(supplier, "Supplier must not be null");
53-
this.supplier = supplier;
48+
@Override
49+
public int length() {
50+
return toString().length();
51+
}
52+
53+
@Override
54+
public char charAt(int index) {
55+
return toString().charAt(index);
5456
}
5557

58+
@Override
59+
public CharSequence subSequence(int start, int end) {
60+
return toString().subSequence(start, end);
61+
}
5662

5763
/**
5864
* This will be called by the logging provider, potentially once
@@ -61,9 +67,202 @@ public LogMessage(Supplier<? extends CharSequence> supplier) {
6167
@Override
6268
public String toString() {
6369
if (this.result == null) {
64-
this.result = this.supplier.get().toString();
70+
this.result = buildString();
6571
}
6672
return this.result;
6773
}
6874

75+
abstract String buildString();
76+
77+
78+
/**
79+
* Build a lazy resolution message from the given supplier.
80+
* @param supplier the supplier (typically bound to a Java 8 lambda expression)
81+
* @see #toString()
82+
*/
83+
public static LogMessage lazy(Supplier<? extends CharSequence> supplier) {
84+
return new LazyMessage(supplier);
85+
}
86+
87+
/**
88+
* Build a formatted message from the given format string and argument.
89+
* @param format the format string (following {@link String#format} rules)
90+
* @param arg1 the argument
91+
* @see String#format(String, Object...)
92+
*/
93+
public static LogMessage format(String format, Object arg1) {
94+
return new FormatMessage1(format, arg1);
95+
}
96+
97+
/**
98+
* Build a formatted message from the given format string and arguments.
99+
* @param format the format string (following {@link String#format} rules)
100+
* @param arg1 the first argument
101+
* @param arg2 the second argument
102+
* @see String#format(String, Object...)
103+
*/
104+
public static LogMessage format(String format, Object arg1, Object arg2) {
105+
return new FormatMessage2(format, arg1, arg2);
106+
}
107+
108+
/**
109+
* Build a formatted message from the given format string and arguments.
110+
* @param format the format string (following {@link String#format} rules)
111+
* @param arg1 the first argument
112+
* @param arg2 the second argument
113+
* @param arg3 the third argument
114+
* @see String#format(String, Object...)
115+
*/
116+
public static LogMessage format(String format, Object arg1, Object arg2, Object arg3) {
117+
return new FormatMessage3(format, arg1, arg2, arg3);
118+
}
119+
120+
/**
121+
* Build a formatted message from the given format string and arguments.
122+
* @param format the format string (following {@link String#format} rules)
123+
* @param arg1 the first argument
124+
* @param arg2 the second argument
125+
* @param arg3 the third argument
126+
* @param arg4 the fourth argument
127+
* @see String#format(String, Object...)
128+
*/
129+
public static LogMessage format(String format, Object arg1, Object arg2, Object arg3, Object arg4) {
130+
return new FormatMessage4(format, arg1, arg2, arg3, arg4);
131+
}
132+
133+
/**
134+
* Build a formatted message from the given format string and varargs.
135+
* @param format the format string (following {@link String#format} rules)
136+
* @param args the varargs array (costly, prefer individual arguments)
137+
* @see String#format(String, Object...)
138+
*/
139+
public static LogMessage format(String format, Object... args) {
140+
return new FormatMessageX(format, args);
141+
}
142+
143+
144+
private static final class LazyMessage extends LogMessage {
145+
146+
private Supplier<? extends CharSequence> supplier;
147+
148+
LazyMessage(Supplier<? extends CharSequence> supplier) {
149+
Assert.notNull(supplier, "Supplier must not be null");
150+
this.supplier = supplier;
151+
}
152+
153+
@Override
154+
String buildString() {
155+
return this.supplier.get().toString();
156+
}
157+
}
158+
159+
160+
private static abstract class FormatMessage extends LogMessage {
161+
162+
protected final String format;
163+
164+
FormatMessage(String format) {
165+
Assert.notNull(format, "Format must not be null");
166+
this.format = format;
167+
}
168+
}
169+
170+
171+
private static final class FormatMessage1 extends FormatMessage {
172+
173+
private final Object arg1;
174+
175+
FormatMessage1(String format, Object arg1) {
176+
super(format);
177+
this.arg1 = arg1;
178+
}
179+
180+
@Override
181+
protected String buildString() {
182+
return String.format(this.format, this.arg1);
183+
}
184+
}
185+
186+
187+
private static final class FormatMessage2 extends FormatMessage {
188+
189+
private final Object arg1;
190+
191+
private final Object arg2;
192+
193+
FormatMessage2(String format, Object arg1, Object arg2) {
194+
super(format);
195+
this.arg1 = arg1;
196+
this.arg2 = arg2;
197+
}
198+
199+
@Override
200+
String buildString() {
201+
return String.format(this.format, this.arg1, this.arg2);
202+
}
203+
}
204+
205+
206+
private static final class FormatMessage3 extends FormatMessage {
207+
208+
private final Object arg1;
209+
210+
private final Object arg2;
211+
212+
private final Object arg3;
213+
214+
FormatMessage3(String format, Object arg1, Object arg2, Object arg3) {
215+
super(format);
216+
this.arg1 = arg1;
217+
this.arg2 = arg2;
218+
this.arg3 = arg3;
219+
}
220+
221+
@Override
222+
String buildString() {
223+
return String.format(this.format, this.arg1, this.arg2, this.arg3);
224+
}
225+
}
226+
227+
228+
private static final class FormatMessage4 extends FormatMessage {
229+
230+
private final Object arg1;
231+
232+
private final Object arg2;
233+
234+
private final Object arg3;
235+
236+
private final Object arg4;
237+
238+
FormatMessage4(String format, Object arg1, Object arg2, Object arg3, Object arg4) {
239+
super(format);
240+
this.arg1 = arg1;
241+
this.arg2 = arg2;
242+
this.arg3 = arg3;
243+
this.arg4 = arg4;
244+
}
245+
246+
@Override
247+
String buildString() {
248+
return String.format(this.format, this.arg1, this.arg2, this.arg3, this.arg4);
249+
}
250+
}
251+
252+
253+
private static final class FormatMessageX extends FormatMessage {
254+
255+
private final Object[] args;
256+
257+
FormatMessageX(String format, Object... args) {
258+
super(format);
259+
this.args = args;
260+
}
261+
262+
@Override
263+
String buildString() {
264+
return String.format(this.format, this.args);
265+
}
266+
}
267+
69268
}

0 commit comments

Comments
 (0)