Importing WSDL with Java and Maven

SOAP web services are often used in commercial software. If we plan to use existing SOAP web service, we should receive a WSDL file which defines the contract between the web service and its clients. This contract defines at least: the methods provided by the web service, arguments of each methods and their types, exception specification for methods and definitions of additional XSD types.

JDK provides wsimport executable which can generate Java source code files based on the information provided in the WSDL file. In practice we use a build tool to do it automatically. In this post I would like to show how we can import WSDL file in Maven project.

Storing WSDL file

After receiving WSDL file we should put it in a location that is accessible by Maven. Usually WSDL file is placed under src/main/resources folder or one of its subdirectories.

In our case the situation will be more complicated because we got two files. One is the WSDL file periodictableaccess.wsdl that we want to import. The second is the XSD file periodictablebase.xsd which is imported inside WSDL file like this:

<xsd:import schemaLocation="periodictablebase.xsd" namespace="http://www.example.org/periodictablebase"></xsd:import>

With such import the WSDL file and its XSD file should be placed in the same directory. We will choose src/main/resources/wsdl directory.

Configuring JAX-WS Maven plugin

To import the WSDL file we have to put the following plugin definition in pom.xml file:

<plugin>
  <groupId>org.codehaus.mojo</groupId>
  <artifactId>jaxws-maven-plugin</artifactId>
  <version>2.4.1</version>
  <executions>
    <execution>
      <id>periodictableaccessws</id>
      <goals>
        <goal>wsimport</goal>
      </goals>
      <configuration>
        <wsdlDirectory>src/main/resources/wsdl</wsdlDirectory>
        <wsdlFiles>
           <wsdlFile>periodictableaccess.wsdl</wsdlFile>
        </wsdlFiles>
        <packageName>com.example.periodictable.ws.access</packageName>
        <vmArgs>
           <vmArg>-Djavax.xml.accessExternalSchema=all</vmArg>
        </vmArgs>
      </configuration>
   </execution>
 </executions>
</plugin>

Let’s go over it step by step. With groupId, artifactId and version we reference the Maven plugin and its version that we want to use. In this case it is jaxws-maven-plugin from Codehaus.

Later we define executions element. This element can contain multiple execution elements – one for each independent wsimport execution. In our case we got only one WSDL file and we execute wsimport only once.

Inside execution element we define unique ID of the execution. Obviously, if you got multiple execution elements, they should have different IDs.

We should also define the goals that we want to use. There are four of these:

  • wsimport – generates JAX-WS artifacts used by JAX-WS clients and services using WSDL file
  • wsimport-test – same like wsimport but for tests
  • wsgen – generates JAX-WS artifacts used by JAX-WS clients and services using service endpoint implementation class
  • wsgen-test – same like wsgen but for tests

Finally, we should provide the configuration that should be used to generate JAX-WS artifacts. Element wsdlDirectory defines the directory where the WSDL files are placed and wsdlFiles specifies which exactly WSDL files from this directory should be imported. We can specify more than one WSDL file if needed.

Element packageName defines in which Java package the generated artifacts should be placed. It is advised to put the generated artifacts in its own separate package to prevent name collisions.

Normally, it should be everything but in our case the WSDL file is not standalone and imports XML schema from separate file. Since Java 8 such access is subject to restrictions and may result in following error during build:

schema_reference: Failed to read schema document 'periodictablebase.xsd', because 'file' access is not allowed due to restriction set by the accessExternalSchema property. 

To prevent the error we should define javax.xml.accessExternalSchema property. We can do so in different ways. In this case we pass the property definition as an argument to wsimport execution.

Here we used only a small subset of parameters provided by the Maven plugin jaxws-maven-plugin. You can read more about the plugin and its parameters in the official documentation.

Please, notice that we don’t specify the path to XSD file in pom.xml file. It is completely enough that the WSDL file knows the location of XSD file.

Running JAX-WS Maven plugin

When you run build in Maven (e.g. mvn install), you should notice the following plugin execution in the output:

