16
16
17
17
package org .springframework .boot .logging .logback ;
18
18
19
- import java .io .ByteArrayInputStream ;
20
19
import java .io .ByteArrayOutputStream ;
21
20
import java .io .IOException ;
22
21
import java .io .InputStream ;
25
24
import java .io .Serializable ;
26
25
import java .lang .reflect .Method ;
27
26
import java .lang .reflect .Modifier ;
27
+ import java .util .Arrays ;
28
28
import java .util .Collection ;
29
29
import java .util .HashMap ;
30
30
import java .util .HashSet ;
51
51
import ch .qos .logback .core .spi .ContextAwareBase ;
52
52
import ch .qos .logback .core .util .AggregationType ;
53
53
54
+ import org .springframework .aot .generate .GeneratedFiles .FileHandler ;
55
+ import org .springframework .aot .generate .GeneratedFiles .Kind ;
54
56
import org .springframework .aot .generate .GenerationContext ;
55
57
import org .springframework .aot .hint .MemberCategory ;
56
58
import org .springframework .aot .hint .SerializationHints ;
62
64
import org .springframework .core .NativeDetector ;
63
65
import org .springframework .core .io .ByteArrayResource ;
64
66
import org .springframework .core .io .ClassPathResource ;
65
- import org .springframework .core .io .Resource ;
66
67
import org .springframework .core .io .support .PropertiesLoaderUtils ;
67
68
import org .springframework .util .ClassUtils ;
68
69
import org .springframework .util .ReflectionUtils ;
69
70
import org .springframework .util .function .SingletonSupplier ;
71
+ import org .springframework .util .function .ThrowingConsumer ;
70
72
71
73
/**
72
74
* Extended version of the Logback {@link JoranConfigurator} that adds additional Spring
@@ -176,15 +178,10 @@ private ModelWriter(Model model, ModelInterpretationContext modelInterpretationC
176
178
}
177
179
178
180
private void writeTo (GenerationContext generationContext ) {
179
- ByteArrayOutputStream bytes = new ByteArrayOutputStream ();
180
- try (ObjectOutputStream output = new ObjectOutputStream (bytes )) {
181
- output .writeObject (this .model );
182
- }
183
- catch (IOException ex ) {
184
- throw new RuntimeException (ex );
185
- }
186
- Resource modelResource = new ByteArrayResource (bytes .toByteArray ());
187
- generationContext .getGeneratedFiles ().addResourceFile (MODEL_RESOURCE_LOCATION , modelResource );
181
+ byte [] serializedModel = serializeModel ();
182
+ generationContext .getGeneratedFiles ()
183
+ .handleFile (Kind .RESOURCE , MODEL_RESOURCE_LOCATION ,
184
+ new RequireNewOrMatchingContentFileHandler (serializedModel ));
188
185
generationContext .getRuntimeHints ().resources ().registerPattern (MODEL_RESOURCE_LOCATION );
189
186
SerializationHints serializationHints = generationContext .getRuntimeHints ().serialization ();
190
187
serializationTypes (this .model ).forEach (serializationHints ::registerType );
@@ -194,6 +191,17 @@ private void writeTo(GenerationContext generationContext) {
194
191
MemberCategory .INVOKE_PUBLIC_METHODS , MemberCategory .INVOKE_PUBLIC_CONSTRUCTORS ));
195
192
}
196
193
194
+ private byte [] serializeModel () {
195
+ ByteArrayOutputStream bytes = new ByteArrayOutputStream ();
196
+ try (ObjectOutputStream output = new ObjectOutputStream (bytes )) {
197
+ output .writeObject (this .model );
198
+ }
199
+ catch (IOException ex ) {
200
+ throw new RuntimeException (ex );
201
+ }
202
+ return bytes .toByteArray ();
203
+ }
204
+
197
205
@ SuppressWarnings ("unchecked" )
198
206
private Set <Class <? extends Serializable >> serializationTypes (Model model ) {
199
207
Set <Class <? extends Serializable >> modelClasses = new HashSet <>();
@@ -389,7 +397,9 @@ private Map<String, String> getRegistryMap() {
389
397
390
398
private void save (GenerationContext generationContext ) {
391
399
Map <String , String > registryMap = getRegistryMap ();
392
- generationContext .getGeneratedFiles ().addResourceFile (RESOURCE_LOCATION , () -> asInputStream (registryMap ));
400
+ byte [] rules = asBytes (registryMap );
401
+ generationContext .getGeneratedFiles ()
402
+ .handleFile (Kind .RESOURCE , RESOURCE_LOCATION , new RequireNewOrMatchingContentFileHandler (rules ));
393
403
generationContext .getRuntimeHints ().resources ().registerPattern (RESOURCE_LOCATION );
394
404
for (String ruleClassName : registryMap .values ()) {
395
405
generationContext .getRuntimeHints ()
@@ -398,7 +408,7 @@ private void save(GenerationContext generationContext) {
398
408
}
399
409
}
400
410
401
- private InputStream asInputStream (Map <String , String > patternRuleRegistry ) {
411
+ private byte [] asBytes (Map <String , String > patternRuleRegistry ) {
402
412
Properties properties = CollectionFactory .createSortedProperties (true );
403
413
patternRuleRegistry .forEach (properties ::setProperty );
404
414
ByteArrayOutputStream bytes = new ByteArrayOutputStream ();
@@ -408,7 +418,32 @@ private InputStream asInputStream(Map<String, String> patternRuleRegistry) {
408
418
catch (IOException ex ) {
409
419
throw new RuntimeException (ex );
410
420
}
411
- return new ByteArrayInputStream (bytes .toByteArray ());
421
+ return bytes .toByteArray ();
422
+ }
423
+
424
+ }
425
+
426
+ private static final class RequireNewOrMatchingContentFileHandler implements ThrowingConsumer <FileHandler > {
427
+
428
+ private final byte [] newContent ;
429
+
430
+ private RequireNewOrMatchingContentFileHandler (byte [] newContent ) {
431
+ this .newContent = newContent ;
432
+ }
433
+
434
+ @ Override
435
+ public void acceptWithException (FileHandler file ) throws Exception {
436
+ if (file .exists ()) {
437
+ byte [] existingContent = file .getContent ().getInputStream ().readAllBytes ();
438
+ if (!Arrays .equals (this .newContent , existingContent )) {
439
+ throw new IllegalStateException (
440
+ "Logging configuration differs from the configuration that has already been written. "
441
+ + "Update your logging configuration so that it is the same for each context" );
442
+ }
443
+ }
444
+ else {
445
+ file .create (new ByteArrayResource (this .newContent ));
446
+ }
412
447
}
413
448
414
449
}
0 commit comments