Home / Class/ ModelWriter Class — spring-boot Architecture

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

Analyze Your Own Codebase

Get architecture documentation, dependency graphs, and domain analysis for your codebase in minutes.

Try Supermodel Free