--- jaxws-maven-plugin:2.4.1:wsimport (periodictableaccessws) @ com.example.wsimp ---
Processing: file:/home/robert/informatyka/tests/com.example.wsimp/src/main/resources/wsdl/periodictableaccess.wsdl
jaxws:wsimport args: [-keep, -s, '/home/robert/informatyka/tests/com.example.wsimp/target/generated-sources/wsimport', -d, '/home/robert/informatyka/tests/com.example.wsimp/target/classes', -encoding, UTF-8, -Xnocompile, -p, com.example.periodictable.ws.access, "file:/home/robert/informatyka/tests/com.example.wsimp/src/main/resources/wsdl/periodictableaccess.wsdl"]
parsing WSDL...

Generating code...

If you take a close look, you can notice that:

  • The generated Java source files (*.java files) are put somewhere under target/generated-sources/wsimport directory.
  • The generated Java class files (*.class files) are put under target/classes directory.

JAX-WS Maven plugin is bound to Maven lifecycle phase generate-sources. This phase is run almost at the very beginning of the build to ensure that all generated classes are already here for compile phase.

More information about wsimport can be found in this technote.

Importing multiple WSDL files

If you have many WSDL files to import, there are 2 possibilities. The easiest one is to specify multiple wsdlFile elements inside wsdlFiles in file pom.xml. The generated classes will be put in the same Java package which may result in name conflicts. The better option is to create multiple execution elements inside file pom.xml. This way we can specify separate Java package for each imported WSDL to prevent name conflicts.

Advertisements
Posted in Java, Java EE, Maven, Web-Services, XML | Tagged , , , , | Leave a comment

Objects utility class in Java

Today I would like to quickly mention java.util.Objects class. The JavaDoc documentation for this class says:

This class consists of static utility methods for operating on objects. These utilities include null-safe or null-tolerant methods for computing the hash code of an object, returning a string for an object, and comparing two objects.

That’s all. There is nothing special or difficult in this class – similar methods were already written thousands of times by many developers all over the world. Yet I find this class very useful because it simplifies the source code and removes unnecessary code duplication. Let’s take a glimpse at its methods.

Validating input arguments

Class Objects provides 3 methods to verify if the argument passed to the method is not null.

static <T> T	Objects.requireNonNull(T obj)

Checks if the passed object is not null. If it is null, the methods throws exception.

static <T> T	Objects.requireNonNull(T obj, String message)

Checks if the passed object is not null. If it is null, the methods throws exception with the specified message.

static <T> T	Objects.requireNonNull(T obj, Supplier messageSupplier)

Checks if the passed object is not null. If it is null, the method throws exception with the message provided by supplier. Although it looks more complicated than the previous method, it has the advantage that it creates error message lazily – only when it is actually needed. Therefore, it may be a bit faster in certain situations.

These basic methods reduce the following 3 lines of code:

if (arg == null) {
    throw new NullPointerException("Argument is null.");
}

to just one:

Objects.requireNonNull(arg, "Argument is null.").

These methods are used often in JDK source code.

Null-safe output

There are also 2 very simple methods for converting objects to string.

static String	Objects.toString(Object o, String nullDefault)

If the passed object is not null, returns o.toString(). Otherwise, returns nullDefault value.

static String	Objects.toString(Object o)

The same as Objects.toString(o, “null”).

Null and non-null predicates

There are two self-explanatory methods:

static boolean	Objects.isNull(Object obj)
static boolean	Objects.nonNull(Object obj)

The only reason for their existence is that they can be used as a predicate in stream API like this:

myList.stream().map(...).filter(Objects::nonNull)...

Hash code and equals

Let’s consider following class with typical hashCode and equals methods:

class Mapping {
        private String name; // never null
        private Integer value; // can be null

        public Mapping(String name, Integer value) {
            Objects.requireNonNull(name);
            this.name = name;
            this.value = value;
        }
        
        @Override
        public int hashCode() {
            int result = name.hashCode();
            result += 3 * (value != null ? value.hashCode() : 0);
            return result;
        }

        @Override
        public boolean equals(Object obj) {
            if (obj == null) {
                return false;
            }
            if (getClass() != obj.getClass()) {
                return false;
            }
            final Mapping other = (Mapping) obj;
            return name.equals(other.name)
                    && ((value == null && other.value == null) || (value != null && value.equals(other.value)));
        }
    }

We can assume that name is never null but value can be sometimes null and we have to put some conditional code in hashCode and equals methods. It is nothing hard here but it takes a moment to verify if the implementation of these methods is correct.

Class Objects provides few convenient methods to simplify the code:

static int	Objects.hashCode(Object o)

If the object is not null, returns its hash code. Otherwise, returns 0.

static int	Objects.hash(Object... values)

Generates hash code for the sequence of values. The values can contain nulls.

static int	Objects.equals(Object a, Object b)

Compares two values in null-safe way. If both are not null, calls equals method on first argument. If both are null, returns true. Otherwise, returns false.

With the first method we can simplify the hashCode method to:

public int hashCode() {
    int result = name.hashCode();
    result += 3 * Objects.hashCode(value);
    return result;
}

and with the second we can reduce the body of the method to single line:

public int hashCode() {
    return Objects.hash(name, value);
}

We can do the similar thing for equals:

public boolean equals(Object obj) {
   if (obj == null) {
       return false;
   }
   if (getClass() != obj.getClass()) {
       return false;
   }
   final Mapping other = (Mapping) obj;
   return Objects.equals(name, other.name)
        && Objects.equals(value, other.value);
}

Most of the conditional code is removed. Isn’t it simpler?

Other

There are two additional methods in Objects class.

static boolean	Objects.deepEquals(Object a, Object b)

If both arguments are arrays, behaves like Arrays.deepEquals(). If both arguments are null, returns true. If one argument is null, returns false. Otherwise, calls equals on the first argument.

static <T> int	Objects.compare(T a, T b, Comparator c)

If both arguments are null or both are the same reference, returns 0. Otherwise, compares the arguments using provided comparator.

Conclusion

This class is a nice addition to Java 7 and reduces some unnecessary boilerplate. New versions of IDE can even use this class to generate simpler and more concise hashCode and equals methods than before.

We can go even further and generate these methods (and more) “on-the-fly” using lombok. But it is a topic for separate post.

Posted in Java | Tagged | Leave a comment

Default and static methods in interfaces in Java 8

Before Java 8 interfaces could only contain static fields (usually simple constants) and abstract methods. Java 8 provided the ability to define concrete (default and static) methods in interfaces. This new language feature is used extensively in Java core packages.

Static methods

Static method in interface looks the same like in a normal class:

public interface Checker {
    ...
    public static boolean isNull(Object obj) {
        return obj == null;
    }
    ...

The main reason to add static methods to interfaces is to keep related utility methods in one place so that they can be easily used by subclasses, default methods in subinterfaces or by users of this interface.

Default methods

Default method looks like a typical class method but is defined inside an interface and contains default specifier. Let’s look at Collection.removeIf() default method:

default boolean removeIf(Predicate<? super E> filter) {
        Objects.requireNonNull(filter);
        boolean removed = false;
        final Iterator<E> each = iterator();
        while (each.hasNext()) {
            if (filter.test(each.next())) {
                each.remove();
                removed = true;
            }
        }
        return removed;
    }

Default method can access everything that is defined within this interface or is inherited by this interface, including:

  • reference to this
  • all abstract methods defined in this or super-interfaces
  • all default or static methods defined in this or super-interfaces
  • all static fields defined in this or super-interfaces

Default methods allow adding new functionality to existing interfaces without breaking all existing implementations – they preserve backwards compatibility. A class, that implements an interface with a default method, gets the default implementation from the interface but it can still override the default implementation.

Default and static methods in functional interfaces

The functional interface can contain multiple default and static methods and still be functional. In fact, default and static methods are not abstract and are not counted within the limit of exactly one abstract method. Here is an example:

@FunctionalInterface
public interface Comparator<T> {
    int compare(T o1, T o2);
    ....
    default Comparator<T> reversed() {
        return Collections.reverseOrder(this);
    }
    public static <T> Comparator<T> nullsFirst(Comparator<? super T> comparator) {
        return new Comparators.NullComparator<>(true, comparator);
    }
    ....

Extending interfaces which contain default methods

If we create a new interface which extends an interface which contains a default method, we have 3 possibilities:

