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 }