Skip to content
hantsy edited this page Apr 14, 2017 · 5 revisions

Aligned with Java 8

There are lots of features added into Java 8, such as new DateTime(JSR310), Streams, etc.

But Java EE 7 is designated to Java 7.

Nowdays, most of application servers, such as Glassfish, Wildfly are compatilble with Java 8, thus means you can use Java 8 language syntax in codes directly, such as function programming features, Lambda, Function etc. But we have to wait for the official supports for new APIs added in Java 8 DateTime, Streams in the next Java EE 8 specifications.

JAXRS 2 and JPA 2.1 provides simple extention APIs, thus we can define our Converters to process Java 8 DateTime types.

Hibernate 5.2 supports Java 8 natively, including Java 8 DateTime APIs as data type, and Streams API for query.

DateTime support in REST APIs

JAXRS provides a ParamConverterProvider to convert presentational string to target object type of the backend bean.

The following is an example of processing Java 8 LocalDateTime.

@Provider
public class CustomBeanParamProvider implements ParamConverterProvider {

    @Override
    public <T> ParamConverter<T> getConverter(Class<T> rawType, Type genericType, Annotation[] annotations) {
        if (rawType.getName().equals(LocalDateTime.class.getName())) {
            return (ParamConverter<T>) new LocalDateTimeParamConverter();
        }
        return null;
    }

    /**
     * datetime format:2016-08-19T10:45:33.100Z
     */
    public static class LocalDateTimeParamConverter implements ParamConverter<LocalDateTime> {

        public LocalDateTimeParamConverter() {
        }

        @Override
        public LocalDateTime fromString(String value) {
            return value == null ? null : LocalDateTime.ofInstant(Instant.parse(value), ZoneId.systemDefault());
        }

        @Override
        public String toString(LocalDateTime value) {
            return value == null ? null : value.atZone(ZoneId.systemDefault()).toInstant().toString();
        }
    }

}

@Provider annotation will tell JAXRS container to register ParamConverterProvider automaticially at runtime.

With this converter, a LocalDateTime object can be converted to standard Javascript Date JSON string in presentational view, eg, 2016-08-19T10:45:33.100Z. which can be recognized by Javascript without any extra steps in client browsers.

Follows the aboving codes, it is easy to add others Java 8 DateTime type supports, such as OffsetDateTime, LocalDate etc.

DateTime in JPA

Currently the data types can be applied on fields of an Entity are based on Java 7, Java 8 DateTime types are not supported.

But JPA 2.1 provides a simple AttribureConveter APIs to convert the JPA unknown type to existed JPA Type, and inverse. More details about JPA AttributeConverter, read my early post about JPA 2.1: Attribute Converter.

The following is an example for converting between Java 8 LocalDate and java.sql.Date.

@Converter(autoApply = true)
public class LocalDateConverter implements AttributeConverter<LocalDate, Date> {

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

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

}

In the Entity class, you can declare a LocalDate type field directly like other @Basic fields.

private LocalDate createdDate;

Before it is persisted into database, it will be converted to java.sql.Date which is supported by JPA 2.1. And when read its value from database, it will be converted to expected LocalDate type before it is returned to users.

Hibernate 5.2

In Hibernate 5.2, Java 8 support(hibernate-java8) is merged into hibernate-core artifact, it means Java 8 is supported by default.

Wildfly 10 ships Hibernate 5.1.x, you have to upgrade to Hibenate 5.2 to experience this feature.

Follows Upgrade Hibernate in Wildfly to upgrade to Hibernate 5.2.

  1. Download a copy of JBoss Module ready Hibernate distribution.

  2. Unzip it into Wildfly moudles root folder.

  3. Modify persistence.xml content of the project, declare to use Hibernate 5.2 as its JPA provider.

    <property name="jboss.as.jpa.providerModule" value="org.hibernate:5.2" />

Now Hibernate 5.2 is ready for use.

Java 8 DateTime

In the last section, Java 8 DateTime can be supported by customsizing Java 8 DateTime type converters via JPA 2.1 attribute converters.

With Hibernate 5.2, these converters can be removed. No need extra helpers for Java 8 DateTime type, it is supported by default.

private LocalDateTime createdDate;

That is all.

Streams API

Java 8 Streams API provides fluent APIs for mapping, filtering, reducing, etc.

public Stream<T> stream() {
	CriteriaBuilder cb = this.entityManager().getCriteriaBuilder();
	CriteriaQuery<T> q = cb.createQuery(entityClass());
	Root<T> c = q.from(entityClass());
	
	Session session = this.entityManager().unwrap(Session.class);
	return session.createQuery(q).stream();
}

Hibernate Query related APIs add Stream capability.

Firstly you should unwrap entityManager to Hibernate specific Session.

Then use Stream APIs as normal Java 8 Streams APIs.

public Optional<User> findOptionalByUsername(String username) {
	return stream().filter(u -> u.getUsername().equals(username)).findFirst();
}

NOTE: Stream APIs are converted into SQL at runtime, NOT just converts the query results into Stream object simply. And you have to use Java 8 Stream APIs in an opended Session.

Optional

Similarly, Hibernate Session provides methods to return an Optional object.

public Optional<T> findOptionalById(Long id) {
	Session session = this.entityManager().unwrap(Session.class);
	return session.byId(entityClass()).loadOptional(id);
}

##Source codes

Checkout the codes from my github.com account.

git clone https://github.com/hantsy/angularjs-ee7-sample

The cdi variant includes Java 8 features described in this post.

Clone this wiki locally