Task 565: .POM File Format

Task 565: .POM File Format

Based on the specifications, the .POM file format is an XML-based format used in Apache Maven as the Project Object Model (POM). It is not a binary format but a structured text file following the Maven 4.0.0 schema. "Properties intrinsic to its file system" appear to refer to the structural elements (tags and attributes) defined in the POM XML schema that describe the project's configuration, dependencies, build settings, and metadata. These are not file system metadata (like size or permissions) but the intrinsic data fields within the file format itself. Here is a comprehensive list of all top-level properties (XML elements) under the root <project> element, along with their key sub-properties and brief descriptions, derived from the official Maven POM reference:

  • modelVersion: Required; specifies the POM schema version (must be 4.0.0).
  • groupId: Unique identifier for the project group or organization (e.g., org.apache.maven).
  • artifactId: Unique name of the project or artifact (e.g., maven-core).
  • version: Version of the artifact (e.g., 3.9.9); supports range specifications.
  • packaging: Type of artifact (e.g., jar, war, pom; defaults to jar).
  • name: Human-readable project name.
  • description: Short description of the project.
  • url: Project homepage URL.
  • inceptionYear: Year the project started.
  • organization: Details about the owning organization.
  • name: Organization name.
  • url: Organization URL.
  • licenses: List of licenses.
  • license: Individual license.
  • name: License name (e.g., Apache-2.0).
  • url: License text URL.
  • distribution: repo or manual.
  • comments: Additional notes.
  • developers: List of core developers.
  • developer: Individual developer.
  • id: Unique ID.
  • name: Full name.
  • email: Email address.
  • url: Personal URL.
  • organization: Dev's organization.
  • organizationUrl: Org URL.
  • roles: List of roles.
  • timezone: Timezone.
  • properties: Custom key-value pairs.
  • contributors: List of non-core contributors (similar structure to developers).
  • mailingLists: List of mailing lists.
  • mailingList: Individual list.
  • name: List name.
  • subscribe: Subscribe URL/email.
  • unsubscribe: Unsubscribe URL/email.
  • post: Post URL/email.
  • archive: Archive URL.
  • otherArchives: Additional archives.
  • prerequisites: Requirements for building (e.g., Maven version).
  • maven: Minimum Maven version.
  • modules: List of sub-modules for multi-module projects.
  • module: Path to a sub-module.
  • scm: Source Control Management info.
  • connection: Read-only SCM URL.
  • developerConnection: Read-write SCM URL.
  • tag: SCM tag (e.g., HEAD).
  • url: Browse URL.
  • issueManagement: Issue tracker info.
  • system: System name (e.g., Jira).
  • url: Tracker URL.
  • ciManagement: Continuous Integration info.
  • system: CI system (e.g., Jenkins).
  • url: CI URL.
  • notifiers: List of notifiers.
  • notifier: Individual notifier.
  • type: e.g., mail.
  • sendOnError/Success/Warning/Failure: Booleans.
  • address: Email.
  • configuration: Key-value pairs.
  • distributionManagement: Deployment info.
  • repository: Deployment repository.
  • uniqueVersion: Boolean for unique versions.
  • id: Repo ID.
  • name: Repo name.
  • url: Repo URL.
  • layout: default or legacy.
  • snapshotRepository: For snapshots (similar to repository).
  • site: Deployment site.
  • id: Site ID.
  • name: Site name.
  • url: Site URL.
  • downloadUrl: URL for downloads.
  • relocation: For moved artifacts.
  • groupId/artifactId/version/message: New coordinates and message.
  • status: Deployment status (e.g., none, deployed).
  • properties: Custom key-value pairs for interpolation (e.g., java.version=1.8).
  • dependencyManagement: Manages dependency versions/scopes.
  • dependencies: List (see dependencies below).
  • dependencies: List of project dependencies.
  • dependency: Individual dependency.
  • groupId/artifactId/version/type/classifier/scope: Coordinates and details.
  • optional: Boolean.
  • exclusions: List of exclusions.
  • exclusion: groupId/artifactId.
  • repositories: List of repositories for dependencies.
  • repository: Individual repo.
  • releases/snapshots: Policies (enabled, updatePolicy).
  • id/name/url/layout: Details.
  • pluginRepositories: Similar to repositories but for plugins.
  • build: Build configuration.
  • sourceDirectory/testSourceDirectory/scriptSourceDirectory: Directories.
  • outputDirectory/testOutputDirectory/directory: Output dirs.
  • finalName: Artifact name.
  • filters: Property files.
  • resources/testResources: Resource sets.
  • resource: directory/targetPath/filtering/includes/excludes.
  • plugins: List of plugins.
  • plugin: groupId/artifactId/version/extensions/inherited/configuration/dependencies/executions.
  • execution: id/goals/phase/configuration.
  • pluginManagement: Manages plugins (similar).
  • extensions: Build extensions.
  • extension: groupId/artifactId/version.
  • defaultGoal: Default goal.
  • reports: Deprecated; use reporting.
  • reporting: Site generation config.
  • excludeDefaults: Boolean.
  • outputDirectory: Site dir.
  • plugins: Reporting plugins (similar to build plugins).
  • reportSets: id/reports/configuration.
  • profiles: List of profiles for conditional builds.
  • profile: Individual profile.
  • id: Profile ID.
  • activation: Conditions (e.g., by JDK, OS, property, file).
  • build: Profile-specific build (similar to main build).
  • modules/properties/dependencyManagement/etc.: Overrides.

