Include filename of corrupt file in store exception

This commit is contained in:
Rene Pfeuffer
2026-01-26 15:51:32 +00:00
committed by Thomas Zerr
parent a378ad97e3
commit e98a6ff093
4 changed files with 105 additions and 87 deletions

View File

@@ -0,0 +1,2 @@
- type: fixed
description: Enhanced error message including filename of corrupt file

View File

@@ -123,92 +123,99 @@ class JAXBConfigurationEntryStore<V> implements ConfigurationEntryStore<V> {
private void load() {
LOG.debug("load configuration from {}", file);
execute(() ->
context.withUnmarshaller(u -> {
try (AutoCloseableXMLReader reader = XmlStreams.createReader(file)) {
context.withUnmarshaller(
u -> {
try (AutoCloseableXMLReader reader = XmlStreams.createReader(file)) {
// configuration
reader.nextTag();
// entry start
reader.nextTag();
while (reader.isStartElement() && reader.getLocalName().equals(TAG_ENTRY)) {
// read key
// configuration
reader.nextTag();
String key = reader.getElementText();
// read value
// entry start
reader.nextTag();
JAXBElement<V> element = u.unmarshal(reader, type);
while (reader.isStartElement() && reader.getLocalName().equals(TAG_ENTRY)) {
if (!element.isNil()) {
V v = element.getValue();
LOG.trace("add element {} to configuration entry store", v);
entries.put(key, v);
} else {
LOG.warn("could not unmarshall object of entry store");
}
// closed or new entry tag
if (reader.nextTag() == END_ELEMENT) {
// fixed format, start new entry
// read key
reader.nextTag();
String key = reader.getElementText();
// read value
reader.nextTag();
JAXBElement<V> element = u.unmarshal(reader, type);
if (!element.isNil()) {
V v = element.getValue();
LOG.trace("add element {} to configuration entry store", v);
entries.put(key, v);
} else {
LOG.warn("could not unmarshall object of entry store");
}
// closed or new entry tag
if (reader.nextTag() == END_ELEMENT) {
// fixed format, start new entry
reader.nextTag();
}
}
}
}
})).withLockedFileForRead(file);
},
file.getAbsoluteFile()
)
).withLockedFileForRead(file);
}
private void store() {
LOG.debug("store configuration to {}", file);
context.withMarshaller(m -> {
m.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);
context.withMarshaller(
m -> {
m.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);
CopyOnWrite.withTemporaryFile(
temp -> {
try (AutoCloseableXMLWriter writer = XmlStreams.createWriter(temp)) {
writer.writeStartDocument();
CopyOnWrite.withTemporaryFile(
temp -> {
try (AutoCloseableXMLWriter writer = XmlStreams.createWriter(temp)) {
writer.writeStartDocument();
// configuration start
writer.writeStartElement(TAG_CONFIGURATION);
writer.writeAttribute("type", "config-entry");
// configuration start
writer.writeStartElement(TAG_CONFIGURATION);
writer.writeAttribute("type", "config-entry");
for (Entry<String, V> e : entries.entrySet()) {
for (Entry<String, V> e : entries.entrySet()) {
// entry start
writer.writeStartElement(TAG_ENTRY);
// entry start
writer.writeStartElement(TAG_ENTRY);
// key start
writer.writeStartElement(TAG_KEY);
writer.writeCharacters(e.getKey());
// key start
writer.writeStartElement(TAG_KEY);
writer.writeCharacters(e.getKey());
// key end
writer.writeEndElement();
// value
JAXBElement<V> je = new JAXBElement<>(QName.valueOf(TAG_VALUE), type,
e.getValue());
m.marshal(je, writer);
// entry end
// key end
writer.writeEndElement();
// value
JAXBElement<V> je = new JAXBElement<>(QName.valueOf(TAG_VALUE), type,
e.getValue());
m.marshal(je, writer);
// entry end
writer.writeEndElement();
}
// configuration end
writer.writeEndElement();
writer.writeEndDocument();
}
// configuration end
writer.writeEndElement();
writer.writeEndDocument();
}
},
file.toPath()
);
});
},
file.toPath()
);
},
file.getAbsoluteFile()
);
}
}

