View Javadoc
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 }