Spring jackson格式化

本文详细介绍了Spring中用于Jackson序列化和反序列化的`@JsonComponent`注解,以及`JsonComponentModule`类如何扫描并注册组件。同时讲解了`@JsonMixin`注解及其模块`JsonMixinModule`,用于实现JSON混合类型处理。这些内容对于理解和定制Jackson在Spring环境中的行为至关重要。

Spring jackson 格式化:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface JsonComponent {

	/**
	 * The value may indicate a suggestion for a logical component name, to be turned into
	 * a Spring bean in case of an autodetected component.
	 * @return the component name
	 */
	@AliasFor(annotation = Component.class)
	String value() default "";

	/**
	 * The types that are handled by the provided serializer/deserializer. This attribute
	 * is mandatory for a {@link KeyDeserializer}, as the type cannot be inferred. For a
	 * {@link JsonSerializer} or {@link JsonDeserializer} it can be used to limit handling
	 * to a subclasses of type inferred from the generic.
	 * @return the types that should be handled by the component
	 * @since 2.2.0
	 */
	Class<?>[] type() default {};

	/**
	 * The scope under which the serializer/deserializer should be registered with the
	 * module.
	 * @return the component's handle type
	 * @since 2.2.0
	 */
	Scope scope() default Scope.VALUES;

	/**
	 * The various scopes under which a serializer/deserializer can be registered.
	 */
	enum Scope {

		/**
		 * A serializer/deserializer for regular value content.
		 * @see JsonSerializer
		 * @see JsonDeserializer
		 */
		VALUES,

		/**
		 * A serializer/deserializer for keys.
		 * @see JsonSerializer
		 * @see KeyDeserializer
		 */
		KEYS

	}

}

JSoncompentModule:

public class JsonComponentModule extends SimpleModule implements BeanFactoryAware, InitializingBean {

	private BeanFactory beanFactory;

	@Override
	public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
		this.beanFactory = beanFactory;
	}

	@Override
	public void afterPropertiesSet() {
		registerJsonComponents();
	}

	public void registerJsonComponents() {
		BeanFactory beanFactory = this.beanFactory;
		while (beanFactory != null) {
			if (beanFactory instanceof ListableBeanFactory listableBeanFactory) {
				addJsonBeans(listableBeanFactory);
			}
			beanFactory = (beanFactory instanceof HierarchicalBeanFactory hierarchicalBeanFactory)
					? hierarchicalBeanFactory.getParentBeanFactory() : null;
		}
	}

	private void addJsonBeans(ListableBeanFactory beanFactory) {
		Map<String, Object> beans = beanFactory.getBeansWithAnnotation(JsonComponent.class);
		for (Object bean : beans.values()) {
			addJsonBean(bean);
		}
	}

	private void addJsonBean(Object bean) {
		MergedAnnotation<JsonComponent> annotation = MergedAnnotations
				.from(bean.getClass(), SearchStrategy.TYPE_HIERARCHY).get(JsonComponent.class);
		Class<?>[] types = annotation.getClassArray("type");
		Scope scope = annotation.getEnum("scope", JsonComponent.Scope.class);
		addJsonBean(bean, types, scope);
	}

	private void addJsonBean(Object bean, Class<?>[] types, Scope scope) {
		if (bean instanceof JsonSerializer) {
			addJsonSerializerBean((JsonSerializer<?>) bean, scope, types);
		}
		else if (bean instanceof JsonDeserializer) {
			addJsonDeserializerBean((JsonDeserializer<?>) bean, types);
		}
		else if (bean instanceof KeyDeserializer) {
			addKeyDeserializerBean((KeyDeserializer) bean, types);
		}
		for (Class<?> innerClass : bean.getClass().getDeclaredClasses()) {
			if (isSuitableInnerClass(innerClass)) {
				Object innerInstance = BeanUtils.instantiateClass(innerClass);
				addJsonBean(innerInstance, types, scope);
			}
		}
	}

	private boolean isSuitableInnerClass(Class<?> innerClass) {
		return !Modifier.isAbstract(innerClass.getModifiers()) && (JsonSerializer.class.isAssignableFrom(innerClass)
				|| JsonDeserializer.class.isAssignableFrom(innerClass)
				|| KeyDeserializer.class.isAssignableFrom(innerClass));
	}

	@SuppressWarnings("unchecked")
	private <T> void addJsonSerializerBean(JsonSerializer<T> serializer, JsonComponent.Scope scope, Class<?>[] types) {
		Class<T> baseType = (Class<T>) ResolvableType.forClass(JsonSerializer.class, serializer.getClass())
				.resolveGeneric();
		addBeanToModule(serializer, baseType, types,
				(scope == Scope.VALUES) ? this::addSerializer : this::addKeySerializer);

	}

	@SuppressWarnings("unchecked")
	private <T> void addJsonDeserializerBean(JsonDeserializer<T> deserializer, Class<?>[] types) {
		Class<T> baseType = (Class<T>) ResolvableType.forClass(JsonDeserializer.class, deserializer.getClass())
				.resolveGeneric();
		addBeanToModule(deserializer, baseType, types, this::addDeserializer);
	}

	private void addKeyDeserializerBean(KeyDeserializer deserializer, Class<?>[] types) {
		Assert.notEmpty(types, "Type must be specified for KeyDeserializer");
		addBeanToModule(deserializer, Object.class, types, this::addKeyDeserializer);
	}

	@SuppressWarnings("unchecked")
	private <E, T> void addBeanToModule(E element, Class<T> baseType, Class<?>[] types,
			BiConsumer<Class<T>, E> consumer) {
		if (ObjectUtils.isEmpty(types)) {
			consumer.accept(baseType, element);
			return;
		}
		for (Class<?> type : types) {
			Assert.isAssignable(baseType, type);
			consumer.accept((Class<T>) type, element);
		}
	}

}

