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