Category Archives: expert

Unit testing private methods

Introduction

In this article, I will contemplate the testing of private methods in unit tests. After that, I will propose a way or pattern to do it, if you must. Finally, I will show how you can generate this pattern automatically.

And yes, I will also write a takeaway section to know what you have read.

Test or not to Test Private Methods

Unit testing is usually not black-box testing. It is debatable if it ought to be or not. Practice shows that it rarely is. When we equip the tested unit with different mocks, we play around with the implementation and not the defined functionality that a black-box test should only deal with.

After setting up and injecting the mock objects, we invoke the tested methods, and these methods are usually public. In other words, the invocation of the tested system is more like a black-box test. You can say that the test setup is not a black-box test, but the actual test is.

The advantage of black-box testing is that it does not need to change if the tested module changes’ internal working. If the functionality changes, it is another story. It is easier to refactor, optimize, simplify, beautify your code if there are clean unit tests that do not depend on the implementation. If the unit tests depend on the implementation, then you cannot reliably refactor your code. As soon as you change the implementation, the test has to follow the change.

I do not particularly appreciate when the unit test cannot be black-box, but there are cases when it is unavoidable. An unusual and frequent case is when we want to test a private method. If you want to, or even God forgive, have to test a private method, it is a code smell. The method may be simple, and you can achieve the coverage of its functionality by invoking only the public API of the tested unit. You do not have to test the private method, and if you do not have to, you must not want.

Another possibility is that that the private method is so complicated that it deserves its own test. In that case, the functionality deserves a separate utility class.

Still, there is a third possibility. After all the contemplating, we decide that the private method remains inside the unit, and we want to test it.

It is a small, insignificant problem that you cannot invoke from outside, and the test is inevitably out of the unit. Some developers remove the private modifier changing the access level from private to “test-private”.

No kidding! After more than 500 technical interviews over the past ten years, I have heard many things. I regret that I did not start recording these. As I heard a few times, one of these lovely things: “test private” as a terminology instead of package-private. Two or three candidates out of the 500 said that the accessibility is test private when there is no access modifier in front of the class member. It means they said that the member can also be accessible from the unit tests. From other classes in the same package? Not so sure.

What this story suggests is that many developers struggle to test private methods. I have also seen this in many other projects.

I am not too fond of this approach because we weaken the access protection of a class member to ease testing.

A different approach is when the tests use reflection to access the class members. There are two issues with this approach. One is the suboptimal performance. The other is the bloated code. The fact that the access to the class members via reflection is slower than the direct access is usually not significant. We are talking about tests. If the test execution needs significant time, then the tests are wrong, or the project is large or has some particular testing need. Even in these cases, the reason for the slow speed is usually not the reflective access.

The bloated code, on the other hand, hinders readability. It is also cumbersome to write every time things like

Field f = sut.getClass().getDeclaredField("counter");
f.setAccessible(true);
f.set(sut, z);

when we want to set a private field, or

Method m = sut.getClass().getDeclaredMethod("increment");
m.setAccessible(true);
m.invoke(sut);

when we want to invoke a private method. The maintenance of such tests is also questionable. If the name of the method or field changes, the test has to follow. There is no significant risk of forgetting because the test will fail, but still, it is a manual editing functionality. Most of the IDEs support renaming. Whenever I rename a method or field, the IDE renames all the references to it. Not when the reference is part of a string.

There is no real solution to this issue, except when you write code that does not need the testing of private methods and fields. Still, some approaches have advantages.

Doing it with a Style

One approach is to declare a private static delegating inner class with the same name as the tested class. This class has to implement the same methods as the original tested class, and these implementations should delegate to the original methods. The class also has to implement setters and getters to all the fields.

If we instantiate this class instead of the original one, then we can invoke any method or set any field without reflective access in the test code. The inner class hides the reflective access.

The reason to name the class with the same simple name as the tested class is that the tests do not need to change this way. If a test has a code that instantiated the tested class calling new Sut() and now we start to have an inner class named Sut, then the constructor all of a sudden will refer to the inner class.

Let’s see an example. The following class is a simple example that has one public method and a private one. The complexity of the methods barely reaches the level that would rectify extensive testing, but this makes it suitable for demonstration purposes.

public class SystemUnderTest {

private int counter = 0;

public int count(int z) {
while (z > 0) {
z--;
increment();
}
return counter;
}

private void increment(){
counter++;
}

}

This file, along with the other samples, can be found in full at https://github.com/verhas/javageci/tree/1.6.1/javageci-jamal/src/test/java/javax0/geci/jamal/sample

The test itself is also very simple:

@Test
void testCounter() throws Exception {
final var sut = new SystemUnderTest();
sut.setCounter(0);
sut.increment();
Assertions.assertEquals(1, sut.getCounter());
}

The only problem with this solution that the system under test does not contain the setter, and the method increment() is private. The code, as it is now, does not compile. We have to provide an implementation of the delegating static inner class named SystemUnderTest.

The following code shows an implementation of this class, which I created manually.

private static class SystemUnderTest {
private javax0.geci.jamal.sample.SystemUnderTest sut = new javax0.geci.jamal.sample.SystemUnderTest();

private void setCounter(int z) throws NoSuchFieldException, IllegalAccessException {
Field f = sut.getClass().getDeclaredField("counter");
f.setAccessible(true);
f.set(sut, z);
}

private int getCounter() throws NoSuchFieldException, IllegalAccessException {
Field f = sut.getClass().getDeclaredField("counter");
f.setAccessible(true);
return (int) f.get(sut);
}

private void increment() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Method m = sut.getClass().getDeclaredMethod("increment");
m.setAccessible(true);
m.invoke(sut);
}

private int count(int z) {
return sut.count(z);
}
}

It is already an achievement because we could separate the messy reflective access from the test code. The test, this way, is more readable. Since we cannot avoid the reflective code, it will not get better than this as per the readability. The other issue, maintainability, however, can still be improved.

Doing it Automated

Creating the delegating inner class is relatively straightforward. It does not need much innovation. If you specify the task precisely, any cheaply hired junior could create the inner class. It is so simple that even a program can create it. It does not need the human brain.

If you tried to write a Java program from scratch that generates this code, it would be, well, not simple. Fortunately (ha ha ha), we have Java::Geci, and even more, we have the Jamal module. Jav::Geci is a code generation framework that you can use to generate Java code. The framework contains readily available code generators, but it is also open and pluggable, providing a clean API for new code generators. It does all the tasks needed for most of the code generators and lets the code generator program focus on its core business.

Code generation.

For simpler applications, when the code generation is straightforward and does not need a lot of algorithm implementation, the module Jamal can be used. Jamal is a text-based templating language, which can be extended with Java classes implementing macros. The Java::Geci Jamal module includes a code generator that parses the source files and looks for code that has the following structure:


/*!Jamal

TEMPLATE

*/

CODE HERE

//__END__

When it sees one, it evaluates the code that is written on the lines TEMPLATE using Jamal, and then it replaces the lines of CODE HERE with the result. It generates code, and if there was a generated code but is stale, it updates the code.

The code generation runs during the test execution time, which has advantages and disadvantages.

One disadvantage is that the empty code or stale code should also compile. The compilation should not depend on the up-to-date-ness of the generated code. In practice, we usually (well, not usually, rather always) can cope with it.

The advantage is that the code generation can access the Java code structures via reflection. That way, for example, the code generators can get a list of all declared fields or methods and can generate some delegating methods for them.

The Jamal module contains Java classes implementing macros that can do that. The fact that you can express the generation of the unit test delegating inner class as Jamal macros shows the tool’s power. On the other hand, I have to note that this task is somewhere at the edge of the tool’s complexity. Nevertheless, I decided to use this task as a sample because generating setter and getters is boring. I also want to avoid lazy readers asking me why to have another setter/getter generator, as it happened at some conferences where I talked about Java::Geci. Setter and getter generator is not a good example, as it does not show you the advantage. You can do that with the IDE or using Lombok or some other tool. Perhaps after reading this article, you can try and implement the setter/getter generation using Jamal just for fun and to practice.

The previous code snippets were from the class ManualTestSystemUnderTest. This class contains the manually created delegating inner class. I created this class for demonstration purposes. The other testing class, GeneratedTestSystemUnderTest contains the generated sample code. We will look at the code in this file and how Java::Geci generates it automatically.

Before looking at the code, however, I have to make two notes:

  • The example code uses a simplified version of the macros. These macros do not cover all the possible causes.
  • On the other hand, the code includes all the macros in the source file. Professional code does not need to have these macros in the source. All they need is an import from a resource file and then the invocation of a single macro. Two lines. The macros generating the delegating inner class are defined in a resource file. It is written once, you do not need to write them all the time. I will show you at the end of this article how it is invoked.

Let’s have a look at the class GeneratedTestSystemUnderTest! This class contains the following Jamal template in a Java comment:

/*!jamal
{%@import res:geci.jim%}\
{%beginCode SystemUnderTest proxy generated%}
private static class SystemUnderTest {
private javax0.geci.jamal.sample.SystemUnderTest sut = new javax0.geci.jamal.sample.SystemUnderTest();
{%!#for ($name,$type,$args) in
({%#methods
{%class javax0.geci.jamal.sample.SystemUnderTest%}
{%selector private %}
{%format/$name|$type|$args%}
%}) =
{%@options skipForEmpty%}
private $type $name({%`@argList $args%}) throws Exception {
Method m = sut.getClass().getDeclaredMethod("$name"{%`#classList ,$args%});
m.setAccessible(true);
m.invoke(sut{%`#callArgs ,$args%});
}
%}
{%!#for ($name,$type,$args) in
({%#methods
{%class javax0.geci.jamal.sample.SystemUnderTest%}
{%selector/ !private & declaringClass -> ( ! canonicalName ~ /java.lang.Object/ )%}
{%format/$name|$type|$args%}
%}) =
{%@options skipForEmpty%}
private $type $name({%`@argList $args%}) {
{%`#ifNotVoid $type return %}sut.$name({%`#callArgs $args%});
}
%}
{%!#for ($name,$type) in
({%#fields
{%class javax0.geci.jamal.sample.SystemUnderTest%}
{%selector/ private %}
{%format/$name|$type%}
%}) =
{%@options skipForEmpty%}
private void {%setter=$name%}($type $name) throws Exception {
Field f = sut.getClass().getDeclaredField("$name");
f.setAccessible(true);
f.set(sut,$name);
}

private $type {%getter/$name/$type%}() throws Exception {
Field f = sut.getClass().getDeclaredField("$name");
f.setAccessible(true);
return ($type)f.get(sut);
}
%}
{%!#for ($name,$type) in
({%#fields
{%class javax0.geci.jamal.sample.SystemUnderTest%}
{%selector/ !private %}
{%format/$name|$type%}
%}) =
{%@options skipForEmpty%}
private void {%setter/$name%}($type $name) {
sut.$name = $name;
}

private $type {%getter/$name/$type%}() {
return sut.$name;
}
%}
}
{%endCode%}
*/

In this code the macro start string is {% and the macro closing string is %}. It is the default setting when Java::Geci starts Jamal to process a source file. This way, the macro enhanced template can freely contain standalone { and } characters, which is very common in Java. Macros implemented as Java code use the @ or the # character in front of the macro name. If there is no such character in front of the macro name, then the macro is user-defined from a @define ... macro.

The text of the template contains three parts:

  1. the start of the code,
  2. four loops, and
  3. the end of the generated code in the template (this is just a closing } character).

The start of the template

{%@import res:geci.jim%}\
{%beginCode SystemUnderTest proxy generated%}
private static class SystemUnderTest {
private javax0.geci.jamal.sample.SystemUnderTest sut = new javax0.geci.jamal.sample.SystemUnderTest();

imports the macro definitions from the resource file geci.jim. The file itself is part of the library. If you have the dependency on the classpath when the code generator and the Jamal processor runs, you can import the definition from this resource file. The macro definitions in this file are simple Jamal macros defined as text. You can have a look at them at the URL

https://github.com/verhas/javageci/blob/1.6.1/javageci-jamal/src/main/resources/geci.jim

The next line uses the beginCode user-defined macro, which is defined in geci.jim as the following:

{%@define beginCode(:x)=//<editor-fold desc=":x">%}

When this macro is used it will result the start of an editor fold that helps to keep the generated code non-intrusive when the file is opened in the IDE. When this macro is evaluated, it will be

//<editor-fold desc="SystemUnderTest proxy generated">

The next two lines start the private static inner class. It is just plain text; there is no macro in it.

Now we get to the four loops that generate proxy codes for

  1. Delegating proxy methods for the private methods of the tested class.
  2. Delegating proxy methods for the non-private methods declared in the class or inherited, except those inherited from the Object class.
  3. Setter and getter methods for the private fields of the tested class.
  4. Setter and getter methods for the non-private fields of the tested class.

Since these are very similar, I will discuss here only the first in detail.

{%!#for ($name,$type,$args) in
({%#methods
{%class javax0.geci.jamal.sample.SystemUnderTest%}
{%selector private %}
{%format/$name|$type|$args%}
%}) =
{%@options skipForEmpty%}
private $type $name({%`@argList $args%}) throws Exception {
Method m = sut.getClass().getDeclaredMethod("$name"{%`#classList ,$args%});
m.setAccessible(true);
m.invoke(sut{%`#callArgs ,$args%});
}
%}

The loop is constructed using a for macro, a Java-implemented, built-in macro of Jamal from the core package. This macro is always available for any Jamal processing. This macro iterates through a comma-separated list and repeats its contents for each list element replacing the loop variables with the actual values. There can be more than one loop variable. In such a case, like in our example, the actual value is split up along the | characters. The comma used as a list separator, and the values separator | can be redefined. In the above case, the for loop uses three-loop variables, $name, $type`, and$args. The start with a$` sign has no significance. Any string can be used as a loop variable.

The list of values is between the () characters after the in keyword. This list is the result of the evaluation of the methods built-in macro. This macro is implemented in Java and is part of the Java::Geci Jamal module. It is not a generally available Jamal macro, but when we run the code generation of Java::Geci, this JAR file is on the classpath, and thus this macro is available.

The methods macro lists the methods of a class.

The class name is taken from the user-defined macro $class, which can be defined using the user-defined macro class. The listing also considers a selector expression that can be used to filter out some of the methods. It is also provided in a user-defined macro, and there is also a helper macro in geci.jim to define it, named selector. In the example above, the selector expression is private, which will select only the private methods.

When the list is collected, the macro methods must convert it to a comma-separated list. To do that, it uses a formatting string that can contain placeholders. In our case, the placeholders are $name, $type, and $args. Every element in the list for the for loop will contain these three strings for the listed methods separated by two | characters as indicated by the format string.

The part after the = sign in the for loop is repeated for each method. It will declare a private method that invokes the same method of the tested method. To do that, it uses the help of the Java::Geci Jamal module provided built-in macros argList, classList, and callArgs. These help generating code that declares the arguments, lists the classes of the argument types or lists the arguments for the actual call.

Since this is just an article and not a full-blown documentation of Java::Geci and Jamal, I skip some details. For example, why the macro for uses the # character in front of it instead of @, why there is a backtick character in front of the macros in the loop’s body, and why the for loop uses a ! character. These details control the macro evaluation order. The list of the methods needs to be created before the for loop starts because it requires the method list. On the other hand, the macros in the loop’s body have to be evaluated after the loop generated the text for every listed method.

Also, note that this implementation is for demonstration purposes only. It simplifies the problem and does not cover all the corner cases. For example, it will generate a setter for a final field.

If you want to use this code generation, you can use the macro proxy(KLASS) defined in the resource file res:unittestproxy.jim.

You can have a look at the class UnitTestWithGeneratedUnitTestProxy, which is a tad more complex than the sample and tests these macros. The start of the generated code is the following:

/*!jamal
{%@import res:unittestproxy.jim%}\

{%beginCode SystemUnderTest proxy generated%}
{%proxy javax0.geci.jamal.unittestproxy.TestSystemUnderTest%}
{%endCode%}
*/

It merely imports the res:unittestproxy.jim file, which imports geci.jim and then uses the macro proxy to generate all the needed code covering all the corner cases.

If you want to use the code generator in your code, you have to do two things:

A. Include the dependency in your pom.xml file:

<dependency>
<groupId>com.javax0.geci</groupId>
<artifactId>javageci-jamal</artifactId>
<version>1.6.1</version>
<scope>test</scope>
</dependency>

B. Create a small unit test that runs the code generator:

@Test
@DisplayName("run the Jamal generator")
public void testRunJamalGenerator() throws Exception {
Geci geci = new Geci();
Assertions.assertFalse(
geci.register(new JamalGenerator())
.generate()
, geci.failed()
);
}

The generator runs during the unit test. During the test run, it has access to the structure of the Java code via reflection. The Jamal macros like methods, fields can query the different classes and provide the list of the methods and fields. The test fails if there was any new code generated. It only happens when the code generator runs the first time or when the tested system has changed. In this case, the test fails because the compiled code during the execution is not the final one. In such a case, start Maven again, and the second time the compilation already runs fine. Do not forget to commit the changed code. There is no risk of failing to update the generated code, like in IDE provided code generation that you have to invoke manually.

Takeaway

What you should remember from this article:

  • Try not to test private methods. If you feel the need, you did something wrong. Probably. Possibly not.
  • If you test private methods arrange the reflective code into a private static class that delegates the call to the original class. This will remove the implementation of the reflective access from the test and the test remains what it has to be: functionality test.
  • If you are a lazy person, and as a good programmer you have to be, use a Java::Geci and Jamal to generate these inner classes for your tests.
  • Master Java::Geci and Jamal and use them to generate code for your other, specific needs.

Hacking the IntegerCache in Java 9

Five years ago I published an article in Hungarian about how to alter the IntegerCahe in the JDK. Doing that is essentially hacking the Java run-time and there is no practical advantage unless while you develop the hacking code you get a better understanding how reflection works and how the Integer class is implemented.

The Integer class has a private nested class named IntegerCache that contains Integer objects for the int values -127 to 128. When the code has to box an int to Integer and the value is within this range then the run-time uses the cache instead of creating new Integer object. This is done for speed optimization reasons bearing in mind that the int values in programs are many times in this range (think about array indexing).

The side effect of this is that many times using the identity operator to compare two Integer objects may work so long as long the value is in the range. This is typically during unit test. In operational mode, when some of the values get bigger than 128 the code fails.

Hacking the IntegerCache using reflection may also lead to mysterious side effects and note that this is something that has its effect on the whole JVM. If a servlet redefines the small Integer cached values then all other servlets running in the same Tomcat under the same JVM will suffer.

There are other articles about it on the net from Lukas Eder

Add Some Entropy to Your JVM

and on the excellent blog site Sitepoint:

https://www.sitepoint.com/10-things-you-didnt-know-about-java/

Now that I started to play around with Java 9 early access version it came to my mind if I can do the same hacking with the new version of Java. Before starting that let’s refresh what we did with Java 8.

Lukas in his article displays a sample code, I copy here:

import java.lang.reflect.Field;
import java.util.Random;
 
public class Entropy {
  public static void main(String[] args) 
  throws Exception {
 
    // Extract the IntegerCache through reflection
    Class<?> clazz = Class.forName(
      "java.lang.Integer$IntegerCache");
    Field field = clazz.getDeclaredField("cache");
    field.setAccessible(true);
    Integer[] cache = (Integer[]) field.get(clazz);
 
    // Rewrite the Integer cache
    for (int i = 0; i < cache.length; i++) {
      cache[i] = new Integer(
        new Random().nextInt(cache.length));
    }
 
    // Prove randomness
    for (int i = 0; i < 10; i++) {
      System.out.println((Integer) i);
    }
  }
}

The code gets access to the IntegerCache via reflection and then fills the cache with random values. Naughty.

We can try to execute the same code in Java 9. Do not expect much fun though. Java 9 is more serious when somebody tries to violate it.

Exception in thread "main" java.lang.reflect.InaccessibleObjectException:
  Unable to make field static final java.lang.Integer[]
  java.lang.Integer$IntegerCache.cache
  accessible: module java.base does not "opens java.lang" to unnamed module @1bc6a36e

We get an exception that did not exist in Java 8. It says that object is not accessible because the module java.base, which is the part of the run-time of the JDK that is automatically imported by each Java program does not ‘opens’ (sic) the module to the unnamed module. It is thrown from the line where we try to set the field accessible.

The object we could easily access in Java 8 is not accessible any more, because the module system protects it. A code can only access fields, methods, and other things using reflection only if the class is in the same module, or if the module opens the package for reflective access for the world or for the module that needs the access. This is done in the module-info.java module definition file, like

module myModule {
    exports com.javax0.module.demo;
    opens com.javax0.module.demo;
}

The module java.base does not open itself for reflective access for us and especially not for the unnamed module, which is the code that we run. If we create a module for our code and name it then the error message will contain the name of that module.

Can we open the module programmatically? There is an addOpens method in the java.lang.reflect.Module module. Will it work?

Bad news for the hackers that it will not. It can only open a package in a module to another module if that package is already opened for the module calling this method. That way modules can pass on to other modules the right that they already have to access some packages in a reflective way but can not open things that are not open.

But the same time it is a good news. Java 9 is not so easily hackable like Java 8 was. At least this little hole is closed. It seems that Java starts to be professional grade and not to be a toy. Soon the time will come when we can migrate serious programs from RPG and COBOL to Java. (Sorry for the joke.)

UPDATE

After the article was republished on DZONE Peter Runge pointed out that the module system in this case still can be neglected using sun.misc.Unsafe class. Based on his suggestion the whole hack is here:

public class IntegerHack {

    public static void main(String[] args)
            throws Exception {
        // Extract the IntegerCache through reflection
        Class usf = Class.forName("sun.misc.Unsafe");
        Field unsafeField = usf.getDeclaredField("theUnsafe");
        unsafeField.setAccessible(true);
        sun.misc.Unsafe unsafe = (sun.misc.Unsafe)unsafeField.get(null);
        Class<?> clazz = Class.forName("java.lang.Integer$IntegerCache");
        Field field = clazz.getDeclaredField("cache");
        Integer[] cache = (Integer[])unsafe.getObject(unsafe.staticFieldBase(field), unsafe.staticFieldOffset(field));
        // Rewrite the Integer cache
        for (int i = 0; i < cache.length; i++) {
            cache[i] = new Integer(
                    new Random().nextInt(cache.length));
        }

        // Prove randomness
        for (int i = 0; i < 10; i++) {
            System.out.println((Integer) i);
        }
    }
}

Final volatile

I was writing my book over the weekend and I was looking for some simple example that could demonstrate the real need of volatile modifier in multi-thread code. Years ago when I last time demonstrated the multi-thread capability Java was still 32-bit, or at least there was 32-bit Java available. On 32 bits you could concurrently increment long variables and because the lower and upper 32 bits were handled in different processor shift there was a chance that two threads garbled some way the non-volatile variable. Now with Java 9 this is not the case. Now Java is 64-bit and I had to demonstrate the need for a volatile on 64-bit before anyone comes up the stupid idea that it was only needed for 32-bit. (I could tell stories, but I try to keep it a professional blog. Not with much success, but still.)

I was searching stackoverflow and found this page that contains many meaningless, or less than usable answer (which clearly demonstrates that the topic is not simple) but it also contains a sample from Jed Wesley-Smith that inspired my demonstrating code for the book:

package packt.java9.by.example.thread;

public class VolatileDemonstration implements Runnable {
    private Object o = null;
    private static final Object NON_NULL = new Object();
    @Override
    public void run() {
        while( o == null );
        System.out.println("o is not null");
    }
    public static void main(String[] args)
                           throws InterruptedException {
        VolatileDemonstration me = new VolatileDemonstration();
        new Thread(me).start();
        Thread.sleep(1000);
        me.o = NON_NULL;
    }
}

This code will never finish, unless you convert the field o volatile. We also need the 1000ms sleep to allow the JIT to optimize the code of the method run() after which it never reads the variable o ever again. The JIT assumes intra-thread semantics and takes the liberty to optimize the code that way. (Java Language Specification 17.4.7)

But what happens if you have a field that you can not convert to volatile? What? Can’t you just write the keyword volatile in front of the type Object? Perhaps I was giving too much hint in the title of the article…

A final field can not be volatile. Of course: a final can not change, there is no point to re-read it from the main memory and waste CPU cycles for the synchronization of any change of it between the CPU caches. But that is not true.

Final variables can be changed once.

This is something that novice Java developers tend to forget. When an object is created any final field has the zero value. In case of an object this value is null. The field has to get its final value until the end of the initialization process, that is until the end of the execution of the constructor (any constructor). Look at the following code:

package packt.java9.by.example.thread;

public class VolatileDemonstration implements Runnable {
    private final Object o;
    private static final Object NON_NULL = new Object();
    @Override
    public void run() {
        while( o == null );
        System.out.println("o is not null");
    }

    public VolatileDemonstration() throws InterruptedException {
        new Thread(this).start();
        Thread.sleep(1000);
        this.o = NON_NULL;
    }
}

The constructor starts the new thread, sleeps and then sets the field that can not be volatile. What is the solution?

What solution? There is no solution! This is a demonstration code. Just don’t write code that does things like this: that is the solution. OK?

Takeaway

What can we learn from this? Not all of the followings can be directly implied from the above, but they are all related to the phenomenon. I could write a longer article leading to any of the followings but it would have only abused your patience.

Juniors

  • Final fields can be changed once. It is not true that they are not changing never (sic).
  • A thread may read the value of a final field once and it may not read it ever again. If the JVM runs for years the thread may keep the value in the thread context in some registry or CPU cache for years as long as it likes.
  • Never let this escape from the constructor.
  • Among other more trivial things the “never let this escape from the constructor” also means not to pass it as argument to a method that can be overridden or not under the control of the programmer, who is responsible for the current class.
  • Write well behaving code or else you will suffer the slings and arrows of your outrageous program.

Seniors

  • See the takeaways for juniors and teach them.
  • You have a nice brain twister code for education.
  • Java is not a perfect language allowing such constructs. But do not tell juniors. When they realize it they are already seniors and then it is just too late.
  • The solution is a liquid mixture in which the minor component is uniformly distributed within the major component.