Using the new Java8 date / time classes with Hibernate

At the time of writing – January 2015 – neither JPA2.1 nor the actual Hibernate implementation 4.3.8.FINAL support the use of the new Java8 date and time classes as properties for an entity class. But JPA2.1 has a @Converter annotation that together with the AttributeConverter interface enables a simple solution to the problem.

(Update July 10, 2015): Hibernate 5.0.0 – currently RC2 – supports the new types without any further need for Converters; hibernate-java8 is needed on the classpath. Thanks to Paul Paulsson for the information)

I show the conversion using the java.time.LocalDate class in my entity which is converted to a java.sql.Date class to be used by Hibernate.

First we need to write a Converter implementation, I called it LocalDateConverter:

import javax.persistence.AttributeConverter;
import javax.persistence.Converter;
import java.sql.Date;
import java.time.LocalDate;

/**
 * Converter to convert from java.time.LocalDate to java.sql.Date and back.
 *
 * @author P.J.Meisch (pj.meisch@sothawo.com)
 */
@Converter
public class LocalDateConverter implements AttributeConverter<LocalDate, Date> {

    @Override
    public Date convertToDatabaseColumn(LocalDate localDate) {
        return null == localDate ? null : Date.valueOf(localDate);
    }

    @Override
    public LocalDate convertToEntityAttribute(Date date) {
        return null == date ? null : date.toLocalDate();
    }
}

In the database, I have a PERSON table which besides things like names has a column named DATEOFBIRTH which is of type DATE.

This is mapped to an Entity class Person (i omit everything but the relevant part). By annotating the getter for the property with the @Convert annotation, the conversion is automatically applied when writing or reading the property to the database.

Update: When Hibernate shall create the table according to the entity, the annotation must be written at the field, not at the getter.

/**
 * Person entity.
 *
 * @author P.J.Meisch (pj.meisch@sothawo.com)
 */
@Entity
@Table(name = "person")
public class Person implements Serializable {

    private LocalDate dateOfBirth;

    @Column(name = "dateofbirth")
    @Convert(converter = LocalDateConverter.class)
    public LocalDate getDateOfBirth() {
        return dateOfBirth;
    }

    public void setDateOfBirth(LocalDate dateOfBirth) {
        this.dateOfBirth = dateOfBirth;
    }
}

Converters for the other time classes are as easily written.

Update:

If your entity has more than one field of the given type, or more than one entities have properties of this type, you can define the Converter to autoApply:

import javax.persistence.AttributeConverter;
import javax.persistence.Converter;
import java.sql.Date;
import java.time.LocalDate;

/**
 * Converter to convert from java.time.LocalDate to java.sql.Date and back.
 *
 * @author P.J.Meisch (pj.meisch@sothawo.com)
 */
@Converter(autoApply = true)
public class LocalDateConverter implements AttributeConverter<LocalDate, Date> {

    @Override
    public Date convertToDatabaseColumn(LocalDate localDate) {
        return null == localDate ? null : Date.valueOf(localDate);
    }

    @Override
    public LocalDate convertToEntityAttribute(Date date) {
        return null == date ? null : date.toLocalDate();
    }
}

You then don’t need to specify the converter for the different properties, they are converted automatically:

/**
 * Person entity.
 *
 * @author P.J.Meisch (pj.meisch@sothawo.com)
 */
@Entity
@Table(name = "person")
public class Person implements Serializable {

    private LocalDate dateOfBirth;
    private LocalDate dateOfDeatch;

    @Column(name = "dateofbirth")
    public LocalDate getDateOfBirth() {
        return dateOfBirth;
    }

    public void setDateOfBirth(LocalDate dateOfBirth) {
        this.dateOfBirth = dateOfBirth;
    }

    @Column(name = "dateofdeath")
    public LocalDate getDateOfDeath() {
        return dateOfDeath;
    }

    public void setDateOfDeath(LocalDate dateOfDeath) {
        this.dateOfDeath = dateOfDeath;
    }
}

Run IntelliJ IDEA with actual Java version on OS X

With every update of IntelliJ IDEA, I stumble over this: IDEA wants to run on Java Version 6. As I don’t have this buggy outdated version on my Mac anymore, I always have to patch the config. To do this, locate the file named Info.plist in the Contents folder of the IntelliJ IDEA 14 CE.app directory. Open the file with TextEdit or any text editor of your choice and change the line

<key>JVMVersion</key>
<string>1.6*</string>

to

<key>JVMVersion</key>
<string>1.6+</string>

After that IJ will start using your default – hopefully actual – java version.

2015-06-21 Update: IntelliJ IDEA 15 EAP has it’s own custom Java8 built in, and also has the possibility to select the JDK to use when starting up. Cool.

mapjfx 1.3.1 and mapjfx-demo-1.3.1 released

I released version 1.3.1 of the mapjfx project to maven central. It can be found at

  <dependency>
    <groupId>com.sothawo</groupId>
    <artifactId>mapjfx</artifactId>
    <version>1.3.1</version>
  </dependency>

The source is available at GitHub.

The demo program that showcases the possibilities is available at GitHub as well. The description of the demo program shows the several features and how to use them.

Changes since 1.3.0:

  • attribution links in the map are displayed in the system’s default browser, not in the WebView
  • removed the WebView’s native context menu

Comments and contributions are welcome!

Threadsafe simple cache with two lines of code in Java 8

Sometimes you just need a small simple cache for calculated values because the value generation is expensive in time or resources. In this post I show how such a cache can be implemented in a thread safe way with the Java8 version of the ConcurrentHashMap class with just 2 lines of relevant code.