Two direct download links for .POM files (these are example POM files from Maven Central repository, which are valid XML files with .pom extension):

Here is an HTML page with embedded JavaScript that can be embedded in a Ghost blog (or any HTML context). It allows drag-and-drop of a .POM file, parses it as XML, and dumps all the properties (elements and their values, recursively) to the screen in a readable format.

POM File Parser
Drag and drop a .POM file here
  1. Python class for handling .POM files (uses xml.etree.ElementTree for parsing; reads, decodes/parses, prints properties recursively, and can write a new POM with sample properties).
import xml.etree.ElementTree as ET
from xml.dom import minidom

class PomHandler:
    def __init__(self, filepath):
        self.filepath = filepath
        self.tree = None
        self.root = None

    def read(self):
        """Read and parse the .POM file."""
        self.tree = ET.parse(self.filepath)
        self.root = self.tree.getroot()

    def print_properties(self):
        """Print all properties recursively."""
        if not self.root:
            print("No POM loaded. Call read() first.")
            return
        self._print_element(self.root, 0)

    def _print_element(self, element, indent):
        indent_str = '  ' * indent
        print(f"{indent_str}{element.tag}:")
        if element.text and element.text.strip():
            print(f"{indent_str}  {element.text.strip()}")
        for child in element:
            self._print_element(child, indent + 1)

    def write(self, output_path):
        """Write a sample .POM file with basic properties."""
        root = ET.Element('project', {'xmlns': 'http://maven.apache.org/POM/4.0.0',
                                      'xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance',
                                      'xsi:schemaLocation': 'http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd'})
        ET.SubElement(root, 'modelVersion').text = '4.0.0'
        ET.SubElement(root, 'groupId').text = 'com.example'
        ET.SubElement(root, 'artifactId').text = 'example-project'
        ET.SubElement(root, 'version').text = '1.0.0'
        ET.SubElement(root, 'packaging').text = 'jar'
        tree = ET.ElementTree(root)
        xml_str = minidom.parseString(ET.tostring(root)).toprettyxml(indent="  ")
        with open(output_path, 'w') as f:
            f.write(xml_str)
        print(f"Written sample POM to {output_path}")

# Example usage:
# handler = PomHandler('example.pom')
# handler.read()
# handler.print_properties()
# handler.write('new.pom')
  1. Java class for handling .POM files (uses javax.xml.parsers for parsing; reads, parses, prints properties recursively, and can write a new POM).
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Element;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.File;

public class PomHandler {
    private String filepath;
    private Document doc;

    public PomHandler(String filepath) {
        this.filepath = filepath;
    }