View File

@@ -64,33 +64,35 @@ final class TypedStoreContext<T> {
T unmarshal(File file) {
log.trace("unmarshal file {}", file);
AtomicReference<T> ref = new AtomicReference<>();
withUnmarshaller(unmarshaller -> {
T value = parameters.getType().cast(unmarshaller.unmarshal(file));
ref.set(value);
});
withUnmarshaller(
unmarshaller -> {
T value = parameters.getType().cast(unmarshaller.unmarshal(file));
ref.set(value);
},
file.getAbsoluteFile());
return ref.get();
}
void marshal(Object object, File file) {
log.trace("marshal file {}", file);
withMarshaller(marshaller -> marshaller.marshal(object, XmlStreams.createWriter(file)));
withMarshaller(marshaller -> marshaller.marshal(object, XmlStreams.createWriter(file)), file.getAbsoluteFile());
}
void withMarshaller(ThrowingConsumer<Marshaller> consumer) {
void withMarshaller(ThrowingConsumer<Marshaller> consumer, Object context) {
Marshaller marshaller = createMarshaller();
withClassLoader(consumer, marshaller);
withClassLoader(consumer, marshaller, context);
}
void withUnmarshaller(ThrowingConsumer<Unmarshaller> consumer) {
void withUnmarshaller(ThrowingConsumer<Unmarshaller> consumer, Object context) {
Unmarshaller unmarshaller = createUnmarshaller();
withClassLoader(consumer, unmarshaller);
withClassLoader(consumer, unmarshaller, context);
}
Class<T> getType() {
return parameters.getType();
}
private <C> void withClassLoader(ThrowingConsumer<C> consumer, C consume) {
private <C> void withClassLoader(ThrowingConsumer<C> consumer, C consume, Object context) {
ClassLoader contextClassLoader = null;
Optional<ClassLoader> classLoader = parameters.getClassLoader();
if (classLoader.isPresent()) {
@@ -100,7 +102,7 @@ final class TypedStoreContext<T> {
try {
consumer.consume(consume);
} catch (Exception e) {
throw new StoreException("failure during marshalling/unmarshalling", e);
throw new StoreException("failure during marshalling/unmarshalling '" + context + "'", e);
} finally {
if (contextClassLoader != null) {
Thread.currentThread().setContextClassLoader(contextClassLoader);
@@ -135,7 +137,8 @@ final class TypedStoreContext<T> {
@FunctionalInterface
interface ThrowingConsumer<T> {
@SuppressWarnings("java:S112") // we need to throw Exception here
@SuppressWarnings("java:S112")
// we need to throw Exception here
void consume(T item) throws Exception;
}

View File

@@ -59,16 +59,19 @@ class TypedStoreContextTest {
File file = tempDir.resolve("test.xml").toFile();
context.withMarshaller(marshaller -> {
marshaller.marshal(new Sample("wow"), file);
});
context.withMarshaller(
marshaller -> {
marshaller.marshal(new Sample("wow"), file);
},
file);
AtomicReference<Sample> ref = new AtomicReference<>();
context.withUnmarshaller(unmarshaller -> {
Sample sample = (Sample) unmarshaller.unmarshal(file);
ref.set(sample);
});
context.withUnmarshaller(
unmarshaller -> {
Sample sample = (Sample) unmarshaller.unmarshal(file);
ref.set(sample);
}, file);
assertThat(ref.get().value).isEqualTo("wow");
}
@@ -85,9 +88,12 @@ class TypedStoreContextTest {
TypedStoreContext<Sample> context = TypedStoreContext.of(params);
AtomicReference<ClassLoader> ref = new AtomicReference<>();
context.withMarshaller(marshaller -> {
ref.set(Thread.currentThread().getContextClassLoader());
});
context.withMarshaller(
marshaller -> {
ref.set(Thread.currentThread().getContextClassLoader());
},
"nothing"
);
assertThat(ref.get()).isSameAs(classLoader);
assertThat(Thread.currentThread().getContextClassLoader()).isSameAs(contextClassLoader);