class AnnotationWriter {

		private final IndentingWriter writer;

		private final FormattingOptions formattingOptions;

		AnnotationWriter(IndentingWriter writer, FormattingOptions formattingOptions) {
			this.writer = writer;
			this.formattingOptions = formattingOptions;
		}

		void write(Annotation annotation) {
			generateAnnotationCode(annotation).write(this.writer, this.formattingOptions);
		}

		private CodeBlock generateAnnotationCode(Annotation annotation) {
			CodeBlock.Builder code = CodeBlock.builder();
			code.add("@$T", annotation.className);
			if (annotation.attributes.size() == 1 && annotation.attributes.get(0).getName().equals("value")) {
				code.add("($L)", generateAttributeValuesCode(annotation.attributes.get(0)));
			}
			else if (!annotation.attributes.isEmpty()) {
				CodeBlock attributes = annotation.attributes.stream()
					.map(this::generateAttributeCode)
					.collect(CodeBlock.joining(", "));
				code.add("($L)", attributes);
			}
			return code.build();
		}

		private CodeBlock generateAttributeCode(Attribute attribute) {
			return CodeBlock.of("$L = $L", attribute.name, generateAttributeValuesCode(attribute));
		}

		private CodeBlock generateAttributeValuesCode(Attribute attribute) {<FILL_FUNCTION_BODY>}

		private CodeBlock generateValueCode(AttributeType attributeType, Object value) {
			Class<?> valueType = ClassUtils.resolvePrimitiveIfNecessary(value.getClass());
			// CodeBlock can be anything
			if (value instanceof CodeBlock codeBlock) {
				return codeBlock;
			}
			return switch (attributeType) {
				case PRIMITIVE -> {
					if (valueType == Character.class) {
						yield CodeBlock.of("'$L'", value);
					}
					else {
						yield CodeBlock.of("$L", value);
					}
				}
				case STRING -> CodeBlock.of("$S", value);
				case CLASS -> {
					ClassName className = (value instanceof Class clazz) ? ClassName.of(clazz) : (ClassName) value;
					yield this.formattingOptions.classReference(className);
				}
				case ENUM -> {
					Enum<?> enumValue = (Enum<?>) value;
					yield CodeBlock.of("$T.$L", enumValue.getClass(), enumValue.name());
				}
				case ANNOTATION -> generateAnnotationCode((Annotation) value);
				case CODE -> (CodeBlock) value;
			};
		}

	}

			CodeBlock[] values = attribute.values.stream()
				.map((value) -> generateValueCode(attribute.type, value))
				.toArray(CodeBlock[]::new);
			return (values.length == 1) ? values[0] : this.formattingOptions.arrayOf(values);
		
<no_super_class>