MySQL, UTF-8 and Emoji

In a MySQL-based project we had a series of UncategorizedSQLExceptions in the log:

org.springframework.jdbc.UncategorizedSQLException:
### Error updating database.  
Cause: java.sql.SQLException: 
Incorrect string value: '\xF0\x9F\x98\x98' for column 'note' at row 1

These exceptions had occured because some users entered Emoji characters into a free text field. Emojis are encoded as UTF-8 character. Normally this isn’t a problem, but the MySQL “utf8” character set only supports UTF-8 characters with 3 bytes(!). So Emoji cannot be stored into a “utf8”-encoded MySQL database. 👎

The solution

MySQL 5.5 introduced an “utf8mb4” character set [1]. If you create new MySQL databases you should use this encoding right from the beginning. Otherwise you have to perform a migration afterwards which might take some time. ⌚ [2][3].

[1] http://dev.mysql.com/doc/refman/5.5/en/charset-unicode-utf8mb4.html
[2] http://dev.mysql.com/doc/refman/5.5/en/charset-unicode-upgrading.html
[3] https://mathiasbynens.be/notes/mysql-utf8mb4

Apache Tomcat’s URIEncoding

Bei einem Refactoring einer Webapplikation hatte ich ein HTML-Formular von HTTP-POST auf GET umgestellt, da eine idempotente Suchanfrage ausgelöst wird. Allerdings traten bei Suchbegriffen mit Umlauten unschöne Encoding-Fehler auf:

Kaputte Umlaute durch fehlerhaftes Encoding

“Endlich mal wieder ein Encoding-Problem” denke ich, und beginne mit einem UTF-8-Schnellcheck:

UTF-8-Schnellcheck

  • Content-Type HTTP-Header korrekt gesetzt ? Ja.
    Content-Type: text/html; utf-8;charset=utf-8
    
  • Meta-Tag gesetzt ? Ja.
    <meta content="text/html; charset=utf-8" http-equiv="content-type">
    
  • Default-Encoding der JVM ?
    Ausgabe von Charset.defaultCharset() ? Ist UTF-8.

Alles schien in Ordnung zu sein, aber warum wurde der Suchbegriff falsch encodiert ? Bei der Analyse mit dem Debugger zeigte sich, dass bereits der CGI-Parameter vom Tomcat falsch encodiert wurde.

Die Ursache: URIEncoding-Attribut des Apache Tomcats
Wenn im Connector das URIEncoding-Attribut nicht gesetzt wird, dann verwendet der Tomcat eben das ISO-8859-1 Encoding. Normalerweise würde man jetzt die server.xml anpassen. Allerdings starten wir unsere Entwicklungsinstanzen mit dem maven-tomcat-plugin. In diesem Fall trägt man in der pom.xml einfach folgendes Attribut ein:

<maven.tomcat.uriEncoding>UTF-8</maven.tomcat.uriEncoding>

Fertig. Und schon wieder ein Encoding-Problem weniger.