OpenpackagingFactory.java

1
package pro.verron.officestamper.utils.openpackaging;
2
3
import org.docx4j.openpackaging.contenttype.ContentTypeManager;
4
import org.docx4j.openpackaging.contenttype.ContentTypes;
5
import org.docx4j.openpackaging.exceptions.InvalidFormatException;
6
import org.docx4j.openpackaging.exceptions.PartUnrecognisedException;
7
import org.docx4j.openpackaging.packages.OpcPackage;
8
import org.docx4j.openpackaging.parts.Part;
9
import org.docx4j.openpackaging.parts.PartName;
10
import org.docx4j.openpackaging.parts.WordprocessingML.BinaryPartAbstractImage;
11
import org.docx4j.openpackaging.parts.relationships.RelationshipsPart;
12
import org.docx4j.relationships.Relationship;
13
import pro.verron.officestamper.utils.UtilsException;
14
import pro.verron.officestamper.utils.image.ImgPart;
15
import pro.verron.officestamper.utils.svg.SvgUtils;
16
17
import java.io.ByteArrayInputStream;
18
19
import static org.docx4j.openpackaging.parts.WordprocessingML.BinaryPartAbstractImage.createImageName;
20
import static pro.verron.officestamper.utils.image.ImgUtils.detectFormat;
21
import static pro.verron.officestamper.utils.image.ImgUtils.supportedContentType;
22
import static pro.verron.officestamper.utils.openpackaging.OpenpackagingUtils.*;
23
24
/// Utility class for creating Open Packaging objects.
25
///
26
/// This class provides helper methods to create instances of docx4j Open Packaging objects, wrapping checked exceptions
27
/// in runtime [UtilsException] for easier handling.
28
public class OpenpackagingFactory {
29
30
    private OpenpackagingFactory() {
31
        throw new UtilsException("Utility class shouldn't be instantiated");
32
    }
33
34
    /// Creates a new PartName instance from the given string representation.
35
    ///
36
    /// This method wraps the checked [InvalidFormatException] that can occur when creating a PartName in a runtime
37
    /// [UtilsException].
38
    ///
39
    /// @param partName the string representation of the part name
40
    ///
41
    /// @return a new PartName instance
42
    ///
43
    /// @throws UtilsException if the part name string is invalid
44
    public static PartName newPartName(String partName) {
45
        try {
46 1 1. newPartName : replaced return value with null for pro/verron/officestamper/utils/openpackaging/OpenpackagingFactory::newPartName → NO_COVERAGE
            return new PartName(partName);
47
        } catch (InvalidFormatException e) {
48
            throw new UtilsException(e);
49
        }
50
    }
51
52
    /// Creates a new [ImgPart] instance from the given [OpcPackage], source part, and image byte array.
53
    /// This method detects the image format, validates its compatibility, and establishes
54
    /// the necessary relationships within the package.
55
    ///
56
    /// @param opcPackage the [OpcPackage] to which this image part belongs
57
    /// @param sourcePart the source [Part] where the relationship to the image part will be created
58
    /// @param bytes the byte array containing image data
59
    /// @return a new [ImgPart] containing the detected image format and its relationship
60
    /// @throws UtilsException if byte array is empty, format cannot be detected, or image type is unsupported
61
    public static ImgPart newImgPart(OpcPackage opcPackage, Part sourcePart, byte[] bytes) {
62 1 1. newImgPart : negated conditional → NO_COVERAGE
        if (bytes.length == 0) throw new UtilsException("Can't create image from empty byte array");
63
64
        var optFormat = detectFormat(bytes);
65 1 1. lambda$newImgPart$0 : replaced return value with null for pro/verron/officestamper/utils/openpackaging/OpenpackagingFactory::lambda$newImgPart$0 → NO_COVERAGE
        var format = optFormat.orElseThrow(() -> new UtilsException("Could not detect a supported image type."));
66
67
        var optMimeType = supportedContentType(format.name());
68 1 1. lambda$newImgPart$1 : replaced return value with null for pro/verron/officestamper/utils/openpackaging/OpenpackagingFactory::lambda$newImgPart$1 → NO_COVERAGE
        var mimeType = optMimeType.orElseThrow(() -> new UtilsException("Unsupported image type"));
69
70 1 1. newImgPart : removed call to pro/verron/officestamper/utils/openpackaging/OpenpackagingUtils::ensureHasRelationshipPart → NO_COVERAGE
        ensureHasRelationshipPart(sourcePart);
71
        var relationshipId = createRelationshipId(sourcePart);
72
        var partName = createImageName(opcPackage, sourcePart, relationshipId, format.name());
73
        var ctm = opcPackage.getContentTypeManager();
74
75
        Part imgPart;
76 1 1. newImgPart : negated conditional → NO_COVERAGE
        if (mimeType.equals(ContentTypes.IMAGE_SVG)) {
77
            var document = SvgUtils.parseDocument(bytes);
78
            imgPart = createSvgPart(document, ctm, partName);
79
        }
80
        else imgPart = createImagePart(bytes, ctm, mimeType, partName);
81
        var relationship = setupRelationship(sourcePart, imgPart, relationshipId);
82 1 1. newImgPart : replaced return value with null for pro/verron/officestamper/utils/openpackaging/OpenpackagingFactory::newImgPart → NO_COVERAGE
        return new ImgPart(format, relationship);
83
    }
84
85
    private static Part createImagePart(byte[] bytes, ContentTypeManager ctm, String mimeType, String partName) {
86
        try {
87
            var imagePart = (BinaryPartAbstractImage) ctm.newPartForContentType(mimeType, partName, null);
88 1 1. createImagePart : removed call to org/docx4j/openpackaging/parts/WordprocessingML/BinaryPartAbstractImage::setBinaryData → NO_COVERAGE
            imagePart.setBinaryData(new ByteArrayInputStream(bytes));
89 1 1. createImagePart : replaced return value with null for pro/verron/officestamper/utils/openpackaging/OpenpackagingFactory::createImagePart → NO_COVERAGE
            return imagePart;
90
        } catch (InvalidFormatException | PartUnrecognisedException e) {
91
            throw new UtilsException(e);
92
        }
93
    }
94
95
    /// Establishes a relationship between a source part and a target part using the specified relationship ID.
96
    ///
97
    /// @param sourcePart the source part from which the relationship originates
98
    /// @param targetPart the target part to which the relationship points
99
    /// @param relationshipId the unique identifier for the relationship
100
    /// @return the created relationship between the source and target parts
101
    /// @throws UtilsException if an error occurs while creating the relationship
102
    public static Relationship setupRelationship(Part sourcePart, Part targetPart, String relationshipId) {
103
        try {
104
            var reuseExisting = RelationshipsPart.AddPartBehaviour.REUSE_EXISTING;
105 1 1. setupRelationship : replaced return value with null for pro/verron/officestamper/utils/openpackaging/OpenpackagingFactory::setupRelationship → NO_COVERAGE
            return sourcePart.addTargetPart(targetPart, reuseExisting, relationshipId);
106
        } catch (InvalidFormatException e) {
107
            throw new UtilsException(e);
108
        }
109
    }
110
}