  • Not mention the default method in the new interface. This way the new interface will inherit the default method from parent.
  • Override the default method by redefining it in the new interface and providing new method body. All subclasses and subinterfaces will use new definition of the default method.
  • Declare the default method as abstract in the new interface. This way the default method must be overridden in subclasses or subinterfaces of the new interface.

Default method ambiguity

Sometimes we may want to implement two interfaces which contain default methods with the same method signature (name, parameters, and so on):

public interface InterfaceOne { 
    default void doSomething() { 
        ...
    } 
}
public interface InterfaceTwo {
    default void doSomething() {
        ...
    }
}
public class MyClass implements InterfaceOne, InterfaceTwo  {
}

In this rare case the compilation will fail because Java compiler does not know which implementation of the default method it should choose for the class. To resolve this issue we have to explicitly redefine/redeclare the default method in the class. We have two possibilities here.

The first one is to simply override the default method in the class and provide new method body:

public class MyClass implements InterfaceOne, InterfaceTwo  {
    public void doSomething() {
        // some code
        InterfaceOne.super.doSomething();
    }
}

Please, note that we are not using default keyword anymore. We can also use following syntax:

InterfaceOne.super.doSomething();

to call default implementation from one of the implemented interfaces.

Alternatively, we can declare the default method in the class as abstract:

public abstract class MyClass implements InterfaceOne, InterfaceTwo  {
        public abstract void doSomething();
    }

As a result the class must be made abstract also. This way we can somehow “postpone” the problem because the concrete subclass will have to redefine this default method.

Conclusion

Many static and default methods have been added to existing interfaces since Java 8 to simplify their usage and promote code reuse. Some of these interfaces include: Iterator, Iterable, Comparator, Collection.

Posted in Java | Tagged | Leave a comment

Database schema creation in JPA using SQL scripts

Recent versions of JPA provide a feature to automatically create the database objects (like tables, sequences or indexes), load initial data into database on application deployment; and also remove them after the application is undeployed.

All that is needed is to define several properties in persistence.xml file:

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
    http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
  <persistence-unit name="mainPU" transaction-type="JTA">
    <provider>org.hibernate.ejb.HibernatePersistence</provider>
    <jta-data-source>java:/orcl</jta-data-source>
    <class>com.example.periodictable.Element</class>
    <class>com.example.periodictable.ElementCategory</class>
    <exclude-unlisted-classes>true</exclude-unlisted-classes>
    <properties>
      <property name="hibernate.dialect" value="org.hibernate.dialect.Oracle10gDialect"/>
      <property name="hibernate.transaction.jta.platform" value="org.hibernate.service.jta.platform.internal.JBossAppServerJtaPlatform"/>
      
      <property name="javax.persistence.schema-generation.database.action" value="drop-and-create"/>
      <property name="javax.persistence.schema-generation.create-source" value="script"/>
      <property name="javax.persistence.schema-generation.create-script-source" value="dbscripts/create.sql"/>
      <property name="javax.persistence.schema-generation.drop-source" value="script"/>
      <property name="javax.persistence.schema-generation.drop-script-source" value="dbscripts/drop.sql"/>
      <property name="javax.persistence.sql-load-script-source" value="dbscripts/load.sql"/>
      
      <property name="hibernate.hbm2ddl.import_files_sql_extractor" value="org.hibernate.tool.hbm2ddl.MultipleLinesSqlCommandExtractor" />
      <property name="hibernate.show_sql" value="true"/>

    </properties>
  </persistence-unit>
</persistence>

Property javax.persistence.schema-generation.database.action defines which action should be taken on database when the application is deployed:

  • none – Takes no action on database. Nothing will be created or dropped.
  • create – JPA provider will create the database schema on application deployment.
  • drop – JPA provider will drop the database schema on application deployment.
  • drop-and-create – JPA provider will first drop the old database schema and then will create the database schema on application deployment.

If property javax.persistence.schema-generation.database.action is not specified, then none is assumed by default. In practice drop-and-create is very useful in simple, test applications and none in real production applications in which the database schema is created elsewhere.

Property javax.persistence.schema-generation.create-source informs JPA provider what should be used as a source of database schema:

  • metadata – JPA provider will use entity metadata (e.g. annotations) to generate the database schema. This is the default.
  • script – JPA provider will run provided SQL script to create database schema. The script should create tables, indexes, sequences and other necessary database artifacts.
  • metadata-then-script – The combination of metadata and then script in that order.
  • script-then-metadata – The combination of script and then metadata in that order.

Finally, property javax.persistence.schema-generation.create-script-source specifies the location of SQL script to run on application deployment. The location can be a file URL but usually is a relative path to the SQL script packaged into application JAR/WAR.

Properties javax.persistence.schema-generation.drop-source and javax.persistence.schema-generation.drop-script-source have similar values and meaning as their create* counterparts but of course these are used to drop database schema.

There is also one additional property javax.persistence.sql-load-script-source which can be used to load the initial data into the database tables. This SQL script is run after the database schema was created.

Hibernate

Hibernate requires (by default) that the SQL script contains maximum one line per statement. In short it means that the SQL statement cannot be split into multiple lines for better readability which is a common thing for CREATE TABLE commands. This inconvenience can be resolved by specifying following Hibernate specific property:

<property name="hibernate.hbm2ddl.import_files_sql_extractor" value="org.hibernate.tool.hbm2ddl.MultipleLinesSqlCommandExtractor" />

Conclusion

The above properties are very useful for simple, test applications which does not require the database data to survive the application undeployment. In production applications property javax.persistence.schema-generation.database.action should be set to none to prevent the loss data from the database in case the application is temporarily undeployed.

The sample application using these properties is available at

Posted in Java, Java EE, JPA, Hibernate | Tagged , , , | Leave a comment

Reading text file line by line in Java

Reading text files from hard disk is quite common task in software development practice. Usually we are interested in processing it line by line. In this article I would like to present few popular ways how to do it easily using Java IO.

Reading whole file into memory

Reading a text file can be as simple as calling single Files.readAllLines() method:

Path path = Paths.get(fileName);
List<String> lines = Files.readAllLines(path, StandardCharsets.UTF_8);
for (String line : lines) {
   System.out.println(line);
}

This method reads the whole file with given path and stores all its lines into an array of String. The rest of the code just prepares the path and prints the read lines.

While it may seem like a perfect method, it has one significant drawback. If the file being read is large, the created array will be very long. As a result memory usage of the application and the whole JVM will grow significantly which can reduce the performance of the application or in worse case kill the application with infamous OutOfMemoryError.

Therefore, usage of this method must be done with care and only in cases where the input file is small.

Reading file using BufferedReader

If you are going to read large file, you can resort to using BufferedReader class:

try (BufferedReader reader = new BufferedReader(new FileReader(fileName))) {
    while (true) {
        String line = reader.readLine();
        if (line == null) {
           break;
        }
    System.out.println(line);
    }
}

First, we are creating a FileReader instance to access the given file. Because FileReader provides only very basic set of operations, we are wrapping it inside BufferedReader which has more convenient and richer interface. Finally, we call BufferedReader.readLine() method to read each line separately as long as this method returns non-null. Try-with-resources block ensures that the file is always closed at the end.

If using Java 7 or later, creation of BufferedReader can be simplified using Files class:

Path path = Paths.get(fileName);
try (BufferedReader reader = Files.newBufferedReader(path, StandardCharsets.UTF_8)) {
    while (true) {
        String line = reader.readLine();
        if (line == null) {
           break;
        }
    System.out.println(line);
    }
}

Reading file using Java 8 streams

Java 8 brought new streams feature into the standard library. The Files class was also extended with new Files.lines() method which opens the file with given path and creates a stream with all the lines of the file. Then the stream of lines can be processed as any other stream of String including filter, map/transform and aggregate operations. In our case we print the lines only:

Path path = Paths.get(fileName);
try (Stream<String> lines = Files.lines(path, StandardCharsets.UTF_8)) {
    lines.forEachOrdered(System.out::println);
}

This method has the advantage over the first presented method because the file is not read into memory at once but lazily.

Conclusion

Usage of BufferedReader is the most popular and versatile method to read a text file. If you are sure that the file is small, you can use Files.readAllLines() method to simplify the source code. The last method utilizing the streams API is very promising but requires Java 8 runtime environment which is still not an option in many cases (e.g. legacy systems, compatibility, long-running projects).

As always the source code of the example is available at GitHub.

Posted in Java | Tagged , | Leave a comment

Iterating through Java list backwards

The most natural method of iterating through a list in Java is to start from the first element of the list and then move forward until the last one is reached. While this is the most common, it is sometimes necessary to do it otherwise – start from the last element and move in reverse direction. In this post I would like to show 4 different ways to do it easily.

This short class creates a simple list and calls 4 methods to print it in reverse order:

package com.example.iteratelistreverse;

import com.google.common.collect.Lists;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import org.apache.commons.collections.iterators.ReverseListIterator;

public class Main {