For this example I use the calculation of the n-th fibonacci number and calculate the values for there input of 1 to 20.

using no cache

The sample program and the first version of the fibonacci() method without caching are as follows:

package com.sothawo;

import java.math.BigInteger;

public class App {

    private BigInteger fibonacci(int n) {
        return (n <= 2) ? BigInteger.ONE : fibonacci(n - 1).add(fibonacci(n - 2));
    }

    public static void main(String[] args) {
        new App().run();
    }

    private void run() {
        for (int i = 1; i <= 20; i++) {
            System.out.println("fibonacci(" + i + ") is " + fibonacci(i));
        }
    }
}

This program produces the desired results, but due to the recursion there are 35.400 calls of the fibonacci() method, as already calculated values are recalculated again and again.

pre-Java 8 cache

As a cache I use a HashMap and guard it’s use with a lock object to ensure thread safety. The modified program looks like this:

package com.sothawo;

import java.math.BigInteger;
import java.util.HashMap;
import java.util.Map;

public class App {

    private Map<Integer, BigInteger> simpleCache = new HashMap<>();
    private Object simpleCacheLock = new Object();

    private BigInteger fibonacci(int n) {
        BigInteger fib;
        synchronized (simpleCacheLock) {
            fib = simpleCache.get(n);
            if (null == fib) {
                fib = (n <= 2) ? BigInteger.ONE : fibonacci(n - 1).add(fibonacci(n - 2));
                simpleCache.put(n, fib);
            }
        }
        return fib;
    }

    public static void main(String[] args) {
        new App().run();
    }

    private void run() {
        for (int i = 1; i <= 20; i++) {
            System.out.println("fibonacci(" + i + ") is " + fibonacci(i));
        }
    }
}

This works as expected and gets the number of calls to the fibonacci() method down to the minimum of 20, but is a lot of code.

Java 8 version

The ConcurrentHashMap in Java 8 has got a nice addition, the computeIfAbsent method. It takes two arguments: the key value and a function to calculate the value if not present in the cache. This leads to the following code:

package com.sothawo;

import java.math.BigInteger;
import java.util.concurrent.ConcurrentHashMap;

public class App {
    private ConcurrentHashMap<Integer, BigInteger> betterCache = new ConcurrentHashMap<>();

    private BigInteger fibonacci(int n) {
        return betterCache.computeIfAbsent(n, (i) -> (i <= 2) ? BigInteger.ONE : fibonacci(i - 1).add(fibonacci(i - 2)));
    }

    public static void main(String[] args) {
        new App().run();
    }

    private void run() {
        for (int i = 1; i <= 20; i++) {
            System.out.println("fibonacci(" + i + ") is " + fibonacci(i));
        }
    }
}

The same result as before, but with just two lines of code.

create a data URI from an URL

Recently I needed for my mapjfx project to convert an image, where I had the URL of, to a base64 encoded data-URI. The following code shows how to do the conversion (Java 8 code):

/*
 * (c) 2015 P.J. Meisch (pj.meisch@sothawo.com).
 */

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.*;
import java.util.Base64;
import java.util.logging.Level;
import java.util.logging.Logger;

public class Test {

    private static Logger logger = Logger.getAnonymousLogger();

    public static URI getDataURIForURL(URL url) {
        URI dataUri = null;
        if (null != url) {
            try (InputStream inStreamGuess = url.openStream();
                 InputStream inStreamConvert = url.openStream();
                 ByteArrayOutputStream os = new ByteArrayOutputStream()) {
                String contentType = URLConnection.guessContentTypeFromStream(inStreamGuess);
                if (null != contentType) {
                    byte[] chunk = new byte[4096];
                    int bytesRead;
                    while ((bytesRead = inStreamConvert.read(chunk)) > 0) {
                        os.write(chunk, 0, bytesRead);
                    }
                    os.flush();
                    dataUri = new URI("data:" + contentType + ";base64," +
                            Base64.getEncoder().encodeToString(os.toByteArray()));
                } else {
                    logger.warning(() -> "could not get content type from " + url.toExternalForm());
                }
            } catch (IOException e) {
                logger.log(Level.SEVERE, "error loading data from url", e);
            } catch (URISyntaxException e) {
                logger.log(Level.SEVERE, "error building uri", e);
            }
        }
        return dataUri;
    }

    public static void main(String[] args) {
        try {
            URL url = new File("test.png").toURI().toURL();
            logger.info(() -> "url: " + url.toExternalForm());
            URI dataURI = getDataURIForURL(url);
            logger.info(() -> "dataUrl: " + dataURI.toString());
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }
    }
}

The logging output is as follows (last line shortened):

Jan 05, 2015 5:22:23 PM Test main
INFORMATION: url: file:/Users/sothawo/Test/test.png
Jan 05, 2015 5:22:23 PM Test main
INFORMATION: dataUrl: data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAAAXNSR0IArs4c6QA...

x

mapjfx 1.3.0 and mapjfx-demo-1.3.0 released

I released version 1.3.0 of the mapjfx project to maven central. It can be found at

  <dependency>
    <groupId>com.sothawo</groupId>
    <artifactId>mapjfx</artifactId>
    <version>1.3.0</version>
  </dependency>

The source is available at GitHub.

The demo program that showcases the possibilities is available at GitHub as well. The description of the demo program shows the several features and how to use them.

Changes since 1.2.1:

  • added marker support
  • added singleclick feedback as JavaFX event with map coordinate

Comments and contributions are welcome!