All Downloads are FREE. Search and download functionalities are using the official Maven repository.

japicmp.output.xml.XmlOutputGenerator Maven / Gradle / Ivy

Go to download

japicmp is a library that computes the differences between two versions of a jar file/artifact in order to ease the API documentation for clients/customers.

There is a newer version: 0.23.1
Show newest version
package japicmp.output.xml;

import japicmp.config.Options;
import japicmp.exception.JApiCmpException;
import japicmp.exception.JApiCmpException.Reason;
import japicmp.model.JApiClass;
import japicmp.output.OutputFilter;
import japicmp.output.OutputGenerator;
import japicmp.output.xml.model.JApiCmpXmlRoot;
import japicmp.util.Optional;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.SchemaOutputResolver;
import javax.xml.transform.Result;
import javax.xml.transform.stream.StreamResult;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Pattern;

import static japicmp.util.StringHelper.filtersAsString;

public class XmlOutputGenerator extends OutputGenerator {
	private static final String XSD_FILENAME = "japicmp.xsd";
	private static final String XML_SCHEMA = XSD_FILENAME;
	private static final Logger LOGGER = Logger.getLogger(XmlOutputGenerator.class.getName());
	private final XmlOutputGeneratorOptions xmlOutputGeneratorOptions;

	@Deprecated
	public XmlOutputGenerator(List jApiClasses, Options options, boolean createSchemaFile) {
		super(options, jApiClasses);
		this.xmlOutputGeneratorOptions = new XmlOutputGeneratorOptions();
		this.xmlOutputGeneratorOptions.setCreateSchemaFile(createSchemaFile);
	}

	public XmlOutputGenerator(List jApiClasses, Options options, XmlOutputGeneratorOptions xmlOutputGeneratorOptions) {
		super(options, jApiClasses);
		this.xmlOutputGeneratorOptions = xmlOutputGeneratorOptions;
	}

	@Override
	public XmlOutput generate() {
		JApiCmpXmlRoot jApiCmpXmlRoot = createRootElement(jApiClasses, options);
		filterClasses(jApiClasses, options);
		return createXmlDocumentAndSchema(options, jApiCmpXmlRoot);
	}

	public static List writeToFiles(Options options, XmlOutput xmlOutput) {
		List filesWritten = new ArrayList<>();
		try {
			if (xmlOutput.getXmlOutputStream().isPresent() && options.getXmlOutputFile().isPresent()) {
				File xmlFile = new File(options.getXmlOutputFile().get());
				try (FileOutputStream fos = new FileOutputStream(xmlFile)) {
					ByteArrayOutputStream outputStream = xmlOutput.getXmlOutputStream().get();
					outputStream.writeTo(fos);
					filesWritten.add(xmlFile);
				} catch (IOException e) {
					throw new JApiCmpException(JApiCmpException.Reason.IoException, "Failed to write XML file '" + xmlFile.getAbsolutePath() + "': " + e.getMessage(), e);
				}
			}
		} finally {
			try {
				xmlOutput.close();
			} catch (Exception e) {
				LOGGER.log(Level.FINE, "Failed to close XML file: " + e.getLocalizedMessage(), e);
			}
		}
		return filesWritten;
	}

	private XmlOutput createXmlDocumentAndSchema(Options options, JApiCmpXmlRoot jApiCmpXmlRoot) {
		XmlOutput xmlOutput = new XmlOutput();
		xmlOutput.setJApiCmpXmlRoot(jApiCmpXmlRoot);
		ByteArrayOutputStream xmlBaos;
		try {
			JAXBContext jaxbContext = JAXBContext.newInstance(JApiCmpXmlRoot.class);
			Marshaller marshaller = jaxbContext.createMarshaller();
			marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
			marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
			marshaller.setProperty(Marshaller.JAXB_NO_NAMESPACE_SCHEMA_LOCATION, XML_SCHEMA);
			xmlBaos = new ByteArrayOutputStream();
			marshaller.marshal(jApiCmpXmlRoot, xmlBaos);
			if (options.getXmlOutputFile().isPresent()) {
				xmlOutput.setXmlOutputStream(Optional.of(xmlBaos));
				if (xmlOutputGeneratorOptions.isCreateSchemaFile()) {
					final File xmlFile = new File(options.getXmlOutputFile().get());
					SchemaOutputResolver outputResolver = new SchemaOutputResolver() {
						@Override
						public Result createOutput(String namespaceUri, String suggestedFileName) {
							File schemaFile = xmlFile.getParentFile();
							if (schemaFile == null) {
								LOGGER.warning(String.format("File '%s' has no parent file. Using instead: '%s'.", xmlFile.getAbsolutePath(), XSD_FILENAME));
								schemaFile = new File(XSD_FILENAME);
							} else {
								schemaFile = new File(schemaFile + File.separator + XSD_FILENAME);
							}
							StreamResult result = new StreamResult(schemaFile);
							result.setSystemId(schemaFile.getAbsolutePath());
							return result;
						}
					};
					jaxbContext.generateSchema(outputResolver);
				}
			}
		} catch (JAXBException e) {
			throw new JApiCmpException(Reason.JaxbException, String.format("Marshalling of XML document failed: %s", e.getMessage()), e);
		} catch (IOException e) {
			throw new JApiCmpException(Reason.IoException, String.format("Marshalling of XML document failed: %s", e.getMessage()), e);
		}
		return xmlOutput;
	}

	private void filterClasses(List jApiClasses, Options options) {
		OutputFilter outputFilter = new OutputFilter(options);
		outputFilter.filter(jApiClasses);
	}

	private JApiCmpXmlRoot createRootElement(List jApiClasses, Options options) {
		JApiCmpXmlRoot jApiCmpXmlRoot = new JApiCmpXmlRoot();
		jApiCmpXmlRoot.setOldJar(options.joinOldArchives());
		jApiCmpXmlRoot.setNewJar(options.joinNewArchives());
		jApiCmpXmlRoot.setOldVersion(options.joinOldVersions());
		jApiCmpXmlRoot.setNewVersion(options.joinNewVersions());
		jApiCmpXmlRoot.setClasses(jApiClasses);
		jApiCmpXmlRoot.setAccessModifier(options.getAccessModifier().name());
		jApiCmpXmlRoot.setOnlyModifications(options.isOutputOnlyModifications());
		jApiCmpXmlRoot.setOnlyBinaryIncompatibleModifications(options.isOutputOnlyBinaryIncompatibleModifications());
		jApiCmpXmlRoot.setPackagesInclude(filtersAsString(options.getIncludes(), true));
		jApiCmpXmlRoot.setPackagesExclude(filtersAsString(options.getExcludes(), false));
		jApiCmpXmlRoot.setIgnoreMissingClasses(options.getIgnoreMissingClasses().isIgnoreAllMissingClasses());
		jApiCmpXmlRoot.setIgnoreMissingClassesByRegularExpressions(regExAsString(options.getIgnoreMissingClasses().getIgnoreMissingClassRegularExpression()));
		if (xmlOutputGeneratorOptions.getTitle().isPresent()) {
			jApiCmpXmlRoot.setTitle(xmlOutputGeneratorOptions.getTitle().get());
		}
		jApiCmpXmlRoot.setSemanticVersioning(xmlOutputGeneratorOptions.getSemanticVersioningInformation());
		return jApiCmpXmlRoot;
	}

	private String regExAsString(List ignoreMissingClassRegularExpression) {
		StringBuilder sb = new StringBuilder();
		for (Pattern pattern : ignoreMissingClassRegularExpression) {
			if (sb.length() > 0) {
				sb.append(";");
			}
			sb.append(pattern.toString());
		}
		return sb.toString();
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy