Class XmlFile
Evolving data format
Changing data format requires a particular care so that users with the old data format can migrate to the newer data format smoothly.
Adding a field is the easiest. When you read an old XML that does
not have any data, the newly added field is left to the VM-default
value (if you let XStream create the object, such as
read()
— which is the majority), or to the value initialized by the
constructor (if the object is created via new
and then its
value filled by XStream, such as unmarshal(Object)
.)
Removing a field requires that you actually leave the field with
transient
keyword. When you read the old XML, XStream
will set the value to this field. But when the data is saved,
the field will no longer will be written back to XML.
(It might be possible to tweak XStream so that we can simply
remove fields from the class. Any help appreciated.)
Changing the data structure is usually a combination of the two
above. You'd leave the old data store with transient
,
and then add the new data. When you are reading the old XML,
only the old field will be set. When you are reading the new XML,
only the new field will be set. You'll then need to alter the code
so that it will be able to correctly handle both situations,
and that as soon as you see data in the old field, you'll have to convert
that into the new data structure, so that the next save
operation
will write the new data (otherwise you'll end up losing the data, because
old fields will be never written back.)
You may also want to call OldDataMonitor.report(UnmarshallingContext, String)
.
This can be done within a nested class ConverterImpl
extending XStream2.PassthruConverter
in an override of XStream2.PassthruConverter.callback(T, com.thoughtworks.xstream.converters.UnmarshallingContext)
.
In some limited cases (specifically when the class is the root object
to be read from XML, such as Descriptor
), it is possible
to completely and drastically change the data format. See
Descriptor.load()
for more about this technique.
There's a few other possibilities, such as implementing a custom
Converter
for XStream, or registering an alias
.
- Author:
- Kohsuke Kawaguchi
- See Also:
-
Constructor Summary
-
Method Summary
Modifier and TypeMethodDescriptionasString()
Returns the XML file read as a string.void
delete()
boolean
exists()
getFile()
com.thoughtworks.xstream.XStream
void
mkdirs()
read()
Loads the contents of this file into a new object.readRaw()
Opens aReader
that loads XML.static Object
replaceIfNotAtTopLevel
(Object o, Supplier<Object> replacement) Provides an XStream replacement for an object unless a call towrite(java.lang.Object)
is currently in progress.Parses the beginning of the file and determines the encoding.toString()
Loads the contents of this file into an existing object.void
void
writeRawTo
(Writer w) Writes the raw XML to the givenWriter
.
-
Constructor Details
-
XmlFile
-
XmlFile
-
XmlFile
- Parameters:
force
- Whether or not to flush the page cache to the storage device withFileChannel.force(boolean)
(i.e.,fsync
} orFlushFileBuffers
) before this method returns. If you set this tofalse
, you will lose data integrity.- Since:
- 2.304
-
-
Method Details
-
getFile
-
getXStream
public com.thoughtworks.xstream.XStream getXStream() -
read
Loads the contents of this file into a new object.- Throws:
IOException
-
unmarshal
Loads the contents of this file into an existing object.- Returns:
- The unmarshalled object. Usually the same as
o
, but would be different if the XML representation is completely new. - Throws:
IOException
-
unmarshalNullingOut
Variant ofunmarshal(Object)
applyingXStream2.unmarshal(HierarchicalStreamReader, Object, DataHolder, boolean)
.- Throws:
IOException
- Since:
- 2.99
-
write
- Throws:
IOException
-
replaceIfNotAtTopLevel
Provides an XStream replacement for an object unless a call towrite(java.lang.Object)
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 someonLoad
hook): implement awriteReplace
method delegating to this method. The replacement need not beSerializable
since it is only necessary for use from XStream.- Parameters:
o
- an object (this
fromwriteReplace
)replacement
- a supplier of a safely serializable replacement object with areadResolve
method- Returns:
o
, ifwrite(java.lang.Object)
is being called on it, else the replacement- Since:
- 2.74
-
exists
public boolean exists() -
delete
- Throws:
IOException
-
mkdirs
- Throws:
IOException
-
toString
-
readRaw
Opens aReader
that loads XML. This method usesthe right encoding
, not just the system default encoding.- Returns:
- Reader for the file. should be close externally once read.
- Throws:
IOException
- Encoding issues
-
asString
Returns the XML file read as a string.- Throws:
IOException
-
writeRawTo
Writes the raw XML to the givenWriter
. Writer will not be closed by the implementation.- Throws:
IOException
-
sniffEncoding
Parses the beginning of the file and determines the encoding.- Returns:
- always non-null.
- Throws:
IOException
- if failed to detect encoding.
-