Hibernate Ignores Entity Listeners

I switched a codebase from EclipseLink as JPA provider to Hibernate and found out that with Hibernate you can not use inheritance in event listener classes. The JPA specs do not go into much detail on this topic so JPA providers are bound to handle this different from one another.

I separated my entity listeners from my entities even though it is possible to add methods annotated with e.g. @PostPersist directly in the entity class. The entity listeners themselves were less than trivial but only slightly so: I created a generic base class for all entity listeners and specialized subclasses for each entity.

public class EntityListenerBase<T> {
	@PostPersist
	public void postPersisted(T object) {
		SomeEventBus.sendEvent(createPostPersistEvent(object));
	}
	
	protected abstract Event createPostPersistEvent(T object);
}

public class ThingEntityListener extends EntityListenerBase<Thing> {
	@Override
	protected Event createPostPersistEvent(Thing thing) {
		return new ThingAdded(thing);
	}
}

Adding the entity listeners to the entity is straight-forward: Just add the @EntityListeners annotation to the entity and point it to the listener.

@Entity
@EntityListeners(ThingEntityListener.class)
public class ThingEntity implements Thing {
	…
}

EclipseLink had no trouble at all using event listeners like these. The problems started after I switched the JPA provider to Hibernate: at some point I realized that apparently the app was not generating any events anymore in response to persistence events. It was like the entity listeners weren’t even there!

After a longer debugging session into how Hibernate manages its event listeners I discovered that my previous approach for the event listeners was no longer viable, for two reasons.

The first reason is that Hibernate insists on the annotated event methods being declared directly in the entity listener class. Methods inherited from super classes are not scanned for event annotations! This is different from the behaviour when methods in the entity class itself are annotated; in that case, super classes annotated with @MappedSuperclass would be used to locate event listener methods as well. However, this is not the case for entity listener classes.

Upon moving the postPersisted method down to the subclass I stumbled upon the second reason: for every event annotation Hibernate only allows a single method in the entity listener class to be annotated with it. Now, because the original postPersisted method has a generic parameter and the subclass has a fixed type parameter, the compiler creates two versions of the method, one with Object as the parameter type, and one with the actual type I want, Thing. One of the methods is marked as synthetic but both get the annotation, and Hibernate doesn’t like that. Not. One. Bit.

So, the solution is simple, even if it means a little bit of code duplication over all the entity listeners: just remove the type hierarchy from the event listeners.

public class ThingEntityListener {
	@PostPersist
	public void postPersist(Thing thing) {
		SomeEventBus.sendEvent(new ThingAdded(thing));
	}
}

One could argue that this is actually even better; less class hierarchy, and all relevant listener methods are right there in the class, increasing visibility and reducing complexity.

Help! My Java Locale is Wrong in JDK11!

We discovered this issue when a user from the Netherlands reported that, upon upgrading to Java 11, his application now reported that the week started on Sunday. This is incorrect for the Netherlands, but the real issue was the change of behavior.

With JDK11, Java now loads locales differently. https://www.oracle.com/technetwork/java/javase/documentation/java11locales-5069639.html#providers details the loading behavior for JDK11, and how it supersedes previous versions. Notably, CLDR, or classloaded entries, now go before COMPAT, or things included with the JDK. This can lead to incorrect behavior with complex classpaths.

To supersede this setting, the java.locale.providers system setting is used. It’s a comma-separated list of values, where the possible values are the providers in the blog post above. The default value is CLDR,COMPAT,HOST,JRE where JRE is also COMPAT. The value that I would have expected is COMPAT,HOST,CLDR, where it uses the built-in locales first (from JDK9!), then the host locales, then the classloader locales. Setting -Djava.locale.providers=COMPAT will cause the JDK11 locale loader to act like the JDK9 locale loader.

Netty is not a web framework

Recently, I have seen more and more web frameworks adopt Netty as their backend (the part that handles the actual HTTP requests). Examples are Spring WebFlux (the spring reactive web stack), Vert.x and Ktor.

What is Netty?

Netty calls itself “an asynchronous event-driven network application framework”. Let’s go over this word for word.

  • Netty is used for network applications: Instead of the “normal” java.io APIs (Socket, InputStream, …) you can use the Netty framework to build network applications.
  • Netty is a framework, not a library. It is fairly opinionated for things like connection management and expects you to use its pipeline model (more on that later) to build your application. This is in contrast to a library like XNIO that aims to simplify and complement the existing Java nio APIs.
  • Netty is asynchronous by design. When processing data from a network connection, you do not do so by calling blocking read methods like you would with InputStream, you instead get chunks of data asynchronously (in a “callback” you register). This is one of the main selling points – it allows you to serve many connections with few threads, which can help performance, and makes for a very convenient programming model.
  • Netty is event-driven. An idiomatic Netty application has a pipeline of “transformations” it applies on incoming and outgoing data. For example, you might first get incoming chunks of bytes, buffer them until a packet boundary and then send the full packet further downstream. The next handler in the pipeline would then parse the packet, and the handler after that finally runs the code that actually handles the packet.

In addition, Netty offers many implementations of common protocols out-of-the-box that you can basically mix-and-match as you wish. This goes from simple handlers such as DelimiterBasedFrameDecoder used for splitting incoming data on delimiters such as newline, to advanced handlers for full protocols like TLS or HTTP 1.1/2.

All this makes Netty one of the best (if not the best) general-purpose network application frameworks of any language out there. Nowhere else do you get network application development that is so convenient and powerful. I have used Netty in many projects over the years, and have contributed to it, and it remains my number one recommendation for anyone writing code that deals with custom protocols.

So why is Netty not appropriate for the Web?

Netty and HTTP

Netty includes handlers for parsing HTTP messages, both versions 1.1 and HTTP 2. It even supports SPDY if you wish to go back a few years! Netty got HTTP 2 support very early while other frameworks were still catching up, which may have contributed to its newfound popularity as a web framework.

I will not dispute Netty HTTP support can be very convenient. Netty’s design allows you to do things using its built-in HTTP handlers that would be impossible or difficult with traditional web frameworks. Is your HTTP/2 connection somehow TLS-less and wrapped in a custom encryption scheme? Does the remote server use upgrade mechanisms that are anything but to spec? Netty can implement your protocol anyway!

However, there are two disadvantages that Netty has that you will not get around easily.

Netty is not optimized as a HTTP server. Netty’s programming model brings with it certain static overhead – per-connection memory use is pretty high compared to raw Java NIO and its buffer management is convenient but not free. “Real” web frameworks can do more here: They can minimize parsing overhead, tune their buffer management to use patterns commonly seen for web servers and drop the niceties that Netty offers internally in favor of performance. When it’s not actually you doing the protocol parsing, the convenience of Netty’s internals don’t matter anymore.

Netty is not binary compatible, even across minor versions. This came as a surprise to me a few years back, but it makes sense: Netty offers very detailed views of its internals and evolution of the API would be hard without breaking binary compatibility at some point. Now this is not necessarily a problem for most Netty users that use Netty directly from their application. However, if you try to use two libraries on the same classpath at the same time that both use Netty (maybe Vert.x and the Java mongo driver) you could be in for a rude awakening in the future. You will either need to recompile or even patch one of the two. An alternative is relocation but that is inconvenient for reasons I will not discuss here. The incompatibility may become an even larger problem in the future when Netty 5 releases (if it ever does, it’s been in development for years).

So what’s the alternative?

Use Undertow. Undertow is a relatively new web server and the backend in Wildfly. Undertow was designed from the ground up as an asynchronous server, same as Netty. However, it is actually designed as a HTTP server and uses NIO directly instead of more expensive wrappers. This makes Undertow faster than Netty HTTP and appropriate for asynchronous applications. On top of that it is binary compatible with previous versions.

When you are building a “vanilla” HTTP server or client – one that does not mess with the HTTP protocol in non-standard ways – or you develop a web framework, use Undertow. There are few advantages Netty offers for the purely HTTP use case, and you are less likely to regret picking Undertow in the future.

Interesting Links – 5 Oct 2016

  • In Accounts is Everything Meteor Does Right, Pete Corey points out that Meteor‘s Accounts package dictates how user authentication and authorization will work, period, and that this removal of choice actually makes it entirely usable. Having wrestled with Shiro and Crowd and Spring Security and JAAS, it’s a point that’s hard to argue with – and while users of Shiro, etc., will probably say that those packages work as well as Accounts does, I’d have to humbly disagree, even while acknowledging how nice it is to have things like Shiro and Crowd. It’d be nice to have something that was just as drop-in for Java was Accounts is for Meteor. (Meteor is, BTW, a reactive application framework for NodeJS.)
  • User jdlee posted Maslow’s hierarchy of dev needs from Twitter – One gets the impression that the developer’s needs weren’t being met when designing that graph.
  • Also from jdlee, who was apparently crawling Twitter: “In Ruby, everything is an object. In Clojure, everything is a list. In Javascript, everything is a terrible mistake.”
  • User adimit gave high praise to Growing Object-Oriented Software Guided by Tests, saying that “it’s really simple but helping me write a test-driven app right now” and (coming from a Haskell background) “I’ve always hated OOP, but now I see how to do it properly, and it can be fun.” Anything that helps code quality improve is awesome, if you ask me.
  • From DZone: The Rise and Fall of Scala describes the apparent slow demise of Scala. The author backs it up, and it’s not a bad article; Scala’s awesome (I love it) but the criticisms are quite valid. Two areas where the author sees Scala remaining strong: Big Data and custom DSLs, definitely two Scala strengths.

Tags on javachannel.org

Articles on javachannel.org are going to start using Odersky’s “Scala Levels” as tags for new content (with old content being rated as they get maintained over time, possibly).
The levels are in two groups: A1, A2, A3, and L1, L2, and L3. The “A” stands for “application;” the “L” stands for “library.” Put simply, the features that tend to be found in applications and libraries are different; an application can prefer concrete types, whereas a library tends not to (if able); the skills and knowledge for writing applications or libraries are different.
An A1 programmer is a beginner at Java; an L3 programmer is expected to really know the language and its features well.
The skills are grouped like: A1, A2/L1, A3/L2, L3. The idea being expressed here is that before you should design a library, you need to be moderately skilled at Java – a beginner shouldn’t bother worrying about expressing ideas in a library.
Odersky actually grouped concepts for Scala in each level (for which he’s gotten some scathing criticism from Tony Morris, for example); eventually, I’d like to have the same kind of groupings for Java, if only to establish a baseline (which is what Odersky was doing, and what Morris apparently missed, in his quest for overreaction. Tony’s a brilliant guy, but like so many other brilliant people in this field, he’s desperate to find points of contention, and then wring them dry. Astute readers might note that Tony’s critique has no way through which to offer commentary…)
So: What you’ll start seeing is tips on javachannel.org being grouped by these levels by tags; the higher the level, the more complex the content is.