1 package top.infra.jackson2;
2
3 import static top.infra.jackson2.JaxbAnnotationJackson2MapperCustomizerFactory.CLASS_JAXB_ANNOTATION_INTROSPECTOR;
4 import static top.infra.jackson2.JaxbAnnotationJackson2MapperCustomizerFactory.CLASS_JAXB_ANNOTATION_MODULE;
5 import static top.infra.jackson2.JaxbAnnotationJackson2MapperCustomizerFactory.CLASS_JAXB_ANNOTATION_MODULE_PRIORITY;
6
7 import com.fasterxml.jackson.databind.Module;
8 import com.fasterxml.jackson.databind.ObjectMapper;
9
10 import lombok.extern.slf4j.Slf4j;
11
12 import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
13
14 import java.lang.reflect.Method;
15 import java.util.List;
16 import java.util.Optional;
17
18 import top.infra.common.ClassUtils;
19 import top.infra.common.EnumUtils;
20
21
22
23
24
25 @Slf4j
26 public class JaxbAnnotationJackson2Customizer implements Jackson2Customizer {
27
28 @Override
29 public void customize(final Jackson2Properties properties, final ObjectMapper mapper) {
30 final Boolean isXmlMapper = this.isXmlMapper(mapper);
31
32 if (properties.getJaxb().getEnabled()) {
33 final Optional<Module> module = this.jaxbAnnotationModule(isXmlMapper);
34 module.ifPresent(mapper::registerModule);
35 }
36 }
37
38 @Override
39 public void customize(final Jackson2Properties properties, final Jackson2ObjectMapperBuilder builder) {
40 final Boolean isXmlMapper = this.isXmlMapper(builder);
41
42 if (properties.getJaxb().getEnabled()) {
43 final Optional<Module> jaxbAnnotationModule = this.jaxbAnnotationModule(isXmlMapper);
44 if (jaxbAnnotationModule.isPresent()) {
45 final List<Module> modules = this.modules(builder);
46 modules.add(jaxbAnnotationModule.get());
47 builder.modulesToInstall(modules.toArray(new Module[0]));
48 }
49 }
50 }
51
52 private Optional<Module> jaxbAnnotationModule(final Boolean isXmlMapper) {
53 final Optional<Module> jaxbAnnotationModule = this.jaxbAnnotationModule();
54
55 final Optional<Object> priority = this.priority(isXmlMapper);
56 if (jaxbAnnotationModule.isPresent() && priority.isPresent()) {
57 this.setJaxbAnnotationModulePriority(jaxbAnnotationModule.get(), priority.get());
58 }
59
60 return jaxbAnnotationModule;
61 }
62
63 private Optional<Module> jaxbAnnotationModule() {
64 try {
65 final Optional<Module> module;
66 final Optional<Class<?>> moduleClass = ClassUtils.forName(CLASS_JAXB_ANNOTATION_MODULE);
67 final Optional<Class<?>> introspectorClass = ClassUtils.forName(CLASS_JAXB_ANNOTATION_INTROSPECTOR);
68 if (moduleClass.isPresent() && introspectorClass.isPresent()) {
69 module = Optional.of((Module) moduleClass.get().getConstructor(introspectorClass.get())
70 .newInstance(new HackedJackson2JaxbAnnotationIntrospector()));
71 } else {
72 module = Optional.empty();
73 }
74
75 return module;
76 } catch (final ReflectiveOperationException ex) {
77 log.info("JaxbAnnotationModule config error", ex);
78
79 return Optional.empty();
80 }
81 }
82
83 private Optional<Object> priority(final Boolean isXmlMapper) {
84 final Optional<Object> priority;
85
86 final String priorityName = isXmlMapper ? "PRIMARY" : "SECONDARY";
87
88 final Class<?> enumType = ClassUtils.forName(CLASS_JAXB_ANNOTATION_MODULE_PRIORITY).orElse(null);
89 priority = Optional.ofNullable(enumType != null ? EnumUtils.objectValueOf(enumType, priorityName) : null);
90 return priority;
91 }
92
93 private void setJaxbAnnotationModulePriority(final Module jaxbAnnotationModule, final Object priority) {
94 try {
95 final Class<?> enumType = ClassUtils.forName(CLASS_JAXB_ANNOTATION_MODULE_PRIORITY).orElse(null);
96 final Method setPriorityMethod = jaxbAnnotationModule.getClass().getDeclaredMethod("setPriority", enumType);
97 setPriorityMethod.invoke(jaxbAnnotationModule, priority);
98 } catch (final ReflectiveOperationException ex) {
99 log.info("JaxbAnnotationModule config error", ex);
100 }
101 }
102 }