2

I am coding an API interface in Java, and I would like to add a method that the client will use to check if the version used by the server is the same.

I could add a thing like final String VERSION = "v1.2.3"; but I want to be sure that the version is always up to date.

I want to prevent the fact that the filed may not be updated.

I am searching something like class hash compute at runtime (or even at compilation time in maven that may generated a resource file with the hash).

As I am using git, maybe Git can update a special tag in the file with its commit hash and at runtime I return a hashCode for every source involved into the API?

How can I do something like that ?

nwinkler
  • 52,665
  • 21
  • 154
  • 168
iXô
  • 1,133
  • 1
  • 16
  • 39
  • RC, I am already using the git maven plugin that write the git hash into a resource file. But my problem is that the classes involved into the api may not be every classes into the artefact. I would like to create a thing like a hash of some few classes, at compilation time, or compute it a runtime giving to the algorithm a list of class. – iXô Jul 30 '15 at 09:34
  • I see, maybe http://stackoverflow.com/questions/9275780/is-it-possible-to-have-sha1-digest-in-java-manifest-file-without-actually-using (close vote retracted) –  Jul 30 '15 at 09:45
  • Note that you should probably consider all your API class as a whole and version that, this will smooth the client<>server version check –  Jul 30 '15 at 09:48

3 Answers3

1
  1. Create a class similar to this:
package com.company;

import java.io.IOException;
import java.util.Properties;

public class VersionHelper
{
    static Properties versionProps=new Properties();

    static
    {
        try
        {
            versionProps.load(VersionHelper.class.getResourceAsStream("/version.properties"));
        }
        catch (IOException e)
        {
            System.err.println("Version von "+VersionHelper.class.getName()+" kann nicht ermittelt werden");
        }
    }

    public static String getArtifactId()
    {
        return versionProps.getProperty("artifact");
    }

    public static String getVersion()
    {
        return versionProps.getProperty("version");
    }

    public static String getBuild()
    {
        return versionProps.getProperty("build");
    }

    public static String getBuildTimeStamp()
    {
        return versionProps.getProperty("buildTimestamp");
    }
}
  1. create the file version.properties in .../src/main/resources. This is the maven default directory for resources.

    artifact=${project.artifactId}
    version=${project.version}
    buildTimestamp=${build.timestamp}
    build=${buildNumber}
    
  2. add these properties to pom.xml

<properties>
    <!-- look at http://rterp.wordpress.com/2012/03/16/stamping-version-number-and-build-time-in-properties-file-with-maven/ -->
    <build.timestamp>${maven.build.timestamp}</build.timestamp>
    <maven.build.timestamp.format>dd.MM.yyyy HH:mm</maven.build.timestamp.format>
</properties>
  1. add this to the <build> section in pom.xml:

    <resources>
        <resource>
            <directory>src/main/resources</directory>
            <filtering>true</filtering>
        </resource>
    </resources>
    
  2. then you can use the get methods from VersionHelper in your project

JimHawkins
  • 4,843
  • 8
  • 35
  • 55
  • Thanks. I already to that, but build timestamp can't be used, and we can have multiple developer that build the same api on different computer, different time, and still use the same api. Artefact version could be forgottent to be updated (and during snapshot life cicle even more). I will finaly use git commit hash, it may envolve class that are not important for the api, but it is the simplest way to do it. – iXô Jul 30 '15 at 11:36
0

Ok, so this is my solution, it is surely not the most efficient way to do it, but it does the trick :

In my pom.xml, i have added this :

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-antrun-plugin</artifactId>
    <version>1.8</version>
    <executions>
        <execution>
            <phase>generate-resources</phase>
            <configuration>
                <target>
                    <macrodef name="gitlog">
                        <attribute name="lfile" />
                        <sequential>
                            <local name="gitHash"/>
                            <exec executable="git" outputproperty="gitHash">
                                <arg value="log" />
                                <arg value="--format=%H" />
                                <arg value="-n" />
                                <arg value="1" />
                                <arg value="--" />
                                <arg value="@{lfile}" />
                            </exec>
                            <concat append="true" destfile="target/classes/api_hashes.txt">@{lfile}:${gitHash}${line.separator}</concat>
                        </sequential>
                    </macrodef>

                    <loadfile property="api.classes" srcFile="api_classes.txt" />

                    <delete file="target/classes/api_hashes.txt"/>
                    <ac:for list="${api.classes}" param="classFile" delimiter="|" xmlns:ac="antlib:net.sf.antcontrib">
                        <sequential>
                            <gitlog lfile="@{classFile}" />
                        </sequential>
                    </ac:for>
                </target>
            </configuration>
            <goals>
                <goal>run</goal>
            </goals>
        </execution>
    </executions>
    <dependencies>
        <dependency>
            <groupId>ant-contrib</groupId>
            <artifactId>ant-contrib</artifactId>
            <version>1.0b3</version>
            <exclusions>
                <exclusion>
                    <groupId>ant</groupId>
                    <artifactId>ant</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>
</plugin>

My api_classes.txt file contain a list of classes file (source) separated by the char | (was unable to use cariage returns) in one line, and it generate a file containing a liste of source, the char : and the last git hash for earch source.

iXô
  • 1,133
  • 1
  • 16
  • 39
0

I may not understand your question exactly. Perhaps this helps some..

Since comments reveal that you are using Maven, take a look at the buildnumber-maven-plugin here. Some fine examples of usage are given here also. I've been able to use this without too much trouble and it has fit the bill very nicely for me. I like to go one step further and create a page footer that exposes the build number on every page that my web application displays, for purposes of knowing exactly which version is in use if I get a complete screenshot with a trouble ticket.

unigeek
  • 2,656
  • 27
  • 27
  • In fact, a modification in the api artefact, may not reveal a api compatibility error, depending one what is modified. If I use the last git commit hash by using buildnumber plugin, even the smallest modification would fire an api version difference. I wanted to be able to specify a list of classes that are neeeded for the api. – iXô Jul 30 '15 at 14:18
  • You are correct. This idea isn't for you then unless maybe you could benefit from packaging your artifacts into, say, an interface jar and an implementation jar. Then you might be able to notice the change in the hash on just the interface jar--that might be useful and may not be a bad strategy at any rate. – unigeek Jul 30 '15 at 14:27
  • Yes indeed, I should separate code, but I was to lazy to do so, but not enough to try to find the ant-run solution I've created :p – iXô Jul 30 '15 at 14:36