parent
0ce6e437a9
commit
f6225fe98b
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
* Copyright 2012-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.logging.logback;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import ch.qos.logback.classic.LoggerContext;
|
||||
import ch.qos.logback.classic.pattern.CallerDataConverter;
|
||||
import ch.qos.logback.classic.pattern.ClassOfCallerConverter;
|
||||
import ch.qos.logback.classic.pattern.ContextNameConverter;
|
||||
import ch.qos.logback.classic.pattern.DateConverter;
|
||||
import ch.qos.logback.classic.pattern.ExtendedThrowableProxyConverter;
|
||||
import ch.qos.logback.classic.pattern.FileOfCallerConverter;
|
||||
import ch.qos.logback.classic.pattern.LevelConverter;
|
||||
import ch.qos.logback.classic.pattern.LineOfCallerConverter;
|
||||
import ch.qos.logback.classic.pattern.LineSeparatorConverter;
|
||||
import ch.qos.logback.classic.pattern.LocalSequenceNumberConverter;
|
||||
import ch.qos.logback.classic.pattern.LoggerConverter;
|
||||
import ch.qos.logback.classic.pattern.MDCConverter;
|
||||
import ch.qos.logback.classic.pattern.MarkerConverter;
|
||||
import ch.qos.logback.classic.pattern.MessageConverter;
|
||||
import ch.qos.logback.classic.pattern.MethodOfCallerConverter;
|
||||
import ch.qos.logback.classic.pattern.NopThrowableInformationConverter;
|
||||
import ch.qos.logback.classic.pattern.PropertyConverter;
|
||||
import ch.qos.logback.classic.pattern.RelativeTimeConverter;
|
||||
import ch.qos.logback.classic.pattern.RootCauseFirstThrowableProxyConverter;
|
||||
import ch.qos.logback.classic.pattern.SyslogStartConverter;
|
||||
import ch.qos.logback.classic.pattern.ThreadConverter;
|
||||
import ch.qos.logback.classic.pattern.ThrowableProxyConverter;
|
||||
import ch.qos.logback.core.rolling.helper.DateTokenConverter;
|
||||
import ch.qos.logback.core.rolling.helper.IntegerTokenConverter;
|
||||
import org.slf4j.bridge.SLF4JBridgeHandler;
|
||||
|
||||
import org.springframework.aot.hint.MemberCategory;
|
||||
import org.springframework.aot.hint.ReflectionHints;
|
||||
import org.springframework.aot.hint.RuntimeHints;
|
||||
import org.springframework.aot.hint.RuntimeHintsRegistrar;
|
||||
import org.springframework.aot.hint.TypeHint.Builder;
|
||||
import org.springframework.aot.hint.TypeReference;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* {@link RuntimeHintsRegistrar} for Logback.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
class LogbackRuntimeHintsRegistrar implements RuntimeHintsRegistrar {
|
||||
|
||||
@Override
|
||||
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
|
||||
if (!ClassUtils.isPresent("ch.qos.logback.classic.LoggerContext", classLoader)) {
|
||||
return;
|
||||
}
|
||||
ReflectionHints reflection = hints.reflection();
|
||||
registerHintsForLogbackLoggingSystemTypeChecks(reflection);
|
||||
registerHintsForBuiltInLogbackConverters(reflection);
|
||||
registerHintsForSpringBootConverters(reflection);
|
||||
}
|
||||
|
||||
private void registerHintsForLogbackLoggingSystemTypeChecks(ReflectionHints reflection) {
|
||||
Consumer<Builder> defaultHint = (hint) -> {
|
||||
};
|
||||
reflection.registerType(LoggerContext.class, defaultHint);
|
||||
reflection.registerType(SLF4JBridgeHandler.class, defaultHint);
|
||||
}
|
||||
|
||||
private void registerHintsForBuiltInLogbackConverters(ReflectionHints reflection) {
|
||||
registerForPublicConstructorInvocation(reflection, CallerDataConverter.class, ClassOfCallerConverter.class,
|
||||
ContextNameConverter.class, DateConverter.class, DateTokenConverter.class,
|
||||
ExtendedThrowableProxyConverter.class, FileOfCallerConverter.class, IntegerTokenConverter.class,
|
||||
LevelConverter.class, LineOfCallerConverter.class, LineSeparatorConverter.class,
|
||||
LocalSequenceNumberConverter.class, LoggerConverter.class, MarkerConverter.class, MDCConverter.class,
|
||||
MessageConverter.class, MethodOfCallerConverter.class, NopThrowableInformationConverter.class,
|
||||
PropertyConverter.class, RelativeTimeConverter.class, RootCauseFirstThrowableProxyConverter.class,
|
||||
SyslogStartConverter.class, ThreadConverter.class, ThrowableProxyConverter.class);
|
||||
}
|
||||
|
||||
private void registerHintsForSpringBootConverters(ReflectionHints reflection) {
|
||||
registerForPublicConstructorInvocation(reflection, ColorConverter.class,
|
||||
ExtendedWhitespaceThrowableProxyConverter.class, WhitespaceThrowableProxyConverter.class);
|
||||
}
|
||||
|
||||
private void registerForPublicConstructorInvocation(ReflectionHints reflection, Class<?>... classes) {
|
||||
reflection.registerTypes(typeReferences(classes),
|
||||
(hint) -> hint.withMembers(MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS));
|
||||
}
|
||||
|
||||
private Iterable<TypeReference> typeReferences(Class<?>... classes) {
|
||||
return Stream.of(classes).map(TypeReference::of).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
}
|
|
@ -1,2 +1,4 @@
|
|||
org.springframework.aot.hint.RuntimeHintsRegistrar=\
|
||||
org.springframework.boot.logging.logback.LogbackRuntimeHintsRegistrar
|
||||
org.springframework.beans.factory.aot.BeanFactoryInitializationAotProcessor=\
|
||||
org.springframework.boot.context.properties.ConfigurationPropertiesBeanFactoryInitializationAotProcessor
|
|
@ -0,0 +1,121 @@
|
|||
/*
|
||||
* Copyright 2012-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.logging.logback;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import ch.qos.logback.classic.LoggerContext;
|
||||
import ch.qos.logback.classic.pattern.ClassicConverter;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.slf4j.bridge.SLF4JBridgeHandler;
|
||||
|
||||
import org.springframework.aot.hint.MemberCategory;
|
||||
import org.springframework.aot.hint.ReflectionHints;
|
||||
import org.springframework.aot.hint.RuntimeHints;
|
||||
import org.springframework.aot.hint.TypeHint;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
|
||||
import org.springframework.core.io.support.ResourcePatternResolver;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link LogbackRuntimeHintsRegistrar}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
class LogbackRuntimeHintsRegistrarTests {
|
||||
|
||||
@Test
|
||||
void registersHintsForTypesCheckedByLogbackLoggingSystem() throws Exception {
|
||||
ReflectionHints reflection = registerHints();
|
||||
assertThat(reflection.getTypeHint(LoggerContext.class)).isNotNull();
|
||||
assertThat(reflection.getTypeHint(SLF4JBridgeHandler.class)).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void registersHintsForBuiltInLogbackConverters() throws Exception {
|
||||
RuntimeHints hints = new RuntimeHints();
|
||||
new LogbackRuntimeHintsRegistrar().registerHints(hints, getClass().getClassLoader());
|
||||
ReflectionHints reflection = registerHints();
|
||||
assertThat(logbackConverters()).allSatisfy(registeredForPublicConstructorInvocation(reflection));
|
||||
}
|
||||
|
||||
@Test
|
||||
void registersHintsForSpringBootConverters() throws IOException, ClassNotFoundException, LinkageError {
|
||||
ReflectionHints reflection = registerHints();
|
||||
assertThat(List.of(ColorConverter.class, ExtendedWhitespaceThrowableProxyConverter.class,
|
||||
WhitespaceThrowableProxyConverter.class))
|
||||
.allSatisfy(registeredForPublicConstructorInvocation(reflection));
|
||||
}
|
||||
|
||||
@Test
|
||||
void doesNotRegisterHintsWhenLoggerContextIsNotAvailable() {
|
||||
RuntimeHints hints = new RuntimeHints();
|
||||
new LogbackRuntimeHintsRegistrar().registerHints(hints, ClassLoader.getPlatformClassLoader());
|
||||
assertThat(hints.reflection().typeHints()).isEmpty();
|
||||
}
|
||||
|
||||
private ReflectionHints registerHints() {
|
||||
RuntimeHints hints = new RuntimeHints();
|
||||
new LogbackRuntimeHintsRegistrar().registerHints(hints, getClass().getClassLoader());
|
||||
ReflectionHints reflection = hints.reflection();
|
||||
return reflection;
|
||||
}
|
||||
|
||||
private Consumer<Class<?>> registeredForPublicConstructorInvocation(ReflectionHints reflection) {
|
||||
return (converter) -> {
|
||||
TypeHint typeHint = reflection.getTypeHint(converter);
|
||||
assertThat(typeHint).isNotNull();
|
||||
assertThat(typeHint.getMemberCategories()).containsExactly(MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS);
|
||||
};
|
||||
}
|
||||
|
||||
private List<Class<?>> logbackConverters() throws IOException {
|
||||
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
|
||||
Resource[] converterResources = resolver
|
||||
.getResources("classpath:ch/qos/logback/classic/pattern/*Converter.class");
|
||||
return Stream.of(converterResources).map(this::className).map(this::load).filter(this::isConcreteConverter)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private String className(Resource resource) {
|
||||
String filename = resource.getFilename();
|
||||
filename = filename.substring(0, filename.length() - ".class".length());
|
||||
return "ch.qos.logback.classic.pattern." + filename;
|
||||
}
|
||||
|
||||
private Class<?> load(String className) {
|
||||
try {
|
||||
return ClassUtils.forName(className, getClass().getClassLoader());
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isConcreteConverter(Class<?> candidate) {
|
||||
return ClassicConverter.class.isAssignableFrom(candidate) && !Modifier.isAbstract(candidate.getModifiers());
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue