Category Archives: XML

Jar Normalizer Maven Plugin

When building a project with Maven, the generated binary artifact would typically differ from one build to another, even if nothing has changed in the project. Systems relying on binary fingerprints (e.g. checks on MD5 hash) would detect different artifacts although the source is exactly the same. The change in the binary Jar files results from different timestamps, possibly different ordering of the entries, among other reasons. One way to solve this is by “fixing” the timestamp of the Jar entries (to some constant value), sorting the entries of the manifest, etc.

The jar-timestamp-normalize-maven-plugin is a Maven plugin which provides this capability. It consists of a single goal called normalize which can be bound to the package lifecycle phase and configured in the project’s POM:

<plugins>
    <plugin>
        <groupId>com.github.manouti</groupId>
        <artifactId>jar-timestamp-normalize-maven-plugin</artifactId>
        <version>1.0-SNAPSHOT</version>
        <executions>
            <execution>
                <id>jar-normalize</id>
                <goals>
                    <goal>normalize</goal>
                </goals>
                <phase>package</phase>
            </execution>
        </executions>
    </plugin>
</plugins>

Normalization mainly consists of the following steps:

  • Alphabetically sort all files and directories in the Jar.
  • Setting the last modified time of all Jar entries to a specific timestamp (default value is 1970-01-01 00:00:00AM but can be changed by passing -Dtimestamp as a system property).
  • Reordering (alphabetically) of attributes in the manifest except for Manifest-Version which always comes first.
  • Removing comments from the pom.properties file which contain a timestamp that causes the Jar to differ from one build to another.

Once invoked, the goal will generate the output file next to the original artifact (named artifactId-version-normalized.jar), i.e. in the project.build.directory directory.

List of configuration parameters:

Parameter Description
outputDirectory Where to store the output artifact, defaults to the project output directory.
timestamp Fixed timestamp for artifact entries, defaults to 1970-01-01 00:00:00AM. Can be using -Dtimestamp property.
normalizedArtifactId Artifact name to be used in the output file name, default to the project’s artifactId.
normalizedClassifierName Classifier to be used in the output file name, defaults to normalized.

Project home: https://github.com/manouti/jar-timestamp-normalize-maven-plugin

Advertisements

Object Serialization/Deserialization Using XStream

XStream is a simple Java library for serializing objects to XML and vice-versa. With few lines of code, it can convert object graphs into an XML representation, or deserialize XML into an object graph. This is done in a fast and memory efficient way. By default, XStream relies on XPP (XML Pull Parser) which is a fast XML parsing library. It can also use a standard DOM parser or a StAX parser (since Java 6) that is provided with the library.

First, let’s consider some simple classes to serialize and deserialize.

public class Student {
    private int id;  // fields can be private
    private String name;
    private int age;
    private List courseInfos = new ArrayList();

    // getters and setters
    // no need for a default constructor

    @Override
    public String toString() {
        return "Student [id=" + id + ", name=" + name + ", age=" + age
	    + ", courseInfos=" + courseInfos + "]";
    }
}

public class CourseInfo {
    private String courseId;
    private String title;

    // getters and setters

    @Override
    public String toString() {
        return "CourseInfo [courseId=" + courseId + ", title=" + title + "]";
    }
}

The below example shows how to serialize an object representing a student into XML.

XStream xstream = new XStream(new DomDriver());

xstream.alias("student", Student.class);
xstream.alias("course", CourseInfo.class);

Student student = new Student();
student.setId(123);
student.setName("Alex");
student.setAge(24);

CourseInfo mathCourse = new CourseInfo();
mathCourse.setCourseId("MATH201");
mathCourse.setTitle("Calculus II");

CourseInfo chemCourse = new CourseInfo();
chemCourse.setCourseId("CHEM200");
chemCourse.setTitle("Introductory chemistry");

student.getCourseInfos().add(mathCourse);
student.getCourseInfos().add(chemCourse);

String serializedStudent = xstream.toXML(student);
System.out.println(serializedStudent);

We create an instance of the XStream class. In this case, we tell XStream to use a DOM parser instead of the default XPP parser. Then we create the Student object to serialize and call the toXML method to get a string containing the XML representation. The alias method at lines 3 and 4 specify the names of the XML elements corresponding to the classes. If no aliases are specified, then the fully qualified class names will be used, which would increase the size of the XML.

When the above code executes, the output is the following:

<student>
  <id>123</id>
  <name>Alex</name>
  <age>24</age>
  <courseInfos>
    <course>
      <courseId>MATH201</courseId>
      <title>Calculus II</title>
    </course>
    <course>
      <courseId>CHEM200</courseId>
      <title>Introductory chemistry</title>
    </course>
  </courseInfos>
</student>

To convert the above XML back into a Student object, we call the fromXML method as follows:

Student student = (Student) xstream.fromXML(serializedStudent);
System.out.println(student);

which would output the following:

Student [id=123, name=Alex, age=24, courseInfos=[CourseInfo [courseId=MATH201, title=Calculus II], CourseInfo [courseId=CHEM200, title=Introductory chemistry]]]

XStream is mainly used to read and write XML but also supports other formats like JSON.