Comprehensive abstraction layer over JAXB model information providing vendor-neutral access to type metadata, property information, and schema details through visitor pattern support. This abstraction enables tools to inspect and work with JAXB model metadata independently of the underlying JAXB implementation.
interface MModelInfo<T, C> extends MCustomizable {
Collection<MBuiltinLeafInfo<T, C>> getBuiltinLeafInfos();
Collection<MClassInfo<T, C>> getClassInfos();
Collection<MEnumLeafInfo<T, C>> getEnumLeafInfos();
Collection<MElementInfo<T, C>> getElementInfos();
void addBuiltinLeafInfo(MBuiltinLeafInfo<T, C> info);
void addClassInfo(MClassInfo<T, C> info);
void addEnumLeafInfo(MEnumLeafInfo<T, C> info);
void addElementInfo(MElementInfo<T, C> info);
void removeBuiltinLeafInfo(MBuiltinLeafInfo<T, C> info);
void removeClassInfo(MClassInfo<T, C> info);
void removeEnumLeafInfo(MEnumLeafInfo<T, C> info);
void removeElementInfo(MElementInfo<T, C> info);
}interface MTypeInfo<T, C> extends MCustomizable {
QName getTypeName();
boolean isSimpleType();
T getTargetType();
<V> V acceptTypeInfoVisitor(MTypeInfoVisitor<T, C, V> visitor);
}
interface MClassInfo<T, C> extends MClassTypeInfo<T, C> {
List<MPropertyInfo<T, C>> getProperties();
MPropertyInfo<T, C> getProperty(String publicName);
QName getElementName();
MClassTypeInfo<T, C, ?> getBaseTypeInfo();
}
interface MEnumLeafInfo<T, C> extends MTypeInfo<T, C> {
List<MEnumConstantInfo<T, C>> getEnumConstants();
MEnumConstantInfo<T, C> getEnumConstant(String name);
}
interface MElementInfo<T, C> extends MPackaged, MCustomizable {
QName getElementName();
MTypeInfo<T, C> getTypeInfo();
MElement getElement();
}interface MPropertyInfo<T, C> extends MTargeted<T>, MCustomizable {
String getPrivateName();
String getPublicName();
boolean isCollection();
boolean isRequired();
MDefaultValue getDefaultValue();
<V> V acceptPropertyInfoVisitor(MPropertyInfoVisitor<T, C, V> visitor);
}
// Specific property types
interface MElementPropertyInfo<T, C> extends MSingleTypePropertyInfo<T, C>, MWrappable {
QName getWrapperElementName();
}
interface MAttributePropertyInfo<T, C> extends MSingleTypePropertyInfo<T, C> {
QName getAttributeName();
boolean isRequired();
}
interface MAnyElementPropertyInfo<T, C> extends MPropertyInfo<T, C>, MMixable {
boolean isLax();
Set<QName> getProcessContents();
}
interface MAnyAttributePropertyInfo<T, C> extends MPropertyInfo<T, C> {
// Marker interface for any attribute properties
}
interface MValuePropertyInfo<T, C> extends MSingleTypePropertyInfo<T, C> {
// Marker interface for value properties
}
interface MElementRefPropertyInfo<T, C> extends MPropertyInfo<T, C>, MWrappable {
MElementInfo<T, C> getElementInfo();
}
interface MElementRefsPropertyInfo<T, C> extends MPropertyInfo<T, C>, MWrappable, MMixable {
List<MElementTypeInfo<T, C>> getElementTypeInfos();
}
interface MElementsPropertyInfo<T, C> extends MPropertyInfo<T, C>, MWrappable, MMixable {
List<MElementTypeInfo<T, C>> getElementTypeInfos();
}interface MTypeInfoVisitor<T, C, V> {
V visitBuiltinLeafInfo(MBuiltinLeafInfo<T, C> info);
V visitEnumLeafInfo(MEnumLeafInfo<T, C> info);
V visitWildcardTypeInfo(MWildcardTypeInfo<T, C> info);
<NTI extends MTypeInfo<T, C>> V visitClassInfo(MClassInfo<T, C> info);
<NTI extends MTypeInfo<T, C>> V visitClassRef(MClassRef<T, C> info);
}
interface MClassTypeInfoVisitor<T, C, V> {
V visitClassInfo(MClassInfo<T, C> info);
V visitClassRef(MClassRef<T, C> info);
}
interface MPropertyInfoVisitor<T, C, V> {
V visitElementPropertyInfo(MElementPropertyInfo<T, C> info);
V visitElementsPropertyInfo(MElementsPropertyInfo<T, C> info);
V visitElementRefPropertyInfo(MElementRefPropertyInfo<T, C> info);
V visitElementRefsPropertyInfo(MElementRefsPropertyInfo<T, C> info);
V visitAttributePropertyInfo(MAttributePropertyInfo<T, C> info);
V visitAnyElementPropertyInfo(MAnyElementPropertyInfo<T, C> info);
V visitAnyAttributePropertyInfo(MAnyAttributePropertyInfo<T, C> info);
V visitValuePropertyInfo(MValuePropertyInfo<T, C> info);
}interface MCustomizable {
MCustomizations getCustomizations();
void setCustomizations(MCustomizations customizations);
}
interface MOriginated<O> {
O getOrigin();
}
interface MPackaged {
MPackageInfo getPackageInfo();
}
interface MContained {
MContainer getContainer();
}
interface MContainer {
Collection<? extends MContained> getContainedInfos();
}
interface MTargeted<T> {
T getTargetType();
}
interface MWrappable {
QName getWrapperElementName();
}
interface MMixable {
boolean isMixed();
}
interface MNillable {
boolean isNillable();
}abstract class CMInfoFactory<T, C, TI extends MTypeInfo<T, C>, CI extends MClassInfo<T, C>,
ELI extends MEnumLeafInfo<T, C>, EI extends MElementInfo<T, C>> {
public abstract MModelInfo<T, C> createModel();
// Factory methods for creating concrete model implementations
protected abstract CI createClassInfo();
protected abstract ELI createEnumLeafInfo();
protected abstract EI createElementInfo();
protected abstract MPropertyInfo<T, C> createPropertyInfo();
// ... additional factory methods
}abstract class DefaultTypeInfoVisitor<T, C, V> implements MTypeInfoVisitor<T, C, V> {
// Default empty implementations for all visitor methods
public V visitBuiltinLeafInfo(MBuiltinLeafInfo<T, C> info) { return null; }
public V visitEnumLeafInfo(MEnumLeafInfo<T, C> info) { return null; }
public V visitWildcardTypeInfo(MWildcardTypeInfo<T, C> info) { return null; }
public <NTI extends MTypeInfo<T, C>> V visitClassInfo(MClassInfo<T, C> info) { return null; }
public <NTI extends MTypeInfo<T, C>> V visitClassRef(MClassRef<T, C> info) { return null; }
}
abstract class DefaultPropertyInfoVisitor<T, C, V> implements MPropertyInfoVisitor<T, C, V> {
// Default empty implementations for all visitor methods
public V visitElementPropertyInfo(MElementPropertyInfo<T, C> info) { return null; }
public V visitAttributePropertyInfo(MAttributePropertyInfo<T, C> info) { return null; }
// ... additional default methods
}
final class XmlTypeUtils {
static QName getTypeName(Class<?> targetClass);
// Extracts QName from @XmlType annotation
}
final class QNameCollector {
Collection<QName> collectQNames(MModelInfo<?, ?> modelInfo);
// Collects all QNames from model components
}
final class QNameUtils {
static String getKey(QName name);
// Converts QName to string key representation
}import org.jvnet.jaxb2_commons.xml.bind.model.*;
import org.jvnet.jaxb2_commons.xml.bind.model.concrete.*;
import javax.xml.bind.JAXBContext;
// Create model from JAXB context
JAXBContext context = JAXBContext.newInstance("com.example.schema");
CMInfoFactory<Type, Class, ?, ?, ?, ?> factory = new CMInfoFactory<Type, Class, ?, ?, ?, ?>(context);
MModelInfo<Type, Class> model = factory.createModel();
// Inspect class information
for (MClassInfo<Type, Class> classInfo : model.getClassInfos()) {
System.out.println("Class: " + classInfo.getTargetType().getName());
System.out.println("Element Name: " + classInfo.getElementName());
// Inspect properties
for (MPropertyInfo<Type, Class> property : classInfo.getProperties()) {
System.out.println(" Property: " + property.getPublicName() +
" (" + property.getPrivateName() + ")");
System.out.println(" Collection: " + property.isCollection());
System.out.println(" Required: " + property.isRequired());
}
}
// Inspect enum information
for (MEnumLeafInfo<Type, Class> enumInfo : model.getEnumLeafInfos()) {
System.out.println("Enum: " + enumInfo.getTargetType().getName());
for (MEnumConstantInfo<Type, Class> constant : enumInfo.getEnumConstants()) {
System.out.println(" Constant: " + constant.getName());
}
}import org.jvnet.jaxb2_commons.xml.bind.model.util.*;
public class PropertyAnalyzer extends DefaultPropertyInfoVisitor<Type, Class, Void> {
@Override
public Void visitElementPropertyInfo(MElementPropertyInfo<Type, Class> info) {
System.out.println("Element Property: " + info.getPublicName());
if (info.getWrapperElementName() != null) {
System.out.println(" Wrapper: " + info.getWrapperElementName());
}
return null;
}
@Override
public Void visitAttributePropertyInfo(MAttributePropertyInfo<Type, Class> info) {
System.out.println("Attribute Property: " + info.getPublicName());
System.out.println(" Attribute Name: " + info.getAttributeName());
System.out.println(" Required: " + info.isRequired());
return null;
}
@Override
public Void visitAnyElementPropertyInfo(MAnyElementPropertyInfo<Type, Class> info) {
System.out.println("Any Element Property: " + info.getPublicName());
System.out.println(" Lax: " + info.isLax());
System.out.println(" Mixed: " + info.isMixed());
return null;
}
@Override
public Void visitElementsPropertyInfo(MElementsPropertyInfo<Type, Class> info) {
System.out.println("Elements Property: " + info.getPublicName());
System.out.println(" Element Types: " + info.getElementTypeInfos().size());
for (MElementTypeInfo<Type, Class> elementType : info.getElementTypeInfos()) {
System.out.println(" Element: " + elementType.getElementName());
}
return null;
}
}
// Usage
PropertyAnalyzer analyzer = new PropertyAnalyzer();
for (MClassInfo<Type, Class> classInfo : model.getClassInfos()) {
for (MPropertyInfo<Type, Class> property : classInfo.getProperties()) {
property.acceptPropertyInfoVisitor(analyzer);
}
}import org.jvnet.jaxb2_commons.xml.bind.model.util.*;
import javax.xml.namespace.QName;
public class SchemaAnalyzer {
public void analyzeSchema(MModelInfo<Type, Class> model) {
// Collect all QNames from the model
QNameCollector collector = new QNameCollector();
Collection<QName> qnames = collector.collectQNames(model);
// Group by namespace
Map<String, List<QName>> namespaceGroups = qnames.stream()
.collect(Collectors.groupingBy(QName::getNamespaceURI));
System.out.println("Schema Analysis:");
for (Map.Entry<String, List<QName>> entry : namespaceGroups.entrySet()) {
String namespace = entry.getKey();
List<QName> names = entry.getValue();
System.out.println("Namespace: " + (namespace.isEmpty() ? "(default)" : namespace));
for (QName name : names) {
System.out.println(" " + name.getLocalPart());
}
}
// Generate unique keys for QNames
for (QName qname : qnames) {
String key = QNameUtils.getKey(qname);
System.out.println("QName: " + qname + " -> Key: " + key);
}
}
}import org.jvnet.jaxb2_commons.xml.bind.model.util.*;
public class TypeInfoAnalyzer extends DefaultTypeInfoVisitor<Type, Class, TypeAnalysisResult> {
@Override
public TypeAnalysisResult visitClassInfo(MClassInfo<Type, Class> info) {
TypeAnalysisResult result = new TypeAnalysisResult();
result.setTypeName(info.getTypeName());
result.setJavaType(info.getTargetType());
result.setPropertyCount(info.getProperties().size());
// Analyze inheritance
MClassTypeInfo<Type, Class, ?> baseType = info.getBaseTypeInfo();
if (baseType != null) {
result.setHasInheritance(true);
result.setBaseType(baseType.getTypeName());
}
// Count different property types
int elementProps = 0, attributeProps = 0, anyProps = 0;
for (MPropertyInfo<Type, Class> prop : info.getProperties()) {
prop.acceptPropertyInfoVisitor(new DefaultPropertyInfoVisitor<Type, Class, Void>() {
@Override
public Void visitElementPropertyInfo(MElementPropertyInfo<Type, Class> info) {
elementProps++;
return null;
}
@Override
public Void visitAttributePropertyInfo(MAttributePropertyInfo<Type, Class> info) {
attributeProps++;
return null;
}
@Override
public Void visitAnyElementPropertyInfo(MAnyElementPropertyInfo<Type, Class> info) {
anyProps++;
return null;
}
});
}
result.setElementPropertyCount(elementProps);
result.setAttributePropertyCount(attributeProps);
result.setAnyPropertyCount(anyProps);
return result;
}
@Override
public TypeAnalysisResult visitEnumLeafInfo(MEnumLeafInfo<Type, Class> info) {
TypeAnalysisResult result = new TypeAnalysisResult();
result.setTypeName(info.getTypeName());
result.setJavaType(info.getTargetType());
result.setEnumConstantCount(info.getEnumConstants().size());
return result;
}
}
// Analysis result class
public class TypeAnalysisResult {
private QName typeName;
private Class javaType;
private int propertyCount;
private boolean hasInheritance;
private QName baseType;
private int elementPropertyCount;
private int attributePropertyCount;
private int anyPropertyCount;
private int enumConstantCount;
// getters and setters...
}
// Usage
TypeInfoAnalyzer analyzer = new TypeInfoAnalyzer();
for (MClassInfo<Type, Class> classInfo : model.getClassInfos()) {
TypeAnalysisResult analysis = classInfo.acceptTypeInfoVisitor(analyzer);
System.out.println("Analysis for " + analysis.getTypeName() + ":");
System.out.println(" Java Type: " + analysis.getJavaType().getSimpleName());
System.out.println(" Properties: " + analysis.getPropertyCount());
System.out.println(" Elements: " + analysis.getElementPropertyCount());
System.out.println(" Attributes: " + analysis.getAttributePropertyCount());
if (analysis.isHasInheritance()) {
System.out.println(" Base Type: " + analysis.getBaseType());
}
}public class ModelValidator {
public void validateModel(MModelInfo<Type, Class> model) {
Set<String> errors = new HashSet<>();
// Validate class information
for (MClassInfo<Type, Class> classInfo : model.getClassInfos()) {
validateClassInfo(classInfo, errors);
}
// Validate element information
for (MElementInfo<Type, Class> elementInfo : model.getElementInfos()) {
validateElementInfo(elementInfo, errors);
}
// Report validation results
if (errors.isEmpty()) {
System.out.println("Model validation passed");
} else {
System.out.println("Model validation failed with errors:");
errors.forEach(System.out::println);
}
}
private void validateClassInfo(MClassInfo<Type, Class> classInfo, Set<String> errors) {
if (classInfo.getTypeName() == null) {
errors.add("Class " + classInfo.getTargetType().getName() + " has null type name");
}
// Check for duplicate property names
Set<String> propertyNames = new HashSet<>();
for (MPropertyInfo<Type, Class> property : classInfo.getProperties()) {
String publicName = property.getPublicName();
if (!propertyNames.add(publicName)) {
errors.add("Class " + classInfo.getTargetType().getName() +
" has duplicate property: " + publicName);
}
validatePropertyInfo(property, classInfo, errors);
}
}
private void validatePropertyInfo(MPropertyInfo<Type, Class> property,
MClassInfo<Type, Class> owner, Set<String> errors) {
if (property.getPublicName() == null || property.getPublicName().trim().isEmpty()) {
errors.add("Property in class " + owner.getTargetType().getName() +
" has null or empty public name");
}
if (property.getPrivateName() == null || property.getPrivateName().trim().isEmpty()) {
errors.add("Property " + property.getPublicName() + " in class " +
owner.getTargetType().getName() + " has null or empty private name");
}
}
private void validateElementInfo(MElementInfo<Type, Class> elementInfo, Set<String> errors) {
if (elementInfo.getElementName() == null) {
errors.add("Element info has null element name");
}
if (elementInfo.getTypeInfo() == null) {
errors.add("Element " + elementInfo.getElementName() + " has null type info");
}
}
}The model abstraction provides several key benefits:
This abstraction is essential for tools that need to analyze, validate, or transform JAXB models independently of the underlying JAXB implementation.