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

pkiraly / metadata-qa-marc / #1527

22 Aug 2025 02:21PM UTC coverage: 90.345%. Remained the same
#1527

push

pkiraly
Improve timeline handling

5191 of 6416 new or added lines in 219 files covered. (80.91%)

886 existing lines in 78 files now uncovered.

36717 of 40641 relevant lines covered (90.34%)

0.9 hits per line

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

90.11
/src/main/java/de/gwdg/metadataqa/marc/MarcSubfield.java
1
package de.gwdg.metadataqa.marc;
2

3
import de.gwdg.metadataqa.marc.dao.DataField;
4
import de.gwdg.metadataqa.marc.dao.record.BibliographicRecord;
5
import de.gwdg.metadataqa.marc.definition.general.Linkage;
6
import de.gwdg.metadataqa.marc.definition.general.parser.ParserException;
7
import de.gwdg.metadataqa.marc.definition.structure.SubfieldDefinition;
8
import de.gwdg.metadataqa.marc.utils.keygenerator.DataFieldKeyGenerator;
9

10
import java.io.Serializable;
11
import java.util.ArrayList;
12
import java.util.Collections;
13
import java.util.HashMap;
14
import java.util.List;
15
import java.util.Map;
16
import java.util.logging.Logger;
17

18
public class MarcSubfield implements Serializable { // Validatable
19

20
  private static final Logger logger = Logger.getLogger(MarcSubfield.class.getCanonicalName());
1✔
21
  private static Map<String, String> prefixCache;
22
  private BibliographicRecord marcRecord;
23
  private DataField field;
24
  private SubfieldDefinition definition;
25
  private final String code;
26
  private final String value;
27
  private String codeForIndex = null;
1✔
28
  private Linkage linkage;
29
  private String referencePath;
30

31

32
  public MarcSubfield(SubfieldDefinition definition, String code, String value) {
1✔
33
    this.definition = definition;
1✔
34
    this.code = code;
1✔
35
    this.value = value;
1✔
36
  }
1✔
37

38
  public String getCode() {
39
    return code;
1✔
40
  }
41

42
  public String getValue() {
43
    return value;
1✔
44
  }
45

46
  public DataField getField() {
47
    return field;
1✔
48
  }
49

50
  public void setField(DataField field) {
51
    this.field = field;
1✔
52
  }
1✔
53

54
  public Linkage getLinkage() {
UNCOV
55
    return linkage;
×
56
  }
57

58
  public void setLinkage(Linkage linkage) {
59
    this.linkage = linkage;
1✔
60
  }
1✔
61

62
  public String getReferencePath() {
63
    return referencePath;
1✔
64
  }
65

66
  public void setReferencePath(String referencePath) {
67
    this.referencePath = referencePath;
1✔
68
  }
1✔
69

70
  public String getLabel() {
71
    String label = code;
1✔
72
    if (definition != null && definition.getLabel() != null)
1✔
73
      label = definition.getLabel();
1✔
74
    return label;
1✔
75
  }
76

77
  /**
78
   * Resolve the subfield value.
79
   * @return Either the original value of the subfield or its label.
80
   */
81
  public String resolve() {
82
    if (definition == null)
1✔
83
      return value;
1✔
84

85
    return definition.resolve(value);
1✔
86
  }
87

88
  public List<String> split() {
89
    if (definition == null || !definition.hasContentSplitter())
1✔
NEW
90
      return List.of(value);
×
91

92
    return definition.getContentSplitter().parse(value);
1✔
93
  }
94

95
  public SubfieldDefinition getDefinition() {
96
    return definition;
1✔
97
  }
98

99
  public void setDefinition(SubfieldDefinition definition) {
100
    this.definition = definition;
1✔
101
  }
1✔
102

103
  public BibliographicRecord getMarcRecord() {
104
    return marcRecord;
1✔
105
  }
106

107
  public void setMarcRecord(BibliographicRecord marcRecord) {
108
    this.marcRecord = marcRecord;
1✔
109
  }
1✔
110

111
  /**
112
   * Get the index code for this subfield. If there's no definition, the code is just the subfield code.
113
   * If there's a definition, the code is the index code from the definition.
114
   * E.g. no definition: "a" -> "_a", definition: see SubfieldDefinition.getCodeForIndex()
115
   * @see SubfieldDefinition#getCodeForIndex()
116
   * @return The index code for this subfield.
117
   */
118
  public String getCodeForIndex() {
119
    if (codeForIndex != null) {
1✔
120
      return codeForIndex;
1✔
121
    }
122
    codeForIndex = code;
1✔
123
    if (definition != null && definition.getCodeForIndex() != null) {
1✔
124
      codeForIndex = definition.getCodeForIndex();
1✔
125
    }
126
    return codeForIndex;
1✔
127
  }
128

129
  public Map<String, String> parseContent() {
130
    if (!definition.hasContentParser()) {
1✔
NEW
131
      return Collections.emptyMap();
×
132
    }
133

134
    try {
135
      return definition.getContentParser().parse(value);
1✔
NEW
136
    } catch (ParserException e) {
×
NEW
137
      var msg = String.format(
×
138
        "Error in record: '%s' %s$%s: '%s'. Error message: '%s'",
NEW
139
        marcRecord.getId(), field.getTag(), definition.getCode(), value, e.getMessage()
×
140
      );
NEW
141
      logger.severe(msg);
×
142
    }
143

NEW
144
    return Collections.emptyMap();
×
145
  }
146

147
  public Map<String, List<String>> getKeyValuePairs(DataFieldKeyGenerator keyGenerator) {
148
    if (prefixCache == null) {
1✔
149
      prefixCache = new HashMap<>();
1✔
150
    }
151

152
    String tagForCache = this.getField().getTag();
1✔
153
    if (this.getField().getOccurrence() != null) {
1✔
154
      tagForCache += "/" + this.getField().getOccurrence();
1✔
155
    }
156

157
    String cacheKey = String.format(
1✔
158
      "%s$%s-%s-%s",
159
      tagForCache, code, keyGenerator.getClass().getSimpleName(), keyGenerator.getMarcVersion());
1✔
160
    if (!prefixCache.containsKey(cacheKey)) {
1✔
161
      String generatedPrefix = keyGenerator.forSubfield(this);
1✔
162
      prefixCache.put(cacheKey, generatedPrefix);
1✔
163
    }
164
    String prefix = prefixCache.get(cacheKey);
1✔
165

166
    Map<String, List<String>> pairs = new HashMap<>();
1✔
167
    if (definition != null && definition.hasContentSplitter()) {
1✔
168
      List<String> items = new ArrayList<>();
1✔
169
      for (String item : split())
1✔
170
        items.add(definition.resolve(item));
1✔
171

172
      pairs.put(prefix, items);
1✔
173
    } else
1✔
174
      pairs.put(prefix, new ArrayList<>(List.of(resolve())));
1✔
175

176
    if (getDefinition() == null) {
1✔
177
      return pairs;
1✔
178
    }
179

180
    getKeyValuePairsForPositionalSubfields(pairs, prefix);
1✔
181
    getKeyValuePairsFromContentParser(keyGenerator, pairs);
1✔
182
    return pairs;
1✔
183
  }
184

185
  private void getKeyValuePairsFromContentParser(DataFieldKeyGenerator keyGenerator,
186
                                                 Map<String,
187
                                                 List<String>> pairs) {
188
    if (!getDefinition().hasContentParser()) {
1✔
189
      return;
1✔
190
    }
191

192
    Map<String, String> extra = parseContent();
1✔
193
    if (extra == null) {
1✔
NEW
194
      return;
×
195
    }
196

197
    for (Map.Entry<String, String> entry : extra.entrySet()) {
1✔
198
      pairs.put(
1✔
199
        String.format("%s_%s", keyGenerator.forSubfield(this), entry.getKey()),
1✔
200
        new ArrayList<>(List.of(entry.getValue()))
1✔
201
      );
202
    }
1✔
203
  }
1✔
204

205
  private void getKeyValuePairsForPositionalSubfields(Map<String, List<String>> pairs, String prefix) {
206
    if (!getDefinition().hasPositions()) {
1✔
207
      return;
1✔
208
    }
209

210
    Map<String, String> extra = getDefinition().resolvePositional(getValue());
1✔
211
    for (Map.Entry<String, String> entry : extra.entrySet()) {
1✔
212
      pairs.put(prefix + "_" + entry.getKey(), new ArrayList<>(List.of(entry.getValue())));
1✔
213
    }
1✔
214
  }
1✔
215

216
  @Override
217
  public String toString() {
218
    return "MarcSubfield{" +
1✔
219
            "code='" + code + '\'' +
220
            ", value='" + value + '\'' +
221
            '}';
222
  }
223
}
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

© 2026 Coveralls, Inc