JSonMIni.java

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface JsonMixin {

	/**
	 * Alias for the {@link #type()} attribute. Allows for more concise annotation
	 * declarations e.g.: {@code @JsonMixin(MyType.class)} instead of
	 * {@code @JsonMixin(type=MyType.class)}.
	 * @return the mixed-in classes
	 * @since 2.7.0
	 */
	@AliasFor("type")
	Class<?>[] value() default {};

	/**
	 * The types that are handled by the provided mix-in class. {@link #value()} is an
	 * alias for (and mutually exclusive with) this attribute.
	 * @return the mixed-in classes
	 * @since 2.7.0
	 */
	@AliasFor("value")
	Class<?>[] type() default {};

}

JsonMixinModule.java:

public class JsonMixinModule extends SimpleModule implements InitializingBean {

	private final ApplicationContext context;

	private final Collection<String> basePackages;

	/**
	 * Create a new {@link JsonMixinModule} instance.
	 * @param context the source application context
	 * @param basePackages the packages to check for annotated classes
	 */
	public JsonMixinModule(ApplicationContext context, Collection<String> basePackages) {
		Assert.notNull(context, "Context must not be null");
		this.context = context;
		this.basePackages = basePackages;
	}

	@Override
	public void afterPropertiesSet() throws Exception {
		if (ObjectUtils.isEmpty(this.basePackages)) {
			return;
		}
		JsonMixinComponentScanner scanner = new JsonMixinComponentScanner();
		scanner.setEnvironment(this.context.getEnvironment());
		scanner.setResourceLoader(this.context);
		for (String basePackage : this.basePackages) {
			if (StringUtils.hasText(basePackage)) {
				for (BeanDefinition candidate : scanner.findCandidateComponents(basePackage)) {
					addJsonMixin(ClassUtils.forName(candidate.getBeanClassName(), this.context.getClassLoader()));
				}
			}
		}
	}

	private void addJsonMixin(Class<?> mixinClass) {
		MergedAnnotation<JsonMixin> annotation = MergedAnnotations
				.from(mixinClass, MergedAnnotations.SearchStrategy.TYPE_HIERARCHY).get(JsonMixin.class);
		for (Class<?> targetType : annotation.getClassArray("type")) {
			setMixInAnnotation(targetType, mixinClass);
		}
	}

	static class JsonMixinComponentScanner extends ClassPathScanningCandidateComponentProvider {

		JsonMixinComponentScanner() {
			addIncludeFilter(new AnnotationTypeFilter(JsonMixin.class));
		}

		@Override
		protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
			return true;
		}

	}

}

JsonObjectSerializer:

public abstract class JsonObjectSerializer<T> extends JsonSerializer<T> {

	@Override
	public final void serialize(T value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
		try {
			jgen.writeStartObject();
			serializeObject(value, jgen, provider);
			jgen.writeEndObject();
		}
		catch (Exception ex) {
			if (ex instanceof IOException ioException) {
				throw ioException;
			}
			throw new JsonMappingException(jgen, "Object serialize error", ex);
		}
	}

	/**
	 * Serialize JSON content into the value type this serializer handles.
	 * @param value the source value
	 * @param jgen the JSON generator
	 * @param provider the serializer provider
	 * @throws IOException on error
	 */
	protected abstract void serializeObject(T value, JsonGenerator jgen, SerializerProvider provider)
			throws IOException;

}

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

迅捷的软件产品制作专家

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值