Java: how to check jar version at runtime

Class loading issues can happen in complex execution environments. Situation gets worst when there are different versions of the same library “loaded” and we are not sure which our application is picking up.

To help debugging this issue, we could check at runtime which version of the library is loaded with the our application.

A code like the following can help:

// Example using HTMLEmail from Apache Commons Email 
Class theClass = HtmlEmail.class;
 
// Find the path of the compiled class 
String classPath = theClass.getResource(theClass.getSimpleName() + ".class").toString(); 
System.out.println("Class: " + classPath); 

// Find the path of the lib which includes the class 
String libPath = classPath.substring(0, classPath.lastIndexOf("!")); 
System.out.println("Lib:   " + libPath); 

// Find the path of the file inside the lib jar 
String filePath = libPath + "!/META-INF/MANIFEST.MF"; 
System.out.println("File:  " + filePath); 

// We look at the manifest file, getting two attributes out of it 
Manifest manifest = new Manifest(new URL(filePath).openStream()); 
Attributes attr = manifest.getMainAttributes(); 
System.out.println("Manifest-Version: " + attr.getValue("Manifest-Version")); 
System.out.println("Implementation-Version: " + attr.getValue("Implementation-Version"));

The above code shows how to find jar file path and how to read the contents of a file (it is usually the Manifest) to read some info from it.

Tutorial: using FindBugs with Maven

FindBugs can be executed using Maven in two different modes: as stand-alone command or as part of the Maven site command.

These two modes require different settings in the project pom.xml but they are not incompatible to each other so we can use both of them.

info48
You can find complete Maven project here.

Stand-alone mode

Let’s start with the stand-alone mode which requires the following configuration in the pom.xml:

<build>
    <plugins>       
        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>findbugs-maven-plugin</artifactId>
            <version>3.0.1</version>
        </plugin>
         ... other build plugins ....
    </plugins>
</build>

Please note that the FindBugs plugin definition is inside build – plugins section of the pom file.

Giving the following command:

mvn findbugs:findbugs

FindBugs is run against our project with the following log in the console output:

[INFO] --- findbugs-maven-plugin:3.0.1:findbugs (default-cli) @ CodeQualityGallery ---
[INFO] Fork Value is true
     [java] Warnings generated: 1
[INFO] Done FindBugs Analysis....

warning48
FindBugs analyze the compiled files (*.class). If the project is not compiled or just cleaned, FindBugs will report nothing, without error messages. So take care to build your project before running FindBugs.

A warnings number is reported on the console. Warnings are possible bugs found by the FindBugs detectors.

The warnings details are included in a report created in the file target/findbugsXml.xml which is in XML format and so not really readable.

A better way to examine the warnings is to use the FindBugs native GUI with the command:

mvn findbugs:gui

The FindBugs window shows the bugs on the left, the (read-only) code on the right and the bug explanation below.

FindBugs GUI

You can filter bugs for bug rank from the most critical (“scariest”) to trivial and even, saving project status, comparing project evolution (which means how may bugs has been eliminated/introduced after previous FindBugs check).

warning48All main IDEs (Eclipse, NetBeans, IntelliJ) FindBugs plugins show similar views and they can also let you modify the code so I don’t suggest to use FindBugs native GUI unless you have to create exclusion files (see below) which is easier with the native GUI: select a bug, filter it out and export bug filters.

 

Site mode

Maven site command is used to generate a project “site”, which is a collection of information on the project nicely reported in HTML pages. You can configure which information is included in the site report and, of course, you can add FindBugs analysis results.

Maven site requires a “reporting section” in the pom file.

<reporting>
    <plugins>       
        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>findbugs-maven-plugin</artifactId>
            <version>3.0.1</version>
        </plugin>
         ... other site plugins ....
    </plugins>
</reporting>

Giving the following command (note: clean and install options are in to assure that project is compiled and all tests run):

mvn clean install site

on the console output we will see the following:

.....
[INFO] --- maven-site-plugin:3.3:site (default-site) @ CodeQualityGallery ---
[INFO] configuring report plugin org.apache.maven.plugins:maven-jxr-plugin:2.5
[INFO] configuring report plugin org.apache.maven.plugins:maven-project-info-reports-plugin:2.8
[INFO] configuring report plugin org.codehaus.mojo:findbugs-maven-plugin:3.0.1
[INFO] Fork Value is true
     [java] Warnings generated: 2
[INFO] Done FindBugs Analysis....
[INFO] configuring report plugin org.apache.maven.plugins:maven-pmd-plugin:3.4
[WARNING] No project URL defined - decoration links will not be relativized!
[INFO] Rendering site with org.apache.maven.skins:maven-default-skin:jar:1.0 skin.
[INFO] Skipped "Source Xref" report, file "xref/index.html" already exists for the English version.
[INFO] Generating "Source Xref" report    --- maven-jxr-plugin:2.5
[INFO] Generating "Dependency Convergence" report    --- maven-project-info-reports-plugin:2.8
[INFO] Generating "Dependency Information" report    --- maven-project-info-reports-plugin:2.8
[INFO] Generating "About" report    --- maven-project-info-reports-plugin:2.8
[INFO] Generating "Plugin Management" report    --- maven-project-info-reports-plugin:2.8
[INFO] Generating "Project Plugins" report    --- maven-project-info-reports-plugin:2.8
[INFO] Generating "Project Team" report    --- maven-project-info-reports-plugin:2.8
[INFO] Generating "Project Summary" report    --- maven-project-info-reports-plugin:2.8
[INFO] Generating "FindBugs" report    --- findbugs-maven-plugin:3.0.1
[INFO] Generating "PMD" report    --- maven-pmd-plugin:3.4
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
.....

The “site” is created in the target/site dir. Opening the file target/site/index.html with the browser, we will see something like the following:

2015-06-08bIn the Project Reports section you will find the FindBugs report like the following:

2015-06-08c   The report is interesting because it give us the complete picture of our project in the summary section but also the list of the files which have FindBugs detected issues with all details including the priority (i.e. how dangerous could be the problem).

Configuration options

Regardless the used mode, the FindBugs plugin can be configured to modify and tune its behaviour. All below configurations should be placed in the configuration section of the plugin:

<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>findbugs-maven-plugin</artifactId>
    <version>3.0.1</version>
    <configuration>
        .....put here
    </configuration>
</plugin>

warning48
Configurations in the build and reporting sections are independent so we can have two different settings in the two modes, stand-alone and site.

Best practice is to use a light and fast configuration on the standalone mode, in order to run quick checks during development and an high effort, production quality configuration for the site mode.

Let’s examine the most important configuration options:

DEBUG: With <debug>true</debug> option, FindBugs will show what is doing during analysis. Useful to fine tune or checks the settings.

EFFORT: with  <effort>Max</effort> we can increase the time FindBugs is allowed to use to analyze the code. More effort means more accurate analysis but, of course, FindBugs run slower.

EXTERNAL PLUGINS: FindBugs can be extended with additional detectors. See my post on the topic. The  <pluginList>plugin1[, plugin2…]</pluginList> configuration option list the plugins to be used. See the sample project for a real example.

EXCLUSIONS: If you need to disable a detector or to disable the analysis on same classes, an exclude list can be specified with the <excludeFilterFile> path_to_exclude_file </excludeFilterFile> option. File syntax is documented here. An easy way to create this file is by using the FindBugs GUI which has an export filter function. See the sample project for a real example.

 

FindBugs plugins

FindBugs is a key code quality tool for Java based projects.

It includes several dozens of bug patterns which are used by FindBugs to identify potential bugs and, more in general, weaknesses in our code.

FindBugs has a plugin architecture which can be used to extend the set of detectors (bug patterns) used during the analysis.

There are few open source projects which aim to develop FindBugs plugin.

My preferred one is Fb-Contrib which contains a significant amount of additional detectors. See here for the complete list. Most of them are really useful to detect poor code quality.

Another interesting plugin is Find Security Bugs; the focus here is on security vulnerabilities (list here) like using unsecured random generator or not checking data received from the user.

Let’s have a look at versions dependencies:

JDK FindBugs FB-Contrib Find Security Bugs
7 and 8 3.x 6.x 1.3 and above
5 and 6 2.x 5.x 1.2

All plugins are released in .jar format and they can be easily added to the FindBugs :

  • FindBugs stand-alone: place the jar in the plugins dir inside FindBugs installation dir
  • Eclipse FindBugs plugin: use the plugin options to specify the plugin path or place the jar file inside FindBugs plugins dir
  • NetBeans FindBugs integration: use Custom FindBugs Plugins button inside Editor → Hints → FindBugs page.
  • IntelliJ FindBugs plugin: add new plugin in the Plugin Configuration tab.

After adding new plugins, review the list of detectors enabled. New detectors are usually added but not enabled.

April 2015 Java releases

Java 9

New Java version is under development. Preliminary JDK versions and information can be found at https://jdk9.java.net/

Java 8

Java 8 is the current Java version.

Java 8 JDK/JRE update 45 has been released. This is mainly a bug fix release. No new functionalities have been introduced.

Complete bug fix list can be found at http://www.oracle.com/technetwork/java/javase/2col/8u45-bugfixes-2494164.html

JDK 8 can be downloaded from http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html
Java 7

Java 7 79/80 is the last public release.

As happened for the latest realese, also latest Java 7 update is splitted in two releases:

  • Update 79 which includes critical security updates only
  • Update 80 which includes 79 updates plus a new command line option to detect deprecated mechanisms: endorsed-standards and extensions.

Endorsed-standards is a way to update Java core to the latest version of non Java standards. Extensions allows us to extend the Java core with new libraries and functionalities. Both mechanism have been declared deprecated and they will be phase-out in the next future. The option introduced in Java 7u80 detect if these mechanisms have been used i our environments.

Update 79 release notes can be found at http://www.oracle.com/technetwork/java/javase/7u79-relnotes-2494161.html

Update 80 release notes can be found at http://www.oracle.com/technetwork/java/javase/7u80-relnotes-2494162.html

JDK 7 can be downloaded from http://www.oracle.com/technetwork/java/javase/downloads/jdk7-downloads-1880260.html

Still using JAVA 6 and previous versions ? Have a look at  http://www.oracle.com/technetwork/java/javase/archive-139210.html

Jan 2015 Java releases

Java 9

New Java version is under development. Preliminary JDK versions and information can be found at https://jdk9.java.net/

Java 8

Java 8 is the current Java version.

Java 8 JDK/JRE update 31 has been released. In addition to several fixes, this release disables by default the SSLv3 protocol which has been found to have a design defect which cannot be solved. If you’re curios about it, have a look here.

Complete bug fix list can be found at http://www.oracle.com/technetwork/java/javase/2col/8u31-bugfixes-2389095.html

JDK 8 can be downloaded from http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html

Java 7

Latest Java 7 update is splitted in two releases:

  • Update 75 which includes critical security updates only

  • Update 76 which includes 75 updates plus some other minor updates.

Both updates disable by default the SSLv3 protocol.

Update 75 bug fixes can be found at http://www.oracle.com/technetwork/java/javase/7u75-relnotes-2389086.html

Update 76 bug fixes can be found at http://www.oracle.com/technetwork/java/javase/7u76-relnotes-2389087.html

JDK 7 can be downloaded from http://www.oracle.com/technetwork/java/javase/downloads/jdk7-downloads-1880260.html

Remember that Java 7 JDK is planned to go to end-of-life on April 2015.

Tutorial: Java abstract classes testing

In Java, abstract classes are used to define the interface of the class, with a list of (abstract) methods to be implemented by the extending class; basically what it is also possible to have with the “real” interfaces, the one defined with the interface instruction.

One significant difference between abstract classes and interfaces is that abstract classes can also have fields and non abstract methods which contain logic.

Abstract classes with code (in non abstract methods) are common in some design patterns implementations and in class hierarchy based frameworks. This is a typical solution to share code inside a class family.

Of course this code should be tested but abstract classes cannot be instantiated.

In this tutorial, we will analyze several cases and all possible alternative solutions to test abstract classes with non abstract methods. Let’s start with the libraries we will use on our tests (all Java 6 source level):

Few important remarks:

  1. Some solutions are based on Mockito version 1.10.12 or above but these versions are not compatible with the latest PowerMock version (1.6.1, see here).
    So in the project we will use two different libraries sets:

    1. Classic: jUnit 4.12, Mockito 1.10.8, PowerMock 1.6.1
    2. Latest: jUnit 4.12, Mockito 1.10.19 (no PowerMock)
  2. All examples are based on the “classic” combination except few ones marked with a special comment. In the project pom.xml, both dependencies sets are defined but one is commented out. Please note that, due to the combinations differences, some tests cannot be compiled in all combinations.
  3. Complete project can be found at https://github.com/gualtierotesta/test-solutions
  4. The examples are not real world code. The code has been kept at the minimum in order to better show the adopted testing strategy.
  5. A basic knowledge about Java unit testing and jUnit framework is needed for a more complete understanding of the examples. Mockito and PowerMock knowledge is not required.
  6. Have also a look at the Test Glossary for the meaning of several test terms used in this post.

CASE 1: independent method

This is the simplest case: the abstract class contains, in addition to abstract methods, a public non abstract method (named “methodToBeTested” in our examples) with no internal dependencies: it does not call any other method in its class.

public abstract class AbstractCase1 {
    public abstract int myAbstractMethod();
    public String methodToBeTested() {
        return "CASE-1";
    }
}

We want to test the logic of the method “methodToBeTested()”. We have three possible testing solutions:

Solution 1.A Using a concrete class

We create a concrete class which extends the abstract class and test the method from this class.

Our test class body:

     private class ConcreteCase1 extends AbstractCase1 {
        @Override
        public int myAbstractMethod() {
            return 0;  //Dummy implementation
        }
    }

    @Test
    public void testUsingConcreteClass() {
        // given
        ConcreteCase1 sut = new ConcreteCase1();
        // when
        String result = sut.methodToBeTested();
        // then
        Assert.assertEquals("CASE-1", result);
    }

Explanation:

  • Line 1: we define a concrete implementation of the abstract class where all abstract methods have a dummy implementation; they are not used so we don’t care.
  • Line 11: we create an instance named “sut” (system under test) of the concrete class. Through this instance we have free access to the method we want to test

The only drawback of this solution is the need to create the concrete class and created a dummy implementation for all abstract methods.

The given, when and then comments are used to separated different test phases: preparation, execution and results analysis. See also http://martinfowler.com/bliki/GivenWhenThen.html

Solution 1.B Using a Mockito spy (Mockito 1.10.12+ required)

We can use Mockito to create a spy instance of the abstract class. A spy is a class instance with standard behavior but that can be controlled by Mockito; for example we can ask Mockito to change the normal method return value, bypassing the return value calculated by the method body. See also the Testing Glossary.

In our case, we use a Mockito spy only because it let us create an abstract class instance, which is normally not possible. This is not a typical Mockito spy use case.

    @Test
    public void testUsingMockitoSpy() {
        // given
        AbstractCase1 sut = Mockito.spy(AbstractCase1.class);
        // when
        String result = sut.methodToBeTested();
        // then
        Assert.assertEquals("CASE-1", result);
    }

Explanation:

  • line 4: create the spy instance using Mockito.spy(class) method.
  • line 6: invoke the method to be tested

The main drawback of this solution is that Mockito.spy() will invoke the abstract class constructor during spy instance creation. In some cases the constructor uses external dependencies which can be an obstacle to our unit test executions. These kind of dependencies are usually called “test impediments”.

Solution 1.C Using Mockito mock

If you cannot use latest Mockito version or the abstract class constructor contains some test impediments, we can use Mockito to create a mock.

In general mocking is used to “empty” a class from its logic: a mocked instance does not have code insides the methods. In our case, we create a mock and then ask Mockito to restore the code inside the method we want to test.

This is not a very clean solution but it works.

    @Test
    public void testUsingMockitoMock() {
        // given
        AbstractCase1 sut = Mockito.mock(AbstractCase1.class);
        Mockito.doCallRealMethod().when(sut).methodToBeTested();
        // when
        String result = sut.methodToBeTested();
        // then
        Assert.assertEquals(&quot;CASE-1&quot;, result);
    }

Explanation:

  • line 4: create the mocked instance using Mockito.mock(class) method.
  • line 5: we ask Mockito to use real (=original) code when method is invoked

CASE 2: independent method with test impediment

In this second use case, the method we want to test calls a private method which contains a test impediment. We cannot simply execute the method to be tested because first we need to disable the test impediment method.

  public abstract class AbstractCase2 {

    public abstract int myAbstractMethod();

    public String methodToBeTested() {
        return prefix() + "2";
    }

    // Test impediment
    private String prefix() {
        return "CASE-";
    }
}

In our example, the method to be tested calls the private method “prefix()”. Note: the method body in the example is NOT a test impediment as it just returns a string. In the real world, the method performs some time and/or resource consuming tasks which should be avoided in our unit tests.
We want to “remove” prefix() standard behavior but to do this we cannot create a concrete class because private methods cannot be overridden. We cannot even use Mockito because it cannot control private (and, by the way, also static ) methods so we will use its stronger companion: PoweMock.

Solution 2.A Using PowerMock
The test class:

@RunWith(PowerMockRunner.class)
@PrepareForTest(AbstractCase2.class)
public class AbstractCase2Test {

    @Test
    public void testWithPowerMock() throws Exception {
        // given
        AbstractCase2 sut = PowerMockito.mock(AbstractCase2.class);
        PowerMockito.doCallRealMethod().when(sut).methodToBeTested();
        PowerMockito.doReturn("TESTCASE-").when(sut, "prefix");
        // when
        String result = sut.methodToBeTested();
        // then
        Assert.assertEquals("TESTCASE-2", result);
    }
}

Explanation:

  • line 1: the @RunWith annotation defines PowerMock as the runner for the test
  • line 2: the @PrepareForTest(class) annotation asks PowerMock to prepare the class for later processing
  • line 8: we create a mock using PowerMockito.mock() which, in turns, call the Mockito mock() method
  • line 9: as we did for the first use case, we ask PowerMock to re-enable the body of the method to be tested
  • line 10: here it is the key element of this test: we ask PowerMock to stub the private method return value so we can test methodToBeTested() without test impediments. Mockito alone cannot do this stub. Please note that the name of the private method, prefix, is passed to PowerMock as string because it is not accessible from outside. PowerMock will use reflection to find it.

CASE 3: method which access instance fields
Abstract classes can have an internal state implemented with class fields. The value of the fields can be significant for the test so we need a way to control them in order to define the initial test context (the “test fixture”).
If the field is public (uh, not very nice OO solution) or protected, it can be freely accessed (and modified) from our test class. But if it is private, we have few options to control it.
Let’s start with the example class:

  public abstract class AbstractCase3 {

    protected boolean type = false;
    private int count;

    public abstract int myAbstractMethod();

    public String methodToBeTested() {
        String res;
        count += 1;
        if (count > 10) {
            res = "Too many times";
        } else {
            if (type) {
                res = "Type is true";
            } else {
                res = "Type is false";
            }
        }
        return res;
    }
}

Two class fields, type and count, control the methodToBeTested() behavior. Note: this is just an example so forgive the meaningless logic.

Solution 3.A Using Mockito mock
This solution is identical to solution 1.C: we create a mock and then later we ask Mockito to re-enable the method body.

    @Test
    public void testTrueTypeWithCountLessThen10() {
        // given
        AbstractCase3 sut = Mockito.mock(AbstractCase3.class);
        Mockito.doCallRealMethod().when(sut).methodToBeTested();
        sut.type = true;
        // when
        String result = sut.methodToBeTested();
        // then
        Assert.assertEquals("Type is true", result);
    } 

Explanation:

  • line 4: create the mocked instance using Mockito.mock(class) method.
  • line 5: we ask Mockito to use real (=original) code when method is invoked
  • line 6: we fix the type field value to be true so we can test the method in this specific condition

As shown, we cannot control the count field value with this kind of solution.

Solution 3.B Using Mockito mock and a setter
Like the solution 3.A but we add a count field setter to the abstract class (not to the test class !) so we can control its value from the test class.

In the abstract class code we add the following lines:

    // Only for test
    void setCount(int pAmount) {
        this.count = pAmount;
    }

This solution is identical to solution 1.C: we create a mock and then later we ask Mockito to re-enable the method body.

    @Test
    public void testCountGreaterThen10WithSetter() {
        // given
        AbstractCase3 sut = Mockito.mock(AbstractCase3.class);
        Mockito.doCallRealMethod().when(sut).methodToBeTested();
        Mockito.doCallRealMethod().when(sut).setCount(Mockito.anyInt());
        sut.setCount(15);
        // when
        String result = sut.methodToBeTested();
        // then
        Assert.assertEquals("Too many times", result);
    } 

Explanation:

  • line 4: create the mocked instance using Mockito.mock(class) method.
  • line 5 and 6: we ask Mockito to use real (=original) code when method is invoked and also for the setter. Note the Mockito.anyInt() call which defines for which value (all, in this specific case) the real method body should be used
  • line 7: we call the count setter with a value, 15, above the condition defined inside the method (10) so we can test this code path

Of course we could also change type field value like we did in the previous solution.

Solution 3.C Using PowerMockito
If we cannot add the setter, for example because abstract class source code cannot be touched, we can use PowerMock to change class fields.

   
    @Test
    public void testWithPowerMock() {
        // given
        AbstractCase3 sut = PowerMockito.mock(AbstractCase3.class);
        PowerMockito.doCallRealMethod().when(sut).methodToBeTested();
        Whitebox.setInternalState(sut, "count", 15);
        // when
        String result = sut.methodToBeTested();
        // then
        Assert.assertEquals("Too many times", result);
    }

Explanation:

  • line 6: PowerMock Whitebox class uses reflection to control internal class contents. In our case we change to 15 the value of the count field (second argument, which should be noted it is a string).

Using Whitebox is not very common and it should be considered only for very untestable code only.

CASE 4: method which call abstract methods
This is the typical case, for example, of the Template Method design pattern (http://en.wikipedia.org/wiki/Template_method_pattern) but also other design patterns and frameworks use this solution. The non abstract method defines the global flow while the abstract method can be implemented in different ways to customize the behavior.

   public abstract class AbstractCase4 {

    public abstract int myAbstractMethod();

    public String methodToBeTested() {
        int val = myAbstractMethod();
        return "CASE-" + val;
    }
}

At line 6, the abstract method is invoked.

To test this code, we have three different solutions: extending the abstract class, using Mockito to create a mock or a spy.

Solution 4.A Using a concrete class
We can extend the abstract class, giving a convenient (for testing purposes) behavior to the abstract method:

   
    private class ConcreteCase4 extends AbstractCase4 {
        @Override
        public int myAbstractMethod() {
            return 4;  //Dummy implementation
        }
    }

    @Test
    public void testUsingConcreteClass() {
        // given
        AbstractCase4Test.ConcreteCase4 sut = new AbstractCase4Test.ConcreteCase4();
        // when
        String result = sut.methodToBeTested();
        // then
        Assert.assertEquals("CASE-4", result);
    }

Explanation:

  • line 1: ConcreteClass4 extends the AbstractClass4Test and gives a convenient implementation of the abstract methods.

Solution 4.B Using a mock with Mockito
We create a mock and we stub the abstract method:

    @Test
    public void testUsingMockitoMock() {
        // given
        AbstractCase4 sut = Mockito.mock(AbstractCase4.class);
        Mockito.doCallRealMethod().when(sut).methodToBeTested();
        Mockito.doReturn(4).when(sut).myAbstractMethod();
        // when
        String result = sut.methodToBeTested();
        // then
        Assert.assertEquals("CASE-4", result);
    }

Explanation:

  • line 6: the abstract method is stubbed with the return value we prefer for the test. Please note that, thanks to Mockito, we are stubbing a method which does not have any implementation (because it is abstract).

Solution 4.C Using a spy with Mockito (Mockito 1.10.12+ required)
Very similar to the previous use case:

   
  @Test
  public void testUsingMockitoSpy() {
        // given
        AbstractCase4 sut = Mockito.spy(AbstractCase4.class);
        Mockito.doReturn(4).when(sut).myAbstractMethod();
        // when
        String result = sut.methodToBeTested();
        // then
        Assert.assertEquals("CASE-4", result);
}

Explanation:

  • line 5: the abstract method is stubbed with the return value we prefer for the test. Please note that, thanks to Mockito, we are stubbing a method which does not have any implementation (because it is abstract).

CONCLUSIONS

Abstract classes code can present a not so short list of use cases. Each of them can be tested using different techniques and different test support libraries.

In this tutorial we went through many examples which hopefully cover many real worlds cases. If not, just let me know so I can extend this post.

 

Latest Java updates

Java 9

New Java version is under development. Preliminary JDK versions and information can be found at https://jdk9.java.net/

Java 8

Java 8 is the current Java version.

Java 8 JDK/JRE update 25 has been released. It includes security fixes only so it is suggested to be installed whenever it is possible.

Complete bug fix list can be found at http://www.oracle.com/technetwork/java/javase/2col/8u25-bugfixes-2298227.html

JDK 8 update 25 can be downloaded from http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html

Java 7

First two important news about Java 7:

Latest Java 7 update is splitted in two releases:

  • Update 71 which includes critical security updates only
  • Update 72 which includes 71 updates plus some other minor updates.

Oracle suggests to migrate to update 71 unless you are affected by problems fixed in 72 update.

Update 71 bug fixes can be found at http://www.oracle.com/technetwork/java/javase/7u71-relnotes-2296187.html

Update 72 bug fixes can be found at http://www.oracle.com/technetwork/java/javase/7u72-relnotes-2296190.html

JDK 7 update 71 and 72 can be downloaded from http://www.oracle.com/technetwork/java/javase/downloads/jdk7-downloads-1880260.html