Convert Serializable into Externalizable

Looking for a tool that automatically converts Serializable classes into Externalizable ones? Look no further, you found Externalizer4J.

Let Externalizer4J optimize your data serialization. Externalizer4J converts your Serializable classes into Externalizable classes. It does more than a simple one on one conversion. First Externalizer4J analyzes the class bytecode and class hierarchy. Based on this analysis Externalizer4J generates new writeExternal() and readExternal() methods containing fast logic. All this at high speed!

Get started with Externalizer4J in less than 2 minutes with the instructions on this page!

2 minutes to get started

This section describes the steps to get started in 2 minutes. For a more detailed explanation please read the individual sections below.

Follow each of the following steps:

  1. Create a file called externalizer4j.properties to your build
  2. Put “acceptEULA=true” (without the double quotes) into the properties file
  3. Integrate in your build
    1. Using Apache Ant copy the part from the build.xml found here
    2. Using Apache Maven copy the part from the pom.xml found here

Externalizer4J for Ant and Maven

Using Maven or Ant for you builds?  This page shows how you can get Externalizer4J in your builds scripts:

  • Ant: with an ant task
  • Maven: with a maven plugin

Basic configuration

Externalizer4J needs very little configuration to get started. externalizer4j.properties

  1. Create a file called externalizer4j.properties
    1. Attention: the filename is case sensitive!
  2. Puts in the resource directory of you build
  3. Make sure it get copied in same directory as .class files

A minimal externalizer4j.properties should contain at least one line! See below for the minimal content. To activate Externalizer4J one has to agree with the EULA. Ones this is setup Externalizer4J can be invoked.

#
# Accept the EULA by setting to true to activate
#
acceptEULA=true

Advanced configuration

Externalizer4J uses the default configuration values that fit most cases. Power users can further optimize the data serialization through a series of advanced configuration options. These additional configuration options include:

  • Including or excludes packages and classes using regular expressions
  • Enable human readable diagnostics to explain the analysis
  • Logging of debug information
  • Enable verification of the generated bytecode
  • Configure advanced speed optimizations for: arrays, String, Collections and Date

Ant

Get the task

Automate the download of the jar containing the ant task for Externalizer4J

<get dest="." skipexisting="false">
    <url url="http://www.biggerbytes.be/maven2/be/biggerbytes/externalizer-maven-plugin/${e4j.version}/externalizer-maven-plugin-${e4j.version}.jar"/>
</get>
dest="." skipexisting="false">

NOTE: the jar which contains the ant also contains the ant task. There is no externalizer-ant-task jar.

Define the task

Once the jar is available locally we need to define the task in our buid. Do this as follows:

<taskdef name="externalizer" classname="be.biggerbytes.ant.ExternalizerTask">
    <classpath path="${externalizer.jar}"/>
</taskdef>
<taskdef name="externalizer" classname="be.biggerbytes.ant.ExternalizerTask">

 

Use the task

Using the task in the ant build is simple. It is just a matter of calling the task after the compilation step.

IMPORTANT: Externalizer4J uses a simple text-based configuration using a standard .properties file. The name of this file is predefined and should be externalizer4j.properties (lower case for case-sensitive filesystems!).

Externalizer4J looks for the externalizer4j.properties file in the same directory as the .class produced by the ant build.

<target name="externalize" description="generate Externalizable classes">
    <externalizer classes="${classes.dir}" classpathref="cp"/>
</target>

The full build.xml

</pre>
<pre><?xml version="1.0" encoding="ISO-8859-1"?>
<project name="Externalizer4J demo" basedir="." default="jar" xmlns:artifact="urn:maven-artifact-ant">

    <property name="e4j.version" value="2015.8-SNAPSHOT"/>
    <property name="src.dir" value="src/main/java"/>
    <property name="testSrc.dir" value="src/test/java"/>
    <property name="classes.dir" value="classesAnt"/>
    <property name="testClasses.dir" value="testClassesAnt"/>
    <property name="maven.ant.tasks.jar" value="maven-ant-tasks-2.1.0.jar"/>
    <property name="m2repo" value="${user.home}/.m2/repository"/>
    <property name="externalizer.jar" value="${m2repo}/be/biggerbytes/externalizer-maven-plugin/${e4j.version}/externalizer-maven-plugin-${e4j.version}.jar"/>

    <path id="cp">
        <pathelement path="${m2repo}/org/openjdk/jmh/jmh-core/1.3.3/jmh-core-1.3.3.jar"/>
        <pathelement path="${m2repo}/org/openjdk/jmh/jmh-generator-annprocess/1.3.3/jmh-generator-annprocess-1.3.3.jar"/>
    </path>

    <path id="testCp">
        <path refid="cp"/>
        <pathelement path="${m2repo}/junit/junit/4.8.2/junit-4.8.2.jar"/>
    </path>

    <get dest="." skipexisting="false">
        <url url="http://www.biggerbytes.be/maven2/be/biggerbytes/externalizer-maven-plugin/${e4j.version}/externalizer-maven-plugin-${e4j.version}.jar"/>
    </get>

    <taskdef name="externalizer" classname="be.biggerbytes.ant.ExternalizerTask">
        <classpath path="${externalizer.jar}"/>
    </taskdef>

    <taskdef name="externalizerTest" classname="be.biggerbytes.ant.ExternalizerTestTask">
        <classpath path="${externalizer.jar}"/>
    </taskdef>


    <target name="clean" description="Delete all generated files">
        <delete dir="${classes.dir}" failonerror="false"/>
        <delete dir="${testClasses.dir}" failonerror="false"/>
        <delete file="${ant.project.name}.jar"/>
    </target>

    <!-- depends="download-libs"-->
    <target name="compile" description="Compiles the Task" >
        <mkdir dir="${classes.dir}"/>
        <javac srcdir="${src.dir}" destdir="${classes.dir}" classpathref="cp"/>
    </target>

    <target name="compileTest" description="Compiles the test Task" >
        <mkdir dir="${testClasses.dir}"/>
        <javac srcdir="${testSrc.dir}" destdir="${testClasses.dir}" classpathref="testCp"/>
    </target>

    <target name="copy_resource">
        <copy todir="${classes.dir}">
            <fileset dir="${src.dir}/../resources"
                     includes="**/*.properties"/>
        </copy>
    </target>

    <!-- The copy_resources should be called first so that externalizer4j.properties can be
     found in the classes directory -->
    <target name="externalize" description="generate Externalizable classes">
        <externalizer classes="${classes.dir}" classpathref="cp"/>
    </target>

    <target name="externalizeTest" description="generate Externalizable test classes">
        <externalizerTest testClasses="${testClasses.dir}" classes="${classes.dir}" classpathref="testCp"/>
    </target>

    <target name="jar" description="JARs the classes" depends="compile,copy_resource,externalize">
        <jar destfile="${ant.project.name}.jar" basedir="${classes.dir}"/>
    </target>

    <target name="testJar" description="JARs the test class" depends="compileTest,externalizeTest">
        <jar destfile="${ant.project.name}-test.jar" basedir="${testClasses.dir}"/>
    </target>


    <!-- Automate deps download from maven repo with tasks below -->

    <target name="download-libs" depends="-init-maven-task">
        <artifact:dependencies pathId="dependencies.classpath">
            <dependency groupId="org.openjdk.jmh"
                        artifactId="jmh-core"
                        version="1.3.3"/>
            <remoteRepository id="maven-central"
                              url="http://repo1.maven.org/maven2/"/>
        </artifact:dependencies>

        <move todir=".">
            <path refid="dependencies.classpath"/>
        </move>
    </target>

    <target name="-init-maven-task" depends="-obtain-maven-task-jar">
        <available property="maven.ant.tasks.jar.exists"
                   file="${maven.ant.tasks.jar}"/>
        <typedef resource="org/apache/maven/artifact/ant/antlib.xml"
                 uri="urn:maven-artifact-ant" classpath="${maven.ant.tasks.jar}"/>
    </target>

    <target name="-obtain-maven-task-jar">
        <available property="maven.ant.tasks.jar.exists"
                   file="${maven.ant.tasks.jar}"/>
        <antcall target="download-maven-jar"/>
    </target>

    <target name="download-maven-jar" unless="maven.ant.tasks.jar.exists">
        <property name="maven.ant.tasks.url"
                  value="http://www.apache.org/dist/maven/binaries/${maven.ant.tasks.jar}"/>
        <get src="${maven.ant.tasks.url}" dest="${maven.ant.tasks.jar}"/>
    </target>

</project>

 

Maven

Define the plugin repository

The plugin can be downloaded automatically from our repository. To make this possible an additional repository should be defined in the pom.xml

</pre>
<pre><pluginRepositories>
    <pluginRepository>
        <id>biggerbytes</id>
        <url>http://www.biggerbytes.be/maven2</url>
        <!--  -->
        <snapshots>
            <enabled>true</enabled>
            <checksumPolicy>fail</checksumPolicy>
            <updatePolicy>daily</updatePolicy>
        </snapshots>
        <releases>
            <enabled>true</enabled>
            <checksumPolicy>fail</checksumPolicy>
            <updatePolicy>never</updatePolicy>
        </releases>
    </pluginRepository>
</pluginRepositories>

Configure the plugin

To included the optimization in maven build one has to add the plugin to the build. This example illustrates the simple use, i.e. without <pluginManagement/>. The plugin execution is bound to the process-classes phase of the build.

IMPORTANT: Externalizer4J uses a simple text-based configuration using a standard .properties file. The name of this file is predefined and should be externalizer4j.properties (lower case for case-sensitive filesystems!).

Externalizer4J looks for the externalizer4j.properties file in the same directory as the .class produced by the maven build. Putting the externalizer4j.properties file in the resources directory of the maven should suffice.

</pre>
<pre>    <build>
        <plugins>
            <plugin>
                <groupId>be.biggerbytes</groupId>
                <artifactId>externalizer-maven-plugin</artifactId>
                <version>${e4j.version}</version>
                <executions>
                    <execution>
                        <id>optimize-classes</id>
                        <goals>
                            <goal>externalize</goal>
                            <goal>externalizeTest</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <groupId>org.apache.maven.plugins</groupId>
                <version>3.3</version>
                <configuration>
                    <source>1.5</source>
                    <target>1.5</target>
                </configuration>
            </plugin>
        </plugins>
    </build></pre>
<pre class="lang:java decode:true"></pre>
<h2 id="pom.xml">The full pom.xml</h2>
<pre class="lang:xhtml decode:true"></pre>
<pre><?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>be.biggerbytes</groupId>
    <artifactId>externalizer-demo</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <e4j.version>2015.8-SNAPSHOT</e4j.version>
    </properties>

    <pluginRepositories>
        <pluginRepository>
            <id>biggerbytes</id>
            <url>http://www.biggerbytes.be/maven2</url>
            <!--  -->
            <snapshots>
                <enabled>true</enabled>
                <checksumPolicy>fail</checksumPolicy>
                <updatePolicy>daily</updatePolicy>
            </snapshots>
            <releases>
                <enabled>true</enabled>
                <checksumPolicy>fail</checksumPolicy>
                <updatePolicy>never</updatePolicy>
            </releases>
        </pluginRepository>
    </pluginRepositories>

    <build>
        <plugins>
            <plugin>
                <groupId>be.biggerbytes</groupId>
                <artifactId>externalizer-maven-plugin</artifactId>
                <version>${e4j.version}</version>
                <executions>
                    <execution>
                        <id>optimize-classes</id>
                        <goals>
                            <goal>externalize</goal>
                            <goal>externalizeTest</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <groupId>org.apache.maven.plugins</groupId>
                <version>3.3</version>
                <configuration>
                    <source>1.5</source>
                    <target>1.5</target>
                </configuration>
            </plugin>
<!--
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <executions>
                    <execution>
                        <id>run-benchmarks</id>
                        <phase>integration-test</phase>
                        <goals>
                            <goal>exec</goal>
                        </goals>
                        <configuration>
                            <classpathScope>test</classpathScope>
                            <executable>java</executable>
                            <arguments>
                                <argument>-classpath</argument>
                                <classpath/>
                                <argument>org.openjdk.jmh.Main</argument>
                                <argument>.*</argument>
                                <argument>-wi</argument>
                                <argument>8</argument>
                                <argument>-i</argument>
                                <argument>10</argument>
                                <argument>-f</argument>
                                <argument>2</argument>
                            </arguments>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
-->
        </plugins>
    </build>
    <dependencies>
        <dependency>
            <groupId>org.apache.ant</groupId>
            <artifactId>ant</artifactId>
            <version>1.8.4</version>
        </dependency>

        <dependency>
            <groupId>com.google.android</groupId>
            <artifactId>android</artifactId>
            <version>4.1.1.4</version>
        </dependency>
        <dependency>
            <groupId>com.hazelcast</groupId>
            <artifactId>hazelcast-cloud</artifactId>
            <version>3.3.3</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.9</version>
        </dependency>

        <dependency>
            <groupId>org.openjdk.jmh</groupId>
            <artifactId>jmh-core</artifactId>
            <version>1.3.3</version>
        </dependency>
        <dependency>
            <groupId>org.openjdk.jmh</groupId>
            <artifactId>jmh-generator-annprocess</artifactId>
            <version>1.3.3</version>
        </dependency>
        <dependency>
            <groupId>commons-lang</groupId>
            <artifactId>commons-lang</artifactId>
            <version>2.5</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.jgroups</groupId>
            <artifactId>jgroups</artifactId>
            <version>3.6.3.Final</version>
        </dependency>

    </dependencies>
</project>

Help and suggestions

 If you have any questions or suggestion do not hesitate to contact us.