    public static void main(String[] args) throws IOException {
        List<String> list = new ArrayList<>();
        list.add("First");
        list.add("Second");
        list.add("Third");
        list.add("Fourth");
        list.add("Fifth");

        iterateIndexedAccess(list);
        iterateListIterator(list);
        iterateReverseListIterator(list);
        iterateListsReverse(list);
    }

    private static void iterateIndexedAccess(List<String> list) {
        System.out.print("\nFor loop with random access:\n");
        for (int i = list.size() - 1; i >= 0; i--) {
            System.out.println(list.get(i));
        }
    }

    private static void iterateListIterator(List<String> list) {
        System.out.print("\nList iterator:\n");
        ListIterator<String> it = list.listIterator(list.size());
        while (it.hasPrevious()) {
            System.out.println(it.previous());
        }
    }

    private static void iterateReverseListIterator(List<String> list) {
        System.out.print("\nApache ReverseListIterator:\n");
        Iterator<String> it = new ReverseListIterator(list);
        while (it.hasNext()) {
            System.out.println(it.next());
        }
    }

    private static void iterateListsReverse(List<String> list) {
        System.out.print("\nGuava List.reverse:\n");
        for (String v : Lists.reverse(list)) {
            System.out.println(v);
        }
    }

}

Method iterateIndexedAccess() shows the most common solution. In this method we are using the indexed access to the elements of the list which is very easy and obvious. It has also very good performance assuming that the instance of the list supports fast random access. It is the case for very popular ArrayList class.

However, other classes may not support fast random access. One of the examples is LinkedList class. For every List.get() method call this class has to iterate from the beginning (or alternatively from the end) of the list to find the element at given index which makes it very slow for large lists.

Method iterateListIterator() overcomes this problem by using a list iterator which can move forward and backward using ListIterator.next() and ListIterator.previous() calls respectively. In our example we are starting from the position after the last element and are moving to the previous element on every loop iteration.

Method iterateReverseListIterator() is quite specific because it creates an iterator which pretends that it is normal iterator (forward iterator). In fact it starts from the last element of the list and moves to the previous one on every call to Iterator.next() method. This solution uses ReverseListIterator class from Apache Commons library.

The last way uses method Lists.reverse() from Guava library to create a reversed view of the given list. Once we have the view, which is in fact instance of Iterable interface, we can go over it using enhanced loop.

As usual you can find the source code of this example at GitHub.

Posted in Guava, Java | Tagged , | 1 Comment

Usage of serialVersionUID in Java serialization

Java run-time associates with each serializable class a special version number known as serialVersionUID. This number is later used during deserialization process to verify if the application which performed the serialization and the application which is doing the deserialization have loaded and use compatible Java classes (with respect to serialization). If the receiver has loaded a class which has the same name but different serialVersionUID, the Java run-time will report a problem by throwing an exception of type InvalidClassException.

Generally speaking this kind of mechanism allows us to detect and report any compatibility problems during deserialization process as early as possible. If this check was missing, the deserialization process would likely finish without raising any exception but the created object would contain invalid data. This can easily lead to unpredictable behavior and can later cause errors which root cause is hard to track.

Defining serialVersionUID

A serializable class can specify its own serialVersionUID value explicitly by declaring a static, final field of name serialVersionUID and of type long:

private static final long serialVersionUID = 4038305141805077716L;

The access modifier does not really matter but private is commonly used.

If serial version is not explicitly declared, it will be automatically generated by compiler and stored in the class file. The compiler calculates default serialVersionUID value based on several aspects of the class like its name, its all public and protected members and so on.

The default serialVersionUID calculation may vary between compilers so it may give different results in different environments. To ensure a consistent serialVersionUID value, it is strongly recommended to explicitly declare its value.

Many IDE for Java have a feature which detects if the class should declare serialVersionUID and can report it as a warning. In case of the Eclipse the warning is following:

The serializable class Person does not declare a static final serialVersionUID field of type long

Adding serialVersionUID to existing classes

If you create a new class, you can choose any arbitrary value for its serialVersionUID because there are no serialized objects of this class yet stored anywhere.

However, if you already have an old class to which you would like to add explicit serial version value, you have be careful. The best idea is to choose a value which would be automatically generated by the compiler.

Oracle JDK provides a program serialver which shows the following basic window when started with -show option from command line:
serialver
When you enter a full name of the existing class and click Show button, it will output its default generated serialVersionUID below. You can just copy-paste this line into Java class file.

Additionally, Eclipse provides a nice context tool which can simplify adding serialVersionUID:

serialver-eclipse

Managing explicit serialVersionUID

The serialVersionUID represents a class version and has to be managed. If you make a change to the existing class which makes it incompatible with the previous version (e.g. changing base class, modifying the types of the fields or removing fields), it is also necessary to modify (e.g. increment) its serialVersionUID value.

On the other hand, adding new fields to the class does not necessarily make it incompatible. Additionally, you may manage to keep the class backward compatible by customizing serialization procedure using readObject() and writeObject() methods.

Example

Let’s consider a simple application serializing and deserializing objects of Person class:

package com.example.serialversionuid;

import java.io.Serializable;

public class Person implements Serializable {
    private static final long serialVersionUID = 4038305141805077716L;
	