Mutations

46

1.1
Location : newPartName
Killed by : none
replaced return value with null for pro/verron/officestamper/utils/openpackaging/OpenpackagingFactory::newPartName → NO_COVERAGE

62

1.1
Location : newImgPart
Killed by : none
negated conditional → NO_COVERAGE

65

1.1
Location : lambda$newImgPart$0
Killed by : none
replaced return value with null for pro/verron/officestamper/utils/openpackaging/OpenpackagingFactory::lambda$newImgPart$0 → NO_COVERAGE

68

1.1
Location : lambda$newImgPart$1
Killed by : none
replaced return value with null for pro/verron/officestamper/utils/openpackaging/OpenpackagingFactory::lambda$newImgPart$1 → NO_COVERAGE

70

1.1
Location : newImgPart
Killed by : none
removed call to pro/verron/officestamper/utils/openpackaging/OpenpackagingUtils::ensureHasRelationshipPart → NO_COVERAGE

76

1.1
Location : newImgPart
Killed by : none
negated conditional → NO_COVERAGE

82

1.1
Location : newImgPart
Killed by : none
replaced return value with null for pro/verron/officestamper/utils/openpackaging/OpenpackagingFactory::newImgPart → NO_COVERAGE

88

1.1
Location : createImagePart
Killed by : none
removed call to org/docx4j/openpackaging/parts/WordprocessingML/BinaryPartAbstractImage::setBinaryData → NO_COVERAGE

89

1.1
Location : createImagePart
Killed by : none
replaced return value with null for pro/verron/officestamper/utils/openpackaging/OpenpackagingFactory::createImagePart → NO_COVERAGE

105

1.1
Location : setupRelationship
Killed by : none
replaced return value with null for pro/verron/officestamper/utils/openpackaging/OpenpackagingFactory::setupRelationship → NO_COVERAGE

Active mutators

Tests examined


Report generated by PIT 1.23.1 support