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