1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.bremersee.xml;
18
19 import static org.springframework.util.ObjectUtils.isEmpty;
20
21 import jakarta.xml.bind.Binder;
22 import jakarta.xml.bind.JAXBContext;
23 import jakarta.xml.bind.JAXBException;
24 import jakarta.xml.bind.JAXBIntrospector;
25 import jakarta.xml.bind.Marshaller;
26 import jakarta.xml.bind.SchemaOutputResolver;
27 import jakarta.xml.bind.Unmarshaller;
28 import jakarta.xml.bind.ValidationEventHandler;
29 import jakarta.xml.bind.annotation.adapters.XmlAdapter;
30 import jakarta.xml.bind.attachment.AttachmentMarshaller;
31 import jakarta.xml.bind.attachment.AttachmentUnmarshaller;
32 import java.io.IOException;
33 import java.nio.charset.StandardCharsets;
34 import java.util.List;
35 import java.util.Optional;
36 import java.util.stream.Stream;
37 import javax.xml.validation.Schema;
38 import lombok.EqualsAndHashCode;
39 import lombok.Getter;
40 import lombok.NonNull;
41 import lombok.Setter;
42 import lombok.ToString;
43 import org.springframework.util.Assert;
44
45
46
47
48
49
50 @SuppressWarnings("SameNameButDifferent")
51 @EqualsAndHashCode(callSuper = false)
52 @ToString(exclude = {"jaxbContext"})
53 public class JaxbContextWrapper extends JAXBContext {
54
55 private final JAXBContext jaxbContext;
56
57 @Getter
58 private final JaxbContextDetails details;
59
60 @Getter
61 @Setter
62 private boolean formattedOutput;
63
64 @Getter
65 @Setter
66 private List<XmlAdapter<?, ?>> xmlAdapters;
67
68 @Getter
69 @Setter
70 private AttachmentMarshaller attachmentMarshaller;
71
72 @Getter
73 @Setter
74 private AttachmentUnmarshaller attachmentUnmarshaller;
75
76 @Getter
77 @Setter
78 private ValidationEventHandler validationEventHandler;
79
80 @Getter
81 @Setter
82 private Schema schema;
83
84 @Getter
85 @Setter
86 @NonNull
87 private SchemaMode schemaMode = SchemaMode.NEVER;
88
89
90
91
92
93
94 public JaxbContextWrapper(
95 JAXBContext jaxbContext) {
96 this(jaxbContext, null);
97 }
98
99
100
101
102
103
104
105
106 public JaxbContextWrapper(Stream<JaxbContextData> data, ClassLoader... classLoaders)
107 throws JAXBException {
108 Assert.notNull(data, "Stream of jaxb context data must be present.");
109 this.details = data.collect(JaxbContextDetails.contextDataCollector());
110 Assert.isTrue(!details.isEmpty(), "There is no jaxb model.");
111 this.jaxbContext = JAXBContext.newInstance(this.details.getClasses(classLoaders));
112 }
113
114
115
116
117
118
119
120 JaxbContextWrapper(
121 JAXBContext jaxbContext,
122 JaxbContextDetails details) {
123 Assert.notNull(jaxbContext, "Jaxb context must be present.");
124 this.jaxbContext = jaxbContext;
125 this.details = Optional.ofNullable(details)
126 .orElseGet(JaxbContextDetails::empty);
127 }
128
129 @Override
130 public Unmarshaller createUnmarshaller() throws JAXBException {
131 Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
132 if (!isEmpty(xmlAdapters)) {
133 xmlAdapters.forEach(unmarshaller::setAdapter);
134 }
135 if (!isEmpty(attachmentUnmarshaller)) {
136 unmarshaller.setAttachmentUnmarshaller(attachmentUnmarshaller);
137 }
138 if (!isEmpty(schema) && (schemaMode == SchemaMode.ALWAYS
139 || schemaMode == SchemaMode.UNMARSHAL
140 || schemaMode == SchemaMode.EXTERNAL_XSD)
141 && !isEmpty(details.getSchemaLocation())) {
142 unmarshaller.setSchema(schema);
143 }
144 if (!isEmpty(validationEventHandler)) {
145 unmarshaller.setEventHandler(validationEventHandler);
146 }
147 return unmarshaller;
148 }
149
150 @Override
151 public Marshaller createMarshaller() throws JAXBException {
152 Marshaller marshaller = jaxbContext.createMarshaller();
153 marshaller.setProperty(Marshaller.JAXB_ENCODING, StandardCharsets.UTF_8.name());
154 marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, formattedOutput);
155 if (!isEmpty(details.getSchemaLocation())) {
156 marshaller.setProperty(Marshaller.JAXB_SCHEMA_LOCATION, details.getSchemaLocation());
157 }
158 if (!isEmpty(xmlAdapters)) {
159 xmlAdapters.forEach(marshaller::setAdapter);
160 }
161 if (!isEmpty(attachmentMarshaller)) {
162 marshaller.setAttachmentMarshaller(attachmentMarshaller);
163 }
164 if (!isEmpty(schema) && (schemaMode == SchemaMode.ALWAYS
165 || schemaMode == SchemaMode.MARSHAL
166 || schemaMode == SchemaMode.EXTERNAL_XSD)
167 && !isEmpty(details.getSchemaLocation())) {
168 marshaller.setSchema(schema);
169 }
170 if (!isEmpty(validationEventHandler)) {
171 marshaller.setEventHandler(validationEventHandler);
172 }
173 return marshaller;
174 }
175
176 @Override
177 public <T> Binder<T> createBinder(Class<T> domType) {
178 return jaxbContext.createBinder(domType);
179 }
180
181 @Override
182 public JAXBIntrospector createJAXBIntrospector() {
183 return jaxbContext.createJAXBIntrospector();
184 }
185
186 @Override
187 public void generateSchema(SchemaOutputResolver outputResolver) throws IOException {
188 jaxbContext.generateSchema(outputResolver);
189 }
190
191 }