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

被折叠的 条评论
为什么被折叠?