    private String firstName;
    private String lastName;

    public Person(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    @Override
    public String toString() {
        return "Person{" + "firstName=" + firstName + ", lastName=" + lastName + '}';
    }
    
}

with the main class:

package com.example.serialversionuid;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class Main {
    
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        if (args.length != 2) {
            System.err.println("Usage: serialversionuid read|write FILE");
            return;
        }
        final String operation = args[0];
        final String file = args[1];
        
        
        if (operation.equals("read")) {
            try (ObjectInputStream is = new ObjectInputStream(new FileInputStream(file))) {
                Person person = (Person) is.readObject();
                System.out.println("Read person: " + person);
            }
        } else if (operation.equals("write")) {
            Person person = new Person("James", "Bond");
            try (ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream(file))) {
                os.writeObject(person);
            }
        }
    }
    
}

When the serialVersionUID is unchanged we can serialize and deserialize objects of Person class without problems:

$ java -jar serialversionuid-1.0-SNAPSHOT.jar write data.ser
$ java -jar serialversionuid-1.0-SNAPSHOT.jar read data.ser
Read person: Person{firstName=James, lastName=Bond}

However, if you change serialVersionUID in Person class, rebuild the jar file and try to read data.ser file again, the InvalidClassException exception appears:

$ java -jar serialversionuid-1.0-SNAPSHOT.jar read data.ser
Exception in thread "main" java.io.InvalidClassException: com.example.serialversionuid.Person; local class incompatible: stream classdesc serialVersionUID = 4038305141805077716, local class serialVersionUID = 4038305141805077717
        at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:617)
        at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1622)
        at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1517)
        at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1771)
        at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1350)
        at java.io.ObjectInputStream.readObject(ObjectInputStream.java:370)
        at com.example.serialversionuid.Main.main(Main.java:22)

As you can easily notice, the Java run-time reports incompatibility between classes used to serialize data and deserialize it later.

Conclusion

Field serialVersionUID is often forgotten and ignored. In most cases not declaring it does not cause any problems. However, if your application exchanges serialized objects over network with another applications or stores serialized data on disk for long time, the importance of proper management of serialVersionUID becomes crucial.

The source code for the example is available at GitHub.

Posted in Java | Tagged | Leave a comment