    public void read() throws Exception {
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();
        doc = builder.parse(new File(filepath));
        doc.getDocumentElement().normalize();
    }

    public void printProperties() {
        if (doc == null) {
            System.out.println("No POM loaded. Call read() first.");
            return;
        }
        printNode(doc.getDocumentElement(), 0);
    }

    private void printNode(Node node, int indent) {
        String indentStr = "  ".repeat(indent);
        if (node.getNodeType() == Node.ELEMENT_NODE) {
            System.out.println(indentStr + node.getNodeName() + ":");
            if (node.getTextContent() != null && !node.getTextContent().trim().isEmpty()) {
                System.out.println(indentStr + "  " + node.getTextContent().trim());
            }
            NodeList children = node.getChildNodes();
            for (int i = 0; i < children.getLength(); i++) {
                printNode(children.item(i), indent + 1);
            }
        }
    }

    public void write(String outputPath) throws Exception {
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();
        Document newDoc = builder.newDocument();
        Element root = newDoc.createElement("project");
        root.setAttribute("xmlns", "http://maven.apache.org/POM/4.0.0");
        root.setAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
        root.setAttribute("xsi:schemaLocation", "http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd");
        newDoc.appendChild(root);

        Element modelVersion = newDoc.createElement("modelVersion");
        modelVersion.appendChild(newDoc.createTextNode("4.0.0"));
        root.appendChild(modelVersion);

        Element groupId = newDoc.createElement("groupId");
        groupId.appendChild(newDoc.createTextNode("com.example"));
        root.appendChild(groupId);

        Element artifactId = newDoc.createElement("artifactId");
        artifactId.appendChild(newDoc.createTextNode("example-project"));
        root.appendChild(artifactId);

        Element version = newDoc.createElement("version");
        version.appendChild(newDoc.createTextNode("1.0.0"));
        root.appendChild(version);

        Element packaging = newDoc.createElement("packaging");
        packaging.appendChild(newDoc.createTextNode("jar"));
        root.appendChild(packaging);

        TransformerFactory transformerFactory = TransformerFactory.newInstance();
        Transformer transformer = transformerFactory.newTransformer();
        transformer.setOutputProperty("indent", "yes");
        DOMSource source = new DOMSource(newDoc);
        StreamResult result = new StreamResult(new File(outputPath));
        transformer.transform(source, result);
        System.out.println("Written sample POM to " + outputPath);
    }

    // Example usage:
    // public static void main(String[] args) throws Exception {
    //     PomHandler handler = new PomHandler("example.pom");
    //     handler.read();
    //     handler.printProperties();
    //     handler.write("new.pom");
    // }
}
  1. JavaScript class for handling .POM files (uses Node.js fs and xml2js for parsing; assumes npm install xml2js; reads, parses, prints properties recursively, and can write a new POM). For browser, adapt to FileReader as in #3.
const fs = require('fs');
const xml2js = require('xml2js');

class PomHandler {
    constructor(filepath) {
        this.filepath = filepath;
        this.parsed = null;
    }

    read(callback) {
        fs.readFile(this.filepath, 'utf8', (err, data) => {
            if (err) return callback(err);
            const parser = new xml2js.Parser();
            parser.parseString(data, (err, result) => {
                if (err) return callback(err);
                this.parsed = result;
                callback(null);
            });
        });
    }

    printProperties() {
        if (!this.parsed) {
            console.log('No POM loaded. Call read() first.');
            return;
        }
        this._printObject(this.parsed.project, 0);
    }

    _printObject(obj, indent) {
        const indentStr = '  '.repeat(indent);
        for (const key in obj) {
            if (Array.isArray(obj[key])) {
                console.log(`${indentStr}${key}:`);
                obj[key].forEach(item => this._printObject(item, indent + 1));
            } else if (typeof obj[key] === 'object') {
                console.log(`${indentStr}${key}:`);
                this._printObject(obj[key], indent + 1);
            } else {
                console.log(`${indentStr}${key}: ${obj[key]}`);
            }
        }
    }

