1 /*
2 * Copyright 2020-2022 the original author or authors.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package org.bremersee.xml;
18
19 import java.util.Collection;
20 import java.util.Iterator;
21 import java.util.Optional;
22 import java.util.Spliterator;
23 import java.util.Spliterators;
24 import java.util.stream.StreamSupport;
25 import jakarta.xml.bind.Marshaller;
26 import jakarta.xml.bind.Unmarshaller;
27 import jakarta.xml.bind.ValidationEventHandler;
28 import jakarta.xml.bind.annotation.XmlRootElement;
29 import jakarta.xml.bind.annotation.XmlType;
30 import jakarta.xml.bind.annotation.adapters.XmlAdapter;
31 import jakarta.xml.bind.attachment.AttachmentMarshaller;
32 import jakarta.xml.bind.attachment.AttachmentUnmarshaller;
33 import javax.xml.validation.Schema;
34
35 /**
36 * The jaxb context builder.
37 *
38 * @author Christian Bremer
39 */
40 public interface JaxbContextBuilder {
41
42 /**
43 * The default dependencies resolver implementation.
44 */
45 JaxbDependenciesResolver DEFAULT_DEPENDENCIES_RESOLVER = new JaxbDependenciesResolverImpl();
46
47
48 /**
49 * Creates a new jaxb context builder.
50 *
51 * @return the jaxb context builder
52 */
53 static JaxbContextBuilder newInstance() {
54 return new JaxbContextBuilderImpl();
55 }
56
57
58 /**
59 * Copy jaxb context builder.
60 *
61 * @return the jaxb context builder
62 */
63 JaxbContextBuilder copy();
64
65 /**
66 * Specifies whether to add a schema to the marshaller or unmarshaller. The default is to add
67 * never a schema to the marshaller or unmarshaller.
68 *
69 * @param schemaMode the schema mode
70 * @return the jaxb context builder
71 * @see SchemaMode#NEVER
72 * @see SchemaMode#ALWAYS
73 * @see SchemaMode#MARSHAL
74 * @see SchemaMode#UNMARSHAL
75 * @see SchemaMode#EXTERNAL_XSD
76 */
77 JaxbContextBuilder withSchemaMode(SchemaMode schemaMode);
78
79 /**
80 * Specifies the schema builder to generate the schema. The default is the default schema builder
81 * implementation (see {@link SchemaBuilder#newInstance()}).
82 *
83 * @param schemaBuilder the schema builder
84 * @return the jaxb context builder
85 */
86 JaxbContextBuilder withSchemaBuilder(SchemaBuilder schemaBuilder);
87
88 /**
89 * Specifies the dependencies-resolver to use. The default jaxb context builder will use a default
90 * implementation.
91 *
92 * <p>To turn off dependency resolving set {@code null} here.
93 *
94 * @param resolver the resolver
95 * @return the jaxb context builder
96 */
97 JaxbContextBuilder withDependenciesResolver(JaxbDependenciesResolver resolver);
98
99 /**
100 * Specifies the class loader to use.
101 *
102 * @param classLoader the class loader
103 * @return the jaxb context builder
104 */
105 JaxbContextBuilder withContextClassLoader(ClassLoader classLoader);
106
107 /**
108 * Specify whether the xml output should be formatted or not.
109 *
110 * @param formattedOutput the formatted output
111 * @return the jaxb context builder
112 */
113 JaxbContextBuilder withFormattedOutput(boolean formattedOutput);
114
115 /**
116 * Sets xml adapters of marshaller and unmarshaller.
117 *
118 * @param xmlAdapters the xml adapters
119 * @return the jaxb context builder
120 */
121 JaxbContextBuilder withXmlAdapters(Collection<? extends XmlAdapter<?, ?>> xmlAdapters);
122
123 /**
124 * Set attachment marshaller.
125 *
126 * @param attachmentMarshaller the attachment marshaller
127 * @return the jaxb context builder
128 */
129 JaxbContextBuilder withAttachmentMarshaller(AttachmentMarshaller attachmentMarshaller);
130
131 /**
132 * Set attachment unmarshaller.
133 *
134 * @param attachmentUnmarshaller the attachment unmarshaller
135 * @return the jaxb context builder
136 */
137 JaxbContextBuilder withAttachmentUnmarshaller(AttachmentUnmarshaller attachmentUnmarshaller);
138
139 /**
140 * Set validation event handler of marshaller and unmarshaller.
141 *
142 * @param validationEventHandler the validation event handler
143 * @return the jaxb context builder
144 */
145 JaxbContextBuilder withValidationEventHandler(ValidationEventHandler validationEventHandler);
146
147
148 /**
149 * Add jaxb context meta-data to the jaxb context builder.
150 *
151 * @param data the data
152 * @return the jaxb context builder
153 */
154 JaxbContextBuilder add(JaxbContextMember data);
155
156 /**
157 * Add all jaxb context meta-data to the jaxb context builder.
158 *
159 * @param data the data
160 * @return the jaxb context builder
161 */
162 default JaxbContextBuilder addAll(Iterable<? extends JaxbContextMember> data) {
163 return Optional.ofNullable(data)
164 .map(d -> addAll(d.iterator()))
165 .orElse(this);
166 }
167
168 /**
169 * Add all jaxb context meta-data to the jaxb context builder.
170 *
171 * @param data the data
172 * @return the jaxb context builder
173 */
174 default JaxbContextBuilder addAll(Iterator<? extends JaxbContextMember> data) {
175 return Optional.ofNullable(data)
176 .map(iter -> Spliterators.spliteratorUnknownSize(iter, Spliterator.ORDERED))
177 .stream()
178 .flatMap(split -> StreamSupport.stream(split, false))
179 .map(this::add)
180 .reduce((first, second) -> second)
181 .orElse(this);
182 }
183
184 /**
185 * Process the jaxb context meta-data provider and add its data to the jaxb context builder.
186 *
187 * @param dataProvider the data provider
188 * @return the jaxb context builder
189 */
190 default JaxbContextBuilder process(JaxbContextDataProvider dataProvider) {
191 return Optional.ofNullable(dataProvider)
192 .map(provider -> addAll(provider.getJaxbContextData()))
193 .orElse(this);
194 }
195
196 /**
197 * Process the jaxb context meta-data providers and add their data to the jaxb context builder.
198 *
199 * @param dataProviders the data providers
200 * @return the jaxb context builder
201 */
202 default JaxbContextBuilder processAll(
203 Iterable<? extends JaxbContextDataProvider> dataProviders) {
204 return Optional.ofNullable(dataProviders)
205 .map(providers -> processAll(providers.iterator()))
206 .orElse(this);
207 }
208
209 /**
210 * Process the jaxb context meta-data providers and add their data to the jaxb context builder.
211 *
212 * @param dataProviders the data providers
213 * @return the jaxb context builder
214 */
215 default JaxbContextBuilder processAll(
216 Iterator<? extends JaxbContextDataProvider> dataProviders) {
217 return Optional.ofNullable(dataProviders)
218 .map(iter -> Spliterators.spliteratorUnknownSize(iter, Spliterator.ORDERED))
219 .stream()
220 .flatMap(split -> StreamSupport.stream(split, false))
221 .map(this::process)
222 .reduce((first, second) -> second)
223 .orElse(this);
224 }
225
226 /**
227 * Determines whether the unmarshaller can decode xml into an object of the given class.
228 *
229 * @param clazz the class
230 * @return {@code true} if the unmarshaller can decode xml into an object of the given class,
231 * otherwise {@code false}
232 */
233 default boolean canUnmarshal(Class<?> clazz) {
234 return Optional.ofNullable(clazz)
235 .filter(c -> c.isAnnotationPresent(XmlRootElement.class)
236 || c.isAnnotationPresent(XmlType.class))
237 .isPresent();
238 }
239
240 /**
241 * Determines whether the marshaller can encode an object of the given class into xml.
242 *
243 * @param clazz the class
244 * @return {@code true} if the marshaller can decode an object of the given class into xml,
245 * otherwise {@code false}
246 */
247 default boolean canMarshal(Class<?> clazz) {
248 return Optional.ofNullable(clazz)
249 .filter(c -> c.isAnnotationPresent(XmlRootElement.class))
250 .isPresent();
251 }
252
253 /**
254 * Build unmarshaller for the given classes with the specified dependencies-resolver. If
255 * dependency resolving is turned off, an unmarshaller of the default context (defined by the
256 * added meta-data) will be returned or one that is created with {@link
257 * jakarta.xml.bind.JAXBContext#newInstance(Class[])}*.
258 *
259 * @param classes the classes that should be processed by the unmarshaller
260 * @return the unmarshaller
261 * @see JaxbDependenciesResolver
262 */
263 Unmarshaller buildUnmarshaller(Class<?>... classes);
264
265 /**
266 * Build marshaller with the context which is defined by the added meta-data.
267 *
268 * @return the marshaller
269 */
270 default Marshaller buildMarshaller() {
271 return buildMarshaller(null);
272 }
273
274 /**
275 * Build marshaller for the given object (POJO) or for the given class or array of classes with
276 * the specified dependencies-resolver. If dependency resolving is turned off, a marshaller of the
277 * default context (defined by the added meta-data) will be returned or one that is created with
278 * {@link jakarta.xml.bind.JAXBContext#newInstance(Class[])}.
279 *
280 * @param value the value (POJO) that should be processed by the marshaller or a single class
281 * or an array of classes
282 * @return the marshaller
283 * @see JaxbDependenciesResolver
284 */
285 Marshaller buildMarshaller(Object value);
286
287 /**
288 * Inits default jaxb context. Otherwise, the jaxb context will be created at first usage.
289 *
290 * @return the jaxb context builder
291 */
292 JaxbContextBuilder initJaxbContext();
293
294 /**
295 * Build default jaxb context that is defined by the added meta-data.
296 *
297 * @return the jaxb context wrapper
298 */
299 default JaxbContextWrapper buildJaxbContext() {
300 return buildJaxbContext(null);
301 }
302
303 /**
304 * Build jaxb context for the given object (POJO) or for the given class or array of classes with
305 * the specified dependency resolver. If dependency resolving is turned off, the default jaxb
306 * context (defined by the added meta-data) will be returned or a jaxb context will be created
307 * with {@link jakarta.xml.bind.JAXBContext#newInstance(Class[])}.
308 *
309 * @param value the value (POJO) that should be processed by the jaxb context or a single
310 * class or an array of classes
311 * @return the jaxb context
312 */
313 JaxbContextWrapper buildJaxbContext(Object value);
314
315 /**
316 * Build schema of the default jaxb context (defined by the added meta-data).
317 *
318 * @return the schema
319 */
320 default Schema buildSchema() {
321 return buildSchema(null);
322 }
323
324 /**
325 * Build schema of the specified value (POJO), a single class or an array of classes.
326 *
327 * @param value the value (POJO), a single class or an array of classes for which the schema
328 * should be created
329 * @return the schema
330 */
331 Schema buildSchema(Object value);
332
333 }