JaxbContextData.java
/*
* Copyright 2020-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bremersee.xml;
import static java.util.Objects.nonNull;
import static java.util.Objects.requireNonNull;
import jakarta.xml.bind.annotation.XmlRootElement;
import jakarta.xml.bind.annotation.XmlType;
import java.util.Optional;
import java.util.stream.Stream;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import org.springframework.util.Assert;
/**
* Meta-data to describe a xml model.
*
* @author Christian Bremer
*/
@EqualsAndHashCode
public final class JaxbContextData implements JaxbContextMember, Comparable<JaxbContextData> {
@Getter
private final Class<?> clazz;
@Getter
private final String clazzElementSchemaLocation;
@Getter
private final String clazzTypeSchemaLocation;
private final Package pakkage;
@Getter
private final String pakkageSchemaLocation;
/**
* Instantiates a new jaxb context data.
*
* @param clazz the class
*/
public JaxbContextData(Class<?> clazz) {
this(clazz, null, null);
}
/**
* Instantiates a new jaxb context data.
*
* @param clazz the class
* @param clazzElementSchemaLocation the class element schema location
* @param clazzTypeSchemaLocation the class type schema location
*/
public JaxbContextData(
Class<?> clazz,
String clazzElementSchemaLocation,
String clazzTypeSchemaLocation) {
this(validate(JaxbContextMember.byClass(clazz)
.clazzElementSchemaLocation(clazzElementSchemaLocation)
.clazzTypeSchemaLocation(clazzTypeSchemaLocation)
.build()));
}
/**
* Instantiates a new jaxb context data.
*
* @param pakkage the package
*/
public JaxbContextData(Package pakkage) {
this(pakkage, null);
}
/**
* Instantiates a new Jaxb context data.
*
* @param clazz the class
* @param pakkageSchemaLocation the package schema location
*/
public JaxbContextData(Class<?> clazz, String pakkageSchemaLocation) {
this(validate(new JaxbContextMemberImpl(
clazz,
null,
null,
null,
pakkageSchemaLocation)));
}
/**
* Instantiates a new jaxb context data.
*
* @param pakkage the package
* @param pakkageSchemaLocation the package schema location
*/
public JaxbContextData(Package pakkage, String pakkageSchemaLocation) {
this(validate(JaxbContextMember.byPackage(pakkage)
.schemaLocation(pakkageSchemaLocation)
.build()));
}
JaxbContextData(JaxbContextMember jaxbContextMember) {
JaxbContextMember validated = validate(jaxbContextMember);
this.pakkage = validated.getPakkage();
this.pakkageSchemaLocation = validated.getPakkageSchemaLocation();
this.clazz = validated.getClazz();
this.clazzElementSchemaLocation = validated.getClazzElementSchemaLocation();
this.clazzTypeSchemaLocation = validated.getClazzTypeSchemaLocation();
}
private static JaxbContextMember validate(JaxbContextMember source) {
Assert.notNull(source, "Jaxb context member must be present.");
if (nonNull(source.getClazz()) && nonNull(source.getPakkage())) {
Assert.isTrue(source.getPakkage().equals(source.getClazz().getPackage()),
"If package and class are present, class must be a member of the package.");
if (JaxbUtils.isJaxbModelPackage(source.getPakkage())) {
return validate(JaxbContextMember.byPackage(source.getPakkage())
.schemaLocation(source.getPakkageSchemaLocation())
.build());
}
return validate(JaxbContextMember.byClass(source.getClazz())
.clazzElementSchemaLocation(source.getClazzElementSchemaLocation())
.clazzTypeSchemaLocation(source.getClazzTypeSchemaLocation())
.build());
}
if (nonNull(source.getClazz()) && JaxbUtils.isInJaxbModelPackage(source.getClazz())) {
return validate(JaxbContextMember.byPackage(source.getClazz().getPackage())
.schemaLocation(source.getPakkageSchemaLocation())
.build());
}
if (nonNull(source.getClazz())
&& (source.getClazz().isAnnotationPresent(XmlRootElement.class)
|| source.getClazz().isAnnotationPresent(XmlType.class))) {
return source;
} else if (nonNull(source.getClazz())) {
throw new IllegalArgumentException(
String.format(
"Class '%s' must be annotated with 'XmlRootElement' or 'XmlType'.",
source.getClazz().getName()));
}
if (nonNull(source.getPakkage()) && JaxbUtils.isJaxbModelPackage(source.getPakkage())) {
return JaxbContextMember.byPackage(source.getPakkage())
.schemaLocation(Optional.ofNullable(source.getPakkageSchemaLocation())
.filter(location -> !location.isBlank())
.or(() -> JaxbUtils.getSchemaLocation(source.getPakkage()))
.orElse(null))
.build();
} else if (nonNull(source.getPakkage())) {
throw new IllegalArgumentException(
String.format(
"Package '%s' does not contain 'ObjectFactory.class' or 'jaxb.index'.",
source.getPakkage().getName()));
}
throw new IllegalArgumentException("Class or package must be present.");
}
public Package getPakkage() {
return nonNull(pakkage) ? pakkage : requireNonNull(clazz).getPackage();
}
/**
* Gets key.
*
* @return the key
*/
Object getKey() {
return nonNull(pakkage) ? pakkage : requireNonNull(clazz);
}
/**
* Gets jaxb classes.
*
* @param classLoaders the class loaders
* @return the jaxb classes
*/
public Stream<Class<?>> getJaxbClasses(ClassLoader... classLoaders) {
return JaxbUtils.findJaxbClasses(getPakkage().getName(), classLoaders);
}
/**
* Gets name spaces with schema locations.
*
* @return the name spaces with schema locations
*/
public Stream<SchemaLocation> getNameSpacesWithSchemaLocations() {
return Stream.of(
Optional.ofNullable(pakkageSchemaLocation)
.filter(location -> !location.isBlank())
.flatMap(location -> JaxbUtils.getNameSpace(pakkage)
.map(ns -> new SchemaLocation(ns, location))),
Optional.ofNullable(clazzElementSchemaLocation)
.filter(location -> !location.isBlank())
.flatMap(location -> JaxbUtils.getNameSpaceOfElement(clazz)
.map(ns -> new SchemaLocation(ns, location))),
Optional.ofNullable(clazzTypeSchemaLocation)
.filter(location -> !location.isBlank())
.flatMap(location -> JaxbUtils.getNameSpaceOfType(clazz)
.map(ns -> new SchemaLocation(ns, location))))
.flatMap(Optional::stream)
.distinct();
}
@Override
public String toString() {
return "JaxbContextData{"
+ "clazz=" + (nonNull(clazz) ? clazz.getName() : "null")
+ ", clazzElementSchemaLocation='" + clazzElementSchemaLocation + '\''
+ ", clazzTypeSchemaLocation='" + clazzTypeSchemaLocation + '\''
+ ", pakkage=" + (nonNull(pakkage) ? pakkage.getName() : "null")
+ ", pakkageSchemaLocation='" + pakkageSchemaLocation + '\''
+ '}';
}
@Override
public int compareTo(JaxbContextData o) {
String a = nonNull(pakkage) ? pakkage.getName() : requireNonNull(clazz).getName();
String b = nonNull(o.pakkage) ? o.pakkage.getName() : requireNonNull(o.clazz).getName();
return a.compareToIgnoreCase(b);
}
}