ModelWriter Class — spring-boot Architecture
Architecture documentation for the ModelWriter class in SpringBootJoranConfigurator.java from the spring-boot codebase.
Entity Profile
Relationship Graph
Source Code
core/spring-boot/src/main/java/org/springframework/boot/logging/logback/SpringBootJoranConfigurator.java lines 171–334
private static final class ModelWriter {
private static final String MODEL_RESOURCE_LOCATION = "META-INF/spring/logback-model";
private final Model model;
private final ModelInterpretationContext modelInterpretationContext;
private ModelWriter(Model model, ModelInterpretationContext modelInterpretationContext) {
this.model = model;
this.modelInterpretationContext = modelInterpretationContext;
}
private void writeTo(GenerationContext generationContext) {
byte[] serializedModel = serializeModel();
generationContext.getGeneratedFiles()
.handleFile(Kind.RESOURCE, MODEL_RESOURCE_LOCATION,
new RequireNewOrMatchingContentFileHandler(serializedModel));
generationContext.getRuntimeHints().resources().registerPattern(MODEL_RESOURCE_LOCATION);
SerializationHints serializationHints = generationContext.getRuntimeHints().serialization();
serializationTypes(this.model).forEach(serializationHints::registerType);
reflectionTypes(this.model).forEach((type) -> generationContext.getRuntimeHints()
.reflection()
.registerType(TypeReference.of(type), MemberCategory.INVOKE_PUBLIC_METHODS,
MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS));
}
private byte[] serializeModel() {
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
try (ObjectOutputStream output = new ObjectOutputStream(bytes)) {
output.writeObject(this.model);
}
catch (IOException ex) {
throw new RuntimeException(ex);
}
return bytes.toByteArray();
}
@SuppressWarnings("unchecked")
private Set<Class<? extends Serializable>> serializationTypes(Model model) {
Set<Class<? extends Serializable>> modelClasses = new HashSet<>();
Class<?> candidate = model.getClass();
while (Model.class.isAssignableFrom(candidate)) {
if (modelClasses.add((Class<? extends Model>) candidate)) {
ReflectionUtils.doWithFields(candidate, (field) -> {
if (Modifier.isStatic(field.getModifiers())) {
return;
}
ReflectionUtils.makeAccessible(field);
Object value = field.get(model);
if (value != null) {
Class<?> fieldType = value.getClass();
if (Serializable.class.isAssignableFrom(fieldType)) {
modelClasses.add((Class<? extends Serializable>) fieldType);
}
}
});
candidate = candidate.getSuperclass();
}
}
for (Model submodel : model.getSubModels()) {
modelClasses.addAll(serializationTypes(submodel));
}
return modelClasses;
}
private Set<Class<?>> reflectionTypes(Model model) {
return reflectionTypes(model, () -> null);
}
private Set<Class<?>> reflectionTypes(Model model, Supplier<Object> parent) {
Set<Class<?>> reflectionTypes = new HashSet<>();
Class<?> componentType = determineType(model, parent);
if (componentType != null) {
processComponent(componentType, reflectionTypes);
}
Supplier<Object> componentSupplier = SingletonSupplier.of(() -> instantiate(componentType));
for (Model submodel : model.getSubModels()) {
reflectionTypes.addAll(reflectionTypes(submodel, componentSupplier));
}
return reflectionTypes;
}
private @Nullable Class<?> determineType(Model model, Supplier<Object> parentSupplier) {
String className = (model instanceof ComponentModel componentModel) ? componentModel.getClassName() : null;
if (className != null) {
return loadImportType(className);
}
String tag = model.getTag();
if (tag != null) {
className = this.modelInterpretationContext.getDefaultNestedComponentRegistry()
.findDefaultComponentTypeByTag(tag);
if (className != null) {
return loadImportType(className);
}
return inferTypeFromParent(parentSupplier, tag);
}
return null;
}
private Class<?> loadImportType(String className) {
return loadComponentType(this.modelInterpretationContext.getImport(className));
}
private @Nullable Class<?> inferTypeFromParent(Supplier<Object> parentSupplier, String tag) {
Object parent = parentSupplier.get();
if (parent != null) {
try {
PropertySetter propertySetter = new PropertySetter(
this.modelInterpretationContext.getBeanDescriptionCache(), parent);
Class<?> typeFromPropertySetter = propertySetter.getClassNameViaImplicitRules(tag,
AggregationType.AS_COMPLEX_PROPERTY,
this.modelInterpretationContext.getDefaultNestedComponentRegistry());
return typeFromPropertySetter;
}
catch (Exception ex) {
return null;
}
}
return null;
}
private Class<?> loadComponentType(String componentType) {
try {
return ClassUtils.forName(this.modelInterpretationContext.subst(componentType),
getClass().getClassLoader());
}
catch (Throwable ex) {
throw new RuntimeException("Failed to load component type '" + componentType + "'", ex);
}
}
private @Nullable Object instantiate(@Nullable Class<?> type) {
if (type == null) {
return null;
}
try {
return type.getConstructor().newInstance();
}
catch (Exception ex) {
return null;
}
}
private void processComponent(Class<?> componentType, Set<Class<?>> reflectionTypes) {
BeanDescription beanDescription = this.modelInterpretationContext.getBeanDescriptionCache()
.getBeanDescription(componentType);
reflectionTypes.addAll(parameterTypesNames(beanDescription.getPropertyNameToAdder().values()));
reflectionTypes.addAll(parameterTypesNames(beanDescription.getPropertyNameToSetter().values()));
reflectionTypes.add(componentType);
}
private Collection<Class<?>> parameterTypesNames(Collection<Method> methods) {
return methods.stream()
.filter((method) -> !method.getDeclaringClass().equals(ContextAware.class)
&& !method.getDeclaringClass().equals(ContextAwareBase.class))
.map(Method::getParameterTypes)
.flatMap(Stream::of)
.filter((type) -> !type.isPrimitive() && !type.equals(String.class))
.map((type) -> type.isArray() ? type.getComponentType() : type)
.toList();
}
}
Domain
Source
Analyze Your Own Codebase
Get architecture documentation, dependency graphs, and domain analysis for your codebase in minutes.
Try Supermodel Free