XmlReport.java
package com.reallifedeveloper.maven.jdepend.xml;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import jakarta.xml.bind.annotation.XmlAccessType;
import jakarta.xml.bind.annotation.XmlAccessorType;
import jakarta.xml.bind.annotation.XmlAttribute;
import jakarta.xml.bind.annotation.XmlElement;
import jakarta.xml.bind.annotation.XmlElementWrapper;
import jakarta.xml.bind.annotation.XmlRootElement;
import jakarta.xml.bind.annotation.XmlValue;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* A representation of the XML report generated by JDepend.
*
* @author RealLifeDeveloper
*/
@XmlRootElement(name = "JDepend")
@XmlAccessorType(XmlAccessType.FIELD)
@Data
@Accessors(fluent = true)
@SuppressWarnings("PMD.AvoidDuplicateLiterals")
@SuppressFBWarnings(value = "EI_EXPOSE_REP", justification = "The classes here are mutable for convenience; we can simply use lombok.Data")
public class XmlReport {
@XmlElementWrapper(name = "Packages")
@XmlElement(name = "Package")
private List<XmlPackage> packages = new ArrayList<>();
@XmlElementWrapper(name = "Cycles")
@XmlElement(name = "Package")
private List<XmlPackageWithCycle> cycles = new ArrayList<>();
/**
* Gives the packages that were successfully analyzed by JDepend.
* <p>
* The XML report generataed by JDepend includes external packages, e.g., {@code java.lang}, but with an error message saying something
* like {@code package referenced, but not analyzed}.
*
* @return the packages that were successfully analyzed by JDepend
*/
public List<XmlPackage> packagesWithoutError() {
return packages().stream().filter(p -> p.error() == null).toList();
}
/**
* Gives the packages that were included in the JDepend report, but not successfully analyzed.
*
* @return the packages that were included in the JDepend report, but not successfully analyzed
*/
public List<XmlPackage> packagesWithError() {
return packages().stream().filter(p -> p.error() != null).toList();
}
/**
* If the given package has any cycles, provides information about this.
*
* @param packageName the name of the package to check
*
* @return an optional containing an {@link XmlPackageWithCycle} if the package named {@code packageName} contains cycles, an empty
* optional otherwise
*/
public Optional<XmlPackageWithCycle> findPackageWithCycle(String packageName) {
return cycles().stream().filter(c -> packageName.equals(c.name())).findFirst();
}
/**
* Contains information from the {@code Package} element.
*/
@Data
public static class XmlPackage {
@XmlAttribute(name = "name")
private String name;
@XmlElement(name = "Stats")
private XmlStats stats;
@XmlElementWrapper(name = "AbstractClasses")
@XmlElement(name = "Class")
private List<XmlClass> abstractClasses = new ArrayList<>();
@XmlElementWrapper(name = "ConcreteClasses")
@XmlElement(name = "Class")
private List<XmlClass> concreteClasses = new ArrayList<>();
@XmlElementWrapper(name = "DependsUpon")
@XmlElement(name = "Package")
private List<String> dependsUpon = new ArrayList<>();
@XmlElementWrapper(name = "UsedBy")
@XmlElement(name = "Package")
private List<String> usedBy = new ArrayList<>();
@XmlElement(name = "error")
private String error;
}
/**
* Contains information from the {@code Stats} element.
*/
@Data
public static class XmlStats {
@XmlElement(name = "TotalClasses")
private int totalClasses;
@XmlElement(name = "ConcreteClasses")
private int concreteClasses;
@XmlElement(name = "AbstractClasses")
private int abstractClasses;
@XmlElement(name = "HasPackageInfo")
private boolean hasPackageInfo;
@XmlElement(name = "Ca")
private int afferentCouplings;
@XmlElement(name = "Ce")
private int efferentCouplings;
@XmlElement(name = "A")
private double abstractness;
@XmlElement(name = "I")
private double instability;
@XmlElement(name = "D")
private double distance;
@XmlElement(name = "V")
private int volatility;
}
/**
* Contains information from the {@code Class} element.
*/
@Data
public static class XmlClass {
@XmlAttribute(name = "sourceFile")
private String sourceFile;
@XmlValue
private String name;
}
/**
* Contains information from the {@code Cycles} element.
*/
@Data
public static class XmlPackageWithCycle {
@XmlAttribute(name = "Name")
private String name;
@XmlElement(name = "Package")
private List<String> packagesInCycle = new ArrayList<>();
}
}