mirror of
https://github.com/jenkinsci/jenkins.git
synced 2026-11-11 11:06:25 +00:00
[JENKINS-45892] Merged #2957: prevent model objects from being serialized except at top level.
This commit is contained in:
commit
14028ec75b
8 files changed
+265
-3
No files matched your search
@@ -50,8 +50,13 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Reader;
|
||||
import java.io.Serializable;
|
||||
import java.io.Writer;
|
||||
import java.io.StringWriter;
|
||||
import java.util.Collections;
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
@@ -114,6 +119,7 @@ import org.apache.commons.io.IOUtils;
|
||||
public final class XmlFile {
|
||||
private final XStream xs;
|
||||
private final File file;
|
||||
private static final Map<Object, Void> beingWritten = Collections.synchronizedMap(new IdentityHashMap<>());
|
||||
|
||||
public XmlFile(File file) {
|
||||
this(DEFAULT_XSTREAM,file);
|
||||
@@ -168,7 +174,12 @@ public final class XmlFile {
|
||||
AtomicFileWriter w = new AtomicFileWriter(file);
|
||||
try {
|
||||
w.write("<?xml version='1.0' encoding='UTF-8'?>\n");
|
||||
xs.toXML(o,w);
|
||||
beingWritten.put(o, null);
|
||||
try {
|
||||
xs.toXML(o, w);
|
||||
} finally {
|
||||
beingWritten.remove(o);
|
||||
}
|
||||
w.commit();
|
||||
} catch(StreamException e) {
|
||||
throw new IOException(e);
|
||||
@@ -177,6 +188,27 @@ public final class XmlFile {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides an XStream replacement for an object unless a call to {@link #write} is currently in progress.
|
||||
* As per JENKINS-45892 this may be used by any class which expects to be written at top level to an XML file
|
||||
* but which cannot safely be serialized as a nested object (for example, because it expects some {@code onLoad} hook):
|
||||
* implement a {@code writeReplace} method delegating to this method.
|
||||
* The replacement need not be {@link Serializable} since it is only necessary for use from XStream.
|
||||
* @param o an object ({@code this} from {@code writeReplace})
|
||||
* @param replacement a supplier of a safely serializable replacement object with a {@code readResolve} method
|
||||
* @return {@code o}, if {@link #write} is being called on it, else the replacement
|
||||
* @since 2.74
|
||||
*/
|
||||
public static Object replaceIfNotAtTopLevel(Object o, Supplier<Object> replacement) {
|
||||
if (beingWritten.containsKey(o)) {
|
||||
return o;
|
||||
} else {
|
||||
// Unfortunately we cannot easily tell which XML file is actually being saved here, at least without implementing a custom Converter.
|
||||
LOGGER.log(Level.WARNING, "JENKINS-45892: reference to {0} being saved but not at top level", o);
|
||||
return replacement.get();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean exists() {
|
||||
return file.exists();
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user