• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

ljacqu / FileDuplicateFinder / 14006930974

22 Mar 2025 08:35AM UTC coverage: 23.055%. Remained the same
14006930974

push

github

ljacqu
Add Nullable annotation next to return value in methods

111 of 610 branches covered (18.2%)

Branch coverage included in aggregate %.

378 of 1511 relevant lines covered (25.02%)

1.28 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/main/java/ch/jalu/fileduplicatefinder/config/PropertyFileResource.java
1
package ch.jalu.fileduplicatefinder.config;
2

3
import ch.jalu.configme.configurationdata.ConfigurationData;
4
import ch.jalu.configme.properties.Property;
5
import ch.jalu.configme.resource.PropertyReader;
6
import ch.jalu.configme.resource.PropertyResource;
7
import com.google.common.primitives.Doubles;
8
import com.google.common.primitives.Ints;
9
import org.jetbrains.annotations.Nullable;
10

11
import java.io.IOException;
12
import java.io.InputStream;
13
import java.io.OutputStream;
14
import java.io.OutputStreamWriter;
15
import java.io.UncheckedIOException;
16
import java.nio.charset.StandardCharsets;
17
import java.nio.file.Files;
18
import java.nio.file.Path;
19
import java.util.List;
20
import java.util.Objects;
21
import java.util.Properties;
22
import java.util.Set;
23

24
/**
25
 * Property resource implementation for {@code .properties} files. Note that certain features are not supported
26
 * by the {@link PropertyFileReader resource reader}.
27
 */
28
public class PropertyFileResource implements PropertyResource {
29

30
    private final Path configFile;
31

32
    PropertyFileResource(Path configFile) {
×
33
        this.configFile = configFile;
×
34
    }
×
35

36
    @Override
37
    public PropertyReader createReader() {
38
        return new PropertyFileReader(configFile);
×
39
    }
40

41
    /**
42
     * {@inheritDoc}
43
     *
44
     * @implNote
45
     *   Comments on intermediate paths (like {@code com.acme} for a property {@code com.acme.filter}) is not
46
     *   picked up by this resource implementation. Only comments on properties and their top-level parents
47
     *   (like {@code com}) will be considered by this class when writing.
48
     *
49
     * @param configurationData the configuration data to export
50
     */
51
    @Override
52
    public void exportProperties(ConfigurationData configurationData) {
53
        try (OutputStream os = Files.newOutputStream(configFile);
×
54
             OutputStreamWriter writer = new OutputStreamWriter(os, StandardCharsets.UTF_8)) {
×
55
            writeComments(writer, "", configurationData, true);
×
56
            String lastParent = "";
×
57

58
            for (Property<?> property : configurationData.getProperties()) {
×
59
                String export = getExportValue(property, configurationData);
×
60
                if (export == null) {
×
61
                    continue;
×
62
                }
63

64
                String parentElem = extractParentElement(property.getPath());
×
65

66
                if (!Objects.equals(lastParent, parentElem) && !property.getPath().equals(parentElem)) {
×
67
                    if (!lastParent.isEmpty()) {
×
68
                        writer.append('\n');
×
69
                    }
70
                    writeComments(writer, parentElem, configurationData, true);
×
71
                }
72

73
                writeComments(writer, property.getPath(), configurationData, false);
×
74
                writer.append('\n').append(property.getPath()).append("=").append(export);
×
75
                lastParent = parentElem;
×
76
            }
×
77

78
            writer.flush();
×
79
        } catch (IOException e) {
×
80
            throw new UncheckedIOException("Could not write to config file", e);
×
81
        }
×
82
    }
×
83

84
    private static void writeComments(OutputStreamWriter writer, String path, ConfigurationData configurationData,
85
                                      boolean newLineAfterComments) throws IOException {
86
        boolean wroteText = false;
×
87
        for (String comment : configurationData.getCommentsForSection(path)) {
×
88
            if (comment.isEmpty()) {
×
89
                writer.append('\n');
×
90
            } else {
91
                writer.append("\n# ").append(comment);
×
92
                wroteText = true;
×
93
            }
94
        }
×
95
        if (newLineAfterComments && wroteText) {
×
96
            writer.append('\n');
×
97
        }
98
    }
×
99

100
    private <T> @Nullable String getExportValue(Property<T> property, ConfigurationData configurationData) {
101
        Object exportValue = property.toExportValue(configurationData.getValue(property));
×
102
        if (exportValue == null) {
×
103
            return null;
×
104
        }
105

106
        return exportValue.toString()
×
107
            .replace("\\", "\\\\")
×
108
            .replace("\n", "\\n")
×
109
            .replace("\r", "\\r")
×
110
            .replace("\t", "\\t");
×
111
    }
112

113
    private String extractParentElement(String path) {
114
        int dotIndex = path.indexOf('.');
×
115
        if (dotIndex > 0) {
×
116
            return path.substring(0, dotIndex);
×
117
        }
118
        return path;
×
119
    }
120

121
    public static final class PropertyFileReader implements PropertyReader {
122

123
        private final Properties properties;
124

125
        public PropertyFileReader(Path configFile) {
×
126
            Properties properties = new Properties();
×
127
            try (InputStream is = Files.newInputStream(configFile)) {
×
128
                properties.load(is);
×
129
            } catch (IOException e) {
×
130
                throw new UncheckedIOException(e);
×
131
            }
×
132
            this.properties = properties;
×
133
        }
×
134

135
        @Override
136
        public boolean contains(String path) {
137
            // Note that intermediate paths will return false, unlike the behavior in the YAML resource reader
138
            return properties.containsKey(path);
×
139
        }
140

141
        @Override
142
        public @Nullable Object getObject(String path) {
143
            return getString(path);
×
144
        }
145

146
        @Override
147
        public @Nullable String getString(String path) {
148
            return properties.getProperty(path);
×
149
        }
150

151
        @Override
152
        public @Nullable Integer getInt(String path) {
153
            String str = getString(path);
×
154
            return str == null ? null : Ints.tryParse(str);
×
155
        }
156

157
        @Override
158
        public @Nullable Double getDouble(String path) {
159
            String str = getString(path);
×
160
            return str == null ? null : Doubles.tryParse(str);
×
161
        }
162

163
        @Override
164
        public @Nullable Boolean getBoolean(String path) {
165
            String str = getString(path);
×
166
            return ("true".equals(str) || "false".equals(str))
×
167
                ? Boolean.valueOf(str)
×
168
                : null;
×
169
        }
170

171
        @Override
172
        public @Nullable List<?> getList(String path) {
173
            throw new UnsupportedOperationException("Not supported by .properties");
×
174
        }
175

176
        @Override
177
        public Set<String> getKeys(boolean onlyLeafNodes) {
178
            throw new UnsupportedOperationException();
×
179
        }
180

181
        @Override
182
        public Set<String> getChildKeys(String path) {
183
            throw new UnsupportedOperationException();
×
184
        }
185
    }
186
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc