How to crash the java compiler (JDK 8 update 112)

I have been testing java optimizations lately and I have found a bug in the Java compiler by accident. The JDK version I use is 8 update 112, which is the latest production release available at this point (Dec 28, 2016). I have just reported the bug to Oracle, hopefully they will fix it soon. I will explain in this blog post how to reproduce the bug. My computer is a MacBook Pro (i7 / 8Gb RAM / Early 2013 / OS X Yosemite).

EDIT: The bug is now confirmed: http://bugs.java.com/bugdatabase/view_bug.do?bug_id=JDK-8172106

Basically I wrote a small program that creates a big Java class with lots of unused assignments. Originally my intention was to check how the JVM would handle the performance of unused assignments (hopefully JIT would ignore them all, but I will check on that later), when I suddenly stumbled upon the bug.

Consider the source code below. This is part of my original code and I removed some pieces that are not needed to reproduce the bug:

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;

public class Main {

   public static void main(String[] args) throws IOException {

      final String folder = "/Users/hugo/temp/";
      BufferedWriter out = new BufferedWriter(new FileWriter(folder + "Performance.java"));

      out.write("public class Performance {\n");
      out.write("\tpublic static int doNothing() {\n");
      out.write("\t\tint i = 0;\n");
      for (int i = 1; i < 99999999; i++) {
         out.write("\t\ti = " + i + ";\n");
      }
      out.close();
   }
}

This code compiles correctly. If you run this code (you should change the “folder” variable first and point it to a valid folder on your computer), it will generate a file called Performance.java on your computer. This is a big source file with 1.5Gb in size.

Now if you try to compile this class:

javac Performance.java

You will get the following error message:

An exception has occurred in the compiler (1.8.0_112). 
Please file a bug against the Java compiler via the Java 
bug reporting page (http://bugreport.java.com) after checking 
the Bug Database (http://bugs.java.com) for duplicates. 
Include your program and the following diagnostic in your 
report. Thank you.
java.lang.IllegalArgumentException
   at java.nio.ByteBuffer.allocate(ByteBuffer.java:334)
   at com.sun.tools.javac.util.BaseFileManager$ByteBufferCache.get(BaseFileManager.java:325)
   at com.sun.tools.javac.util.BaseFileManager.makeByteBuffer(BaseFileManager.java:294)
   at com.sun.tools.javac.file.RegularFileObject.getCharContent(RegularFileObject.java:114)
   at com.sun.tools.javac.file.RegularFileObject.getCharContent(RegularFileObject.java:53)
   at com.sun.tools.javac.main.JavaCompiler.readSource(JavaCompiler.java:602)
   at com.sun.tools.javac.main.JavaCompiler.parse(JavaCompiler.java:665)
   at com.sun.tools.javac.main.JavaCompiler.parseFiles(JavaCompiler.java:950)
   at com.sun.tools.javac.main.JavaCompiler.compile(JavaCompiler.java:857)
   at com.sun.tools.javac.main.Main.compile(Main.java:523)
   at com.sun.tools.javac.main.Main.compile(Main.java:381)
   at com.sun.tools.javac.main.Main.compile(Main.java:370)
   at com.sun.tools.javac.main.Main.compile(Main.java:361)
   at com.sun.tools.javac.Main.compile(Main.java:56)
   at com.sun.tools.javac.Main.main(Main.java:42)

I have found bugs in the JVM before, but this is the first bug I have found on the Java compiler. You can leave your comments below.

Comparing the volatile keyword in Java, C and C++

The volatile keyword exists in some programming languages, including Java, C and C++. I want to discuss in this blog post the differences, similarities and some details that every programmer should know about this keyword and help you understand how it affects your code. My focus will be only on Java, C and C++ because those are the languages I have most experience with. Feel free to share in the comments information about how other programming languages deal with the volatile modifier.

You probably know that Wikipedia has a good article about the volatile keyword, but the article doesn’t go very deep into the language details. The goal of this blog post is to compare the languages side by side and provide a bit more knowledge to anyone who is interested in this subject.

Declaring a volatile variable in Java

In Java, you can only add the volatile keyword to class members:

public class MyClass {
   private volatile int count = 0;
   public static volatile int sum = 0;
}

Arrays can be volatile, but the elements won’t be volatile:

volatile int[] numbers = new int[10];
...
numbers[0] = 5;  // not volatile

Local variables cannot be volatile:

public void doStuff() {
   volatile int count = 0; // Error: illegal start of expression
}

Declaring a volatile variable in C and C++

In C and C++, the volatile keyword can be applied to local and global variables:

volatile int globalNumber = 0;
int* volatile pInt; // volatile pointer to nonvolatile int
volatile int* volatile pInt2; // volatile pointer to a volatile int

void doStuff() {
   volatile float localNumber = 5.0f;
}

structs can also have volatile fields:

struct A {
   volatile double n = 0.0;
};

In C++, class members can also be volatile:

class T {
   volatile long id = 0;
};

C++ also allows the volatile qualifier to be applied to return values, parameters and class methods. This is explained at the end of the post (see below).

In Java, volatile means memory visibility

When a variable is declared volatile in Java, the compiler is informed that such variable is shared and its value can be changed by another thread. Since the value of a volatile variable can change unexpectedly, the compiler has to make sure its value is propagated predictably to all other threads. Let’s consider a simple piece of code:

volatile boolean isDone = false;
public void run() {
   while (!isDone)
      doWork();
}

The isDone variable is declared volatile. If that variable is set to true by another thread, this piece of code will read the new value and immediately leave the while-loop. If we forget to add the volatile modifier to that variable, there is a good chance the loop will never finish if the variable is set to true by another thread.

If a variable is declared volatile, all threads must read its most recent written value. The JVM does not cache volatile variables in registers or other caches that are hidden from other processors. This gives visibility to the variable and is considered a weaker form of synchronization between threads.

In Java, the volatile keyword guarantees memory visibility and it is meant to be used in concurrent programming.

In C/C++, volatile means no optimizations

In C/C++, optimizations are done by the compiler. Most compilers have command line parameters that allow you to specify different levels of optimization. For example, take a look at some options from CLANG:

-O0 = no optimization
-O1 = somewhere between -O0 and -O2
-O2 = Moderate level of optimization, which enables most optimizations
-O3 = Like -O2 with extra optimizations to reduce code size

Some compiler optimizations include removing unused assignments and reordering of memory operations. This is easy to check with the gcc.goldbolt.com website, let’s take a look at a simple example:

cpp1

This code has an int variable x that receives a useless assignment on line 2. The compiler detects this issue, ignores the value 10 and decides to return 30 directly (see assembly code on the right).

The volatile keyword in C/C++ disables all optimizations on a variable. If we try the same code again, but with the volatile modifier applied to the x variable, the assembly code looks totally different:

cpp2.png

Now the useless assignment isn’t removed by the compiler and the assembly code on the right reflects exactly the source code on the left. You may ask why would someone use this kind of less efficient code. One answer is memory-mapped I/O, where Gadgets and electronic peripherals (e.g., sensors, displays, etc.) must communicate with the software in a very specific way. Optimizations could break the communication with those electronic parts.

Still in this topic, I have found an interesting difference between GCC and CLANG when it comes to optimizations and the volatile keyword. You can check it out in my previous article: a note about the volatile keyword in c++

In C/C++, the volatile keyword is NOT suitable for concurrent programming. It is meant to be used only with special memory (e.g., memory-mapped I/O).

In Java, volatile doesn’t guarantee atomicity and thread-safety

A common misunderstanding about the volatile keyword in Java is whether operations on such variables are atomic or not. The answer to this question can be YES and NO, so it depends on what the code is doing. Let me explain.

Operations are atomic if you look at individual reads and writes of the volatile variable. In other words, reading or writing a value works as if you are entering a synchronized block. So the integrity of the value is kept safe and there is no chance you will read a broken value because some other thread was still in the process of writing it.

Operations are NOT atomic if the code has to read the value before updating it. For example, consider this code:

volatile int i = 0;
i += 10;  // not atomic

The += operator isn’t atomic because operations on volatile variables perform no locking. Because there is no locking, the executing thread cannot block other threads before the operation is completed. So read-update-write sequences on volatile variables are not thread-safe in Java. Another thread could just sneak into the sequence and create a race condition.

One way of implementing atomicity in Java is to use atomic classes from the java.util.concurrent.atomic package, like AtomicInteger, AtomicBoolean, AtomicReference, etc. The previous code would look like this:

AtomicInteger i = new AtomicInteger(0);
i.addAndGet(10);  // atomic

In C/C++, volatile can be used in return types and parameters

C++ allows return types and parameters to be volatile. The following function takes a volatile int parameter and returns another volatile int:

volatile int work(volatile int x) {
  return x + 1;
}

As discussed before, the only difference the volatile qualifier makes in this case is that it won’t be optimized by the compiler. The same function without the volatile keywords would be optimized. Here is the assembly code generated by the CLANG compiler:

volatile_function

Now compare the same function without the volatile qualifiers. The assembly code is simplified:

nonvolatile_function.png

In C++, volatile can also be used in class methods, constructors and operators

C++ also allows you to use the volatile qualifier in class methods. Here is a simple example:

class MyClass {
  public:
   int normalMethod() { 
      return 1; 
    }
   int volatileMethod() volatile { 
      return 2; 
    }
};

If an instance of this class is declared volatile, then the code can only call volatile methods on that object:

int main() {
   volatile MyClass a;
   a.normalMethod();  // error: nonvolatile method cannot be called
   a.volatileMethod();  // OK 
   return 0;
}

If the instance is not volatile, then the code can call both volatile and nonvolatile methods:

int main() {
   MyClass a;
   a.normalMethod();  // OK
   a.volatileMethod();  // OK 
   return 0;
}

Conclusion

The meaning of the volatile keyword differs from language to language and this blog post briefly explains how it works in Java, C and C++.

In Java, volatile variables are meant to be used in multithreaded contexts. Threads that concurrently read a volatile variable will always read its latest value, which means the JVM will not cache the variable internally and its value will be shared across all processors.

Atomicity and thread-safety in Java are not guaranteed by volatile variables. In summary, you should use the volatile keyword if writes to the variable do not depend on its current value, or you can ensure that only a single thread ever updates the value. Besides that, there shouldn’t be other variables participating in the concurrent state of the class, otherwise you will have race conditions. Finally, remember that locking is not required for any other reason while the variable is being accessed.

In C/C++, the volatile keyword is meant to be used with special memory: manipulating I/O registers or memory-mapped hardware. All optimizations on those variables will be disabled, which means that assignments and their order will be preserved. The volatile qualifier doesn’t help us in multithreaded code.

We can finish with a table that summarizes the points discussed:

Java C / C++
Purpose Concurrent Programming Special Memory (e.g., memory mapped I/O)
What difference does it make? Adds visibility to the variable Disables optimizations on the variable
Is the operation atomic? Yes for individual reads and writes;

No if the write depends on the current value;

No
Applies to class fields local and global variables;

return types;

function parameters;

class fields and methods (C++ only);

Reading text files line by line: Java, C++ and C benchmark

I wanted to compare how Java, C++ and C perform when reading a text file line by line and printing the output. I’ve implemented some possibilities and, at the end, we can compare the speed of each execution.

Java 7 version (BufferedReader)

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;

public class Main7 {

   private static final String FILENAME = "/path/to/file.txt";

   public static void main(String[] args) throws IOException {
      File file = new File(FILENAME);
      BufferedReader br = new BufferedReader(new FileReader(file));
      for (String line; (line = br.readLine()) != null; ) {
         System.out.println(line);
      }
   }
}

Java 8 version (Stream)

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.stream.Stream;

public class Main8 {

   private static final String FILENAME = "/path/to/file.txt";

   public static void main(String[] args) throws IOException {
       try (Stream stream = Files.lines(Paths.get(FILENAME))) {
           stream.forEach(System.out::println);
       }
   } 
}

C++ (ifstream)

#include < iostream>
#include < fstream>
#include < string>

using namespace std;

int main() {
   const constexpr char* FILENAME = "/path/to/file.txt";
   ifstream file(FILENAME);

   string line;
   while (file.peek() != EOF) {
      getline(file, line);
      cout << line << '\n';
   }
   file.close();
   return 0;
}

C (FILE)

#include < stdio.h>
#include < stdlib.h>

int main(void)
{
   FILE* fp = fopen("/path/to/file.txt", "r");
   if (fp == NULL)
      exit(EXIT_FAILURE);

   char* line = NULL;
   size_t len = 0;
   while ((getline(&line, &len, fp)) != -1) {
      printf("%s", line);
   }

   fclose(fp);
   if (line)
      free(line);
   exit(EXIT_SUCCESS);
}

Performance

Below you can see how each program above performs reading a TXT file with 10,440 lines (file size is 3.5Mb).

 Version  Time
 Java 7 (BufferedReader)  0.254 seconds
 Java 8 (Stream)  0.324 seconds
 C++ (ifstream)  0.429 seconds
 C (File)  0.023 seconds

As we can see, C is by far the fastest option. I am surprised that C++ isn’t faster than Java, but this is probably because of the ifstream and std::getline() implementation. This is not the first time I see the Standard Library with performance issues compared to other languages (the regular expression implementation was the first time).

 

 

High-Quality Image Resize with Java

Learn a trick to shrink images using the Java2D API, which creates high-quality image icons for your applications.

Image resize with java isn’t a new topic. What I want to explain here is a technique to create small high-quality images using the Java2D API, since I couldn’t find any reasonable solution on the Internet. The are some solutions available – like this one – but the final quality is low.

You can use this approach for different purposes, but the best example I can think of is the implementation of small avatars on web applications (see Nabble, DZone, etc.) or desktop software (e.g., Skype, MSN, etc.).

In order to show the contribution of this technique, I have to explain image resize from the beginning. We will improve the algorithm as we go and I also assume you have some background with Java2D.

Reading and Writing the Image

Since this is a simple example, I will read an image from the file system, resize it and save it back. The image I am using is below. Note that I am using a JPG file, which is the common format for pictures.

picture

To read this image, we can use the ImageIO class:

BufferedImage image = ImageIO.read(new File("c:\picture.jpg"));

First Attempt

Now we have to find a way to resize this image. Our first attempt is to use the drawImage() method of the Graphics interface:

private static BufferedImage resize(BufferedImage image, int width, int height) {
    BufferedImage resizedImage = new BufferedImage(width, height,
    BufferedImage.TYPE_INT_ARGB);
    Graphics2D g = resizedImage.createGraphics();
    g.drawImage(image, 0, 0, width, height, null);
    g.dispose();
    return resizedImage;
}

With this method, we can create a 24×24 avatar by calling:

Image resized = resize(image, 24, 24);
The last step is to save the image so that we can see the results. The ImageIO class can do this job:

ImageIO.write(resized, “png”, new File(“c:\picture1.png”));
Note that the second parameter is the format of the saved image. I used “png” because it is simpler. If you want to save it as JPG, you will have to use the JPEGImageEncoder class (and the result is the same, trust me).

The result of this method is a low-quality image:

picture1

Pay attention to the details of the image (look closer). There is no anti-alias and the face is distorted. Would you add such algorithm to your web application? I don’t think so. Users could get scared by looking at those images.

Second Attempt

We noticed that the main problem of the resize() method above is the fact that it doesn’t have anti-aliasing. So we could use the Rendering Hints of the Java2D API as an attempt to solve that problem:

private static BufferedImage resize(BufferedImage image, int width, int height) {
    int type = image.getType() == 0? BufferedImage.TYPE_INT_ARGB : image.getType();
    BufferedImage resizedImage = new BufferedImage(width, height, type);
    Graphics2D g = resizedImage.createGraphics();
    g.setComposite(AlphaComposite.Src);

    g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
    RenderingHints.VALUE_INTERPOLATION_BILINEAR);

    g.setRenderingHint(RenderingHints.KEY_RENDERING,
    RenderingHints.VALUE_RENDER_QUALITY);

    g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
    RenderingHints.VALUE_ANTIALIAS_ON);

    g.drawImage(image, 0, 0, width, height, null);
    g.dispose();
    return resizedImage;
}

The result is below (right image). If you pay attention to the details, it is somewhat better, but still trash:

picture1picture2

Finally, The Trick

Now I will explain how to improve the quality of this image. Basically, the trick is to blur the image before resizing. The code that blurs an image in java is:

public static BufferedImage blurImage(BufferedImage image) {
    float ninth = 1.0f/9.0f;
    float[] blurKernel = {
        ninth, ninth, ninth,
        ninth, ninth, ninth,
        ninth, ninth, ninth
    };

    Map map = new HashMap();

    map.put(RenderingHints.KEY_INTERPOLATION,
    RenderingHints.VALUE_INTERPOLATION_BILINEAR);

    map.put(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
    map.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

    RenderingHints hints = new RenderingHints(map);
    BufferedImageOp op = new ConvolveOp(new Kernel(3, 3, blurKernel), ConvolveOp.EDGE_NO_OP, hints);
    return op.filter(image, null);
}

Since the original image is in the JPG format, we can’t blur it directly. We have to create a compatible image first:

private static BufferedImage createCompatibleImage(BufferedImage image) {
    GraphicsConfiguration gc = BufferedImageGraphicsConfig.getConfig(image);
    int w = image.getWidth();
    int h = image.getHeight();
    BufferedImage result = gc.createCompatibleImage(w, h, Transparency.TRANSLUCENT);
    Graphics2D g2 = result.createGraphics();
    g2.drawRenderedImage(image, null);
    g2.dispose();
    return result;
}

Blurring the image before resizing it isn’t the only trick. You have to do this when the width or height of the image is 100px. Since small avatars are usually a square (width = height), you can resize it to 100×100, call the blur() method and resize again to 24×24:

private static BufferedImage resizeTrick(BufferedImage image, int width, int height) {
    image = createCompatibleImage(image);
    image = resize(image, 100, 100);
    image = blurImage(image);
    image = resize(image, width, height);
    return image;
}

(the resize() method is the one described in the second attempt)

Now you can compare the three results:

picture1picture2picture3

Conclusion

This was my contribution to the tough problem of shrinking images using the Java2D API. I would like to remember that this isn’t the ultimate algorithm to achieve that goal, but it is good enough considering its simplicity. If you have comments or feedback, I would like to hear them.

FULL SOURCE

import sun.awt.image.BufferedImageGraphicsConfig;

import javax.imageio.ImageIO;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.AlphaComposite;
import java.awt.GraphicsConfiguration;
import java.awt.Transparency;
import java.awt.image.BufferedImage;
import java.awt.image.BufferedImageOp;
import java.awt.image.ConvolveOp;
import java.awt.image.Kernel;
import java.io.File;
import java.io.IOException;
import java.util.Map;
import java.util.HashMap;

/**
 * High-Quality Image Resize with Java
 * http://www.componenthouse.com/article-20
 *
 * @author Hugo Teixeira
 */
public class ComponentHouseResizer {

	public static void main(String[] args) {
		try {
			BufferedImage image = ImageIO.read(new File("c:\\picture.jpg"));
			ImageIO.write(resizeTrick(image, 24, 24), "png", new File("c:\\picture3.png"));
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	private static BufferedImage resize(BufferedImage image, int width, int height) {
		int type = image.getType() == 0? BufferedImage.TYPE_INT_ARGB : image.getType();
		BufferedImage resizedImage = new BufferedImage(width, height, type);
		Graphics2D g = resizedImage.createGraphics();
		g.setComposite(AlphaComposite.Src);
		g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,RenderingHints.VALUE_INTERPOLATION_BILINEAR);
		g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
		g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
		g.drawImage(image, 0, 0, width, height, null);
		g.dispose();
		return resizedImage;
	}

	private static BufferedImage resizeTrick(BufferedImage image, int width, int height) {
		image = createCompatibleImage(image);
		image = resize(image, 100, 100);
		image = blurImage(image);
		return resize(image, width, height);
	}

	public static BufferedImage blurImage(BufferedImage image) {
		float ninth = 1.0f/9.0f;
		float[] blurKernel = {
				ninth, ninth, ninth,
				ninth, ninth, ninth,
				ninth, ninth, ninth
		};

		Map<RenderingHints.Key, Object> map = new HashMap<RenderingHints.Key, Object>();
		map.put(RenderingHints.KEY_INTERPOLATION,RenderingHints.VALUE_INTERPOLATION_BILINEAR);
		map.put(RenderingHints.KEY_RENDERING,RenderingHints.VALUE_RENDER_QUALITY);
		map.put(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
		RenderingHints hints = new RenderingHints(map);
		BufferedImageOp op = new ConvolveOp(new Kernel(3, 3, blurKernel), ConvolveOp.EDGE_NO_OP, hints);
		return op.filter(image, null);
	}

	private static BufferedImage createCompatibleImage(BufferedImage image) {
		GraphicsConfiguration gc = BufferedImageGraphicsConfig.getConfig(image);
		int w = image.getWidth();
		int h = image.getHeight();
		BufferedImage result = gc.createCompatibleImage(w, h, Transparency.TRANSLUCENT);
		Graphics2D g2 = result.createGraphics();
		g2.drawRenderedImage(image, null);
		g2.dispose();
		return result;
	}

}

Using JGoodies With Other Frameworks

Learn how to combine JGoodies with other backend frameworks in your desktop application. The main problem is the need to create objects that extend the Model class while other frameworks might consider this a problem, either because they require POJOs or provide other specific rules.

If you create GUIs using the JGoodies Binding library, you will probably have to create bean classes that extend the com.jgoodies.binding.beans.Model class.

If your desktop application also uses a framework for other purposes (e.g., persistency) and you plan to use the same model object from the GUI with this framework, then you will have to make sure you don’t have conflicting requirements.

This problem is reasonably common and happens because java doesn’t allow multiple inheritance. So, any framework that is used in conjunction with JGoodies and has rules for the target object (e.g., it must be a POJO), then the implementation starts to become more complex.

Let’s discuss one possible solution for those cases where the other framework requires the object to be a POJO (e.g., Hibernate, JPA, etc.). In such cases, we can create one class for the POJO (attributes + getters + setters) and another class that wraps this POJO, which has similar methods but has the advantage to execute other actions.

Example of a POJO:

public class Student {
    private String name;
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
}

The POJO above can be used by the persistency framework without problems. Now we need a class to be used by the Binding library (GUI):

public class StudentModel extends Model {
    private Student student;

    public StudentModel(Student student) { this.student = student; }

    public String getName() { return student.getName(); }

    public void setName(String name) {
        String old = student.getName();
        student.setName(name);
        this.firePropertyChange("name", old, name);
    }
}

This isn’t a perfect solution, but solves the problem. One disadvantage is the maintenance required by the two sets of methods that access the POJO, which could be automated by a small piece of code that uses java reflection.

JGoodies Binding API: The Basics

Learn the basics of the JGoodies Binding API, which allows you to separate the application logic from UI components. This can lead to better code and strategic separation of concerns. This is the first relevant step towards the Presentation Model pattern.

The JGoodies Binding API offers a set of classes that helps the applicability of the Presentation Model pattern in java. It was developed on top of the Swing API and has some mechanisms to bind UI components to variables and objects that can be operated independently of their visual representations.

You can download the API from the JGoodies website. This and other libraries are available here. Inside the zip file you will find the source code, the documentation, examples and the JAR file you should add to your classpath to run the examples.

Now let’s study the idea behind this API. There are two basic cases that you must understand:binding components to single values and binding components to lists of objects.

Case 1 – Binding Components to Single Values

In order to better understand this binding idea, imagine that you have a boolean variable that is bound to a JCheckBox. This “connection” means that whenever we change the value of this variable, the JCheckBox reflects this change. This is also true for the opposite direction, so that when we click on the JCheckBox, the variable receives the edited value.

In this same scenario, imagine now that we bind another component to our boolean variable – say – a JToggleButton. Now there are two components that visually display the same value held by that variable. Without surprise, you can realize that whenever the boolean value is changed, both components reflect the new value. Also, if you click either on the JCheckBox or theJToggleButton, the variable and all components bound to it are immediately updated.

This technique is a fundamental step towards the creation of the View and Presentation Model classes in the Presentation Model pattern, where the UI components are kept in the former, and the variables that describe the GUI state, in the latter.

In practice, components that can be bound to a single value are those that display a single value on the screen. This includes: JLabel, JTextField, JTextArea, JCheckBox, JRadioButton,JPasswordField and JFormattedTextField.

To connect these components to a variable, we need an implementation of the ValueModel interface (package com.jgoodies.binding.value), which holds a value and keep it synchronized with the value displayed by the component. Therefore, we can change the value held by theValueModel and the component will reflect this change. In the same way, if the user edits this value through the GUI, the ValueModel will receive the provided value.

public interface ValueModel {
    Object getValue();
    void setValue(Object o);
    void addValueChangeListener(PropertyChangeListener propertyChangeListener);
    void removeValueChangeListener(PropertyChangeListener propertyChangeListener);
}

There are two ways to connect a ValueModel to a UI component. The first one is to use the static method bind() of the Bindings class (package com.jgoodies.binding.adapter):

JTextField textField = new JTextField();
ValueModel valueModel = new ValueHolder();
Bindings.bind(textField, valueModel);

Notice that we create a ValueModel using the ValueHolder class, which is the implementation that we need for this case.

The second possibility is to use a convenient class called BasicComponentFactory (found incom.jgoodies.binding.adapter), which has methods to create the components with the binding idea in mind:

ValueModel valueModel = new ValueHolder();
JTextField textField = new BasicComponentFactory.createTextField(valueModel);

It is important to remember that whenever we bind a UI component to a ValueModel, the former must understand the value held by the latter. Therefore, we can connect without problems aJCheckBox to a ValueModel that holds a Boolean object, but NOT to a ValueModel that holds aDate. If the ValueModel receives a value that cannot be handled by the component, it will throw an Exception.

Case 2 – Binding Components to Lists of Objects

The second type of binding that we can address with the JGoodies API is useful to handle lists of objects that must be displayed on the GUI. In this case the following components can be used:JComboBox, JList and JTable.

The list of objects is represented by the javax.swing.ListModel interface, which provides:

– access to the objects in the list;
– the size of the list;
– capability to observe changes in the list.

public interface ListModel {
    int getSize();
    Object getElementAt(int index);
    void addListDataListener(ListDataListener l);
    void removeListDataListener(ListDataListener l);
}

Since this interface belongs to the Swing platform, the JGoodies’ contribution was two implementations that keep things as simple as the java.util.List interface: ArrayListModel (which inherits from ArrayList and implements ListModel) and LinkedListModel (which inherits fromLinkedList and implements ListModel).

As you can notice, the ListModel interface is not aware of selected objects in the list. This is actually good because in practice there may be lists where only one object can be selected at a time and others where multi-selection is desired. Thus, the ListModel alone does not solve our binding problem.

For lists of objects that can have only one object selected at a time, we can use theSelectionInList class (com.jgoodies.binding.list package). For lists that accept multi-selection, there is no generic class to handle this situation – this will be the subject of another article.

The SelectionInList class is basically a wrapper for a ListModel and a ValueModel. TheValueModel is used here to hold a reference to the selected object in the list. Let’s se how is can be used:

ListModel listModel = new ArrayListModel();
ValueModel selectedItemHolder = new ValueHolder();
SelectionInList selectionInList = new SelectionInList(listModel, selectedItemHolder);

We can bind a SelectionInList object to a JComboBox using an adapter:

JComboBox comboBox = new JComboBox(new ComboBoxAdapter(selectionInList));

We can bind JLists using the same component factory explained before:

JList list = BasicComponentFactory.createList(selectionInList);

The case for JTables is a little bit more complex because we need a TableModel implementation with defined columns.

Here is the source code of an example: https://www.dropbox.com/s/z5e3xouoqzdrawh/JTableBinding.zip?dl=0