    write(outputPath, callback) {
        const builder = new xml2js.Builder({ renderOpts: { 'pretty': true, 'indent': '  ', 'newline': '\n' } });
        const xmlObj = {
            project: {
                $: {
                    xmlns: 'http://maven.apache.org/POM/4.0.0',
                    'xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance',
                    'xsi:schemaLocation': 'http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd'
                },
                modelVersion: '4.0.0',
                groupId: 'com.example',
                artifactId: 'example-project',
                version: '1.0.0',
                packaging: 'jar'
            }
        };
        const xml = builder.buildObject(xmlObj);
        fs.writeFile(outputPath, xml, (err) => {
            if (err) return callback(err);
            console.log(`Written sample POM to ${outputPath}`);
            callback(null);
        });
    }
}

// Example usage:
// const handler = new PomHandler('example.pom');
// handler.read((err) => {
//     if (!err) handler.printProperties();
// });
// handler.write('new.pom', (err) => {});
  1. C++ class for handling .POM files (uses TinyXML2 library for parsing; assumes #include <tinyxml2.h>; reads, parses, prints properties recursively, and can write a new POM).
#include <iostream>
#include <tinyxml2.h>
#include <string>

using namespace tinyxml2;

class PomHandler {
private:
    std::string filepath;
    XMLDocument doc;

public:
    PomHandler(const std::string& fp) : filepath(fp) {}

    bool read() {
        if (doc.LoadFile(filepath.c_str()) != XML_SUCCESS) {
            std::cerr << "Error loading POM: " << doc.ErrorStr() << std::endl;
            return false;
        }
        return true;
    }

    void printProperties() {
        XMLElement* root = doc.FirstChildElement("project");
        if (!root) {
            std::cout << "No project element found." << std::endl;
            return;
        }
        printElement(root, 0);
    }

    void printElement(XMLElement* elem, int indent) {
        std::string indentStr(indent * 2, ' ');
        std::cout << indentStr << elem->Name() << ":" << std::endl;
        const char* text = elem->GetText();
        if (text && std::string(text).find_first_not_of(" \t\n\r") != std::string::npos) {
            std::cout << indentStr << "  " << text << std::endl;
        }
        for (XMLElement* child = elem->FirstChildElement(); child; child = child->NextSiblingElement()) {
            printElement(child, indent + 1);
        }
    }

    bool write(const std::string& outputPath) {
        XMLDocument newDoc;
        XMLDeclaration* decl = newDoc.NewDeclaration();
        newDoc.InsertFirstChild(decl);

        XMLElement* root = newDoc.NewElement("project");
        root->SetAttribute("xmlns", "http://maven.apache.org/POM/4.0.0");
        root->SetAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
        root->SetAttribute("xsi:schemaLocation", "http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd");
        newDoc.InsertEndChild(root);

        XMLElement* modelVersion = newDoc.NewElement("modelVersion");
        modelVersion->SetText("4.0.0");
        root->InsertEndChild(modelVersion);

        XMLElement* groupId = newDoc.NewElement("groupId");
        groupId->SetText("com.example");
        root->InsertEndChild(groupId);

        XMLElement* artifactId = newDoc.NewElement("artifactId");
        artifactId->SetText("example-project");
        root->InsertEndChild(artifactId);

        XMLElement* version = newDoc.NewElement("version");
        version->SetText("1.0.0");
        root->InsertEndChild(version);

        XMLElement* packaging = newDoc.NewElement("packaging");
        packaging->SetText("jar");
        root->InsertEndChild(packaging);

        XMLPrinter printer;
        newDoc.Accept(&printer);
        std::string xml = printer.CStr();

        FILE* file = fopen(outputPath.c_str(), "w");
        if (!file) {
            std::cerr << "Error opening output file." << std::endl;
            return false;
        }
        fprintf(file, "%s", xml.c_str());
        fclose(file);
        std::cout << "Written sample POM to " << outputPath << std::endl;
        return true;
    }
};

// Example usage:
// int main() {
//     PomHandler handler("example.pom");
//     if (handler.read()) {
//         handler.printProperties();
//     }
//     handler.write("new.pom");
//     return 0;
// }