Base64 utils for Java

Last time I needed to add Base64 encoding to represent some binary data as a text. Especially I needed the functionality of translating a part (with given offset and length) of a byte array and get a result as a String object (listed in point “D” below). Surprisingly such an operation is not provided by most Base64 utils for Java. Below is the summary of my findings. I’ve focused on operations matching following signatures:

  1. byte[] encode(byte[] data)
  2. String encode(byte[] data)
  3. ByteBuffer encode(ByteBuffer data)
  4. String encode(byte[] data, int offset, int length)
  5. byte[] decode(byte[] base64)
  6. byte[] decode(String base64)
  7. ByteBuffer decode(ByteBuffer base64)
Name Remarks Operations
Java SE API Since Java 8, rather uncomfortable API (separate classes for coder and decoder) A, B, C, E, F, G
Apache Commons Codec It’s additional 293 KB. Many exotic operations. Maven dependency. A, B, E, F
Spring Framework Only an option if already using Spring, however it’s mostly an adapter using the one of the above libraries or JAXB DatatypeConverter as a fallback. Maven dependency. A, B, E, F
iHarder.net Base64 It weights only 17 KB! Many additional operations. Home page. Maven dependency. A, B, C, D, E, F
Guava Really heavy: 2.3 MB. Only an option if you’re already using Guava. Maven dependency. B, D, F

My personal favourite is iHarder.net Base64. Small and does the job. If performance is your strong requirement please refer to this article: Base64 encoding and decoding performance.

Posted in Java | Tagged | 2 Comments

AES 256 without JCE Unlimited Strength Jurisdiction Policy Files

Once upon a time I wanted my Java application to encrypt/decrypt some data. I decided to use AES (Advanced Encryption Standard, Rijndael) encryption algorithm with 256-bit key. AES is supported by Java SE by a built-in JCA (Java Cryptography Architecture) provider so in theory no 3rd party library needed. So I turned first to JCA-based solution. However to use 256-bit keys with AES we need to install Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files. At least we have to do it with Sun/Oracle JVM. This document explains cryptographic key limits in JCA and here is an interesting citation:

If stronger algorithms are needed (for example, AES with 256-bit keys), the JCE Unlimited Strength Jurisdiction Policy Files must be obtained and installed in the JDK/JRE.

A working example of a code for encryption/decryption with 256-bit AES using JCA:

import java.nio.charset.Charset;
import java.security.Key;
import java.util.Arrays;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import net.iharder.Base64;

public class AesExample {

	private static final Charset utf8Charset = Charset.forName("UTF-8");

	// placeholder, real key should be loaded from a key store
	static Key loadAes256bitKey() {
		byte[] aesKey = new byte[32];
		for (int i = 0; i < aesKey.length; ++i) {
			aesKey[i] = (byte)i;
		}
		return new SecretKeySpec(aesKey, "AES");
	}

	// placeholder, real IV should be somehow better
	static byte[] loadIvBytes() {
		byte[] data = new byte[16];
		for (int i = 0; i < data.length; ++i) {
			data[i] = (byte)i;
		}
		return data;
	}	

	// opmode: javax.crypto.Cipher.ENCRYPT_MODE or javax.crypto.Cipher.DECRYPT_MODE
	static Cipher getJcaCipher(int opmode) {
		try {
			Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
			Key key = loadAes256bitKey();
			byte[] iv = loadIvBytes();
			cipher.init(opmode, key, new IvParameterSpec(iv));
			return cipher;
		} catch (Exception ex) {
			throw new RuntimeException("Cannot intialize cipher. " + ex.getMessage(), ex);
		}
	}

	static String encode(String value) {
		try {
			byte[] encoded = getJcaCipher(Cipher.ENCRYPT_MODE).doFinal(value.getBytes(utf8Charset));
			return Base64.encodeBytes(encoded);
		} catch (Exception ex) {
			throw new RuntimeException("Data encryption failed. " + ex.getMessage(), ex);
		}
	}

	static String decode(String encodedStr) {
		try {
			byte[] encoded = Base64.decode(encodedStr);
			byte[] decoded = getJcaCipher(Cipher.DECRYPT_MODE).doFinal(encoded);
			return new String(decoded, utf8Charset);
		} catch (Exception ex) {
			throw new RuntimeException("Data decryption failed. " + ex.getMessage(), ex);
		}
	}

	public static void main(String... args) {

		for (String inputText : Arrays.asList("", "a", "ab", "abc", "And here we have some longer message.")) {
			String encoded = encode(inputText);
			String decoded = decode(encoded);
			System.out.format("%40s => %s => '%s' (%b)\n", inputText, encoded, decoded, inputText.equals(decoded));
		}
	}
}

And maven dependencies for the above:

<dependency>
    <groupId>net.iharder</groupId>
    <artifactId>base64</artifactId>
    <version>2.3.9</version>
</dependency>

NOTE: the above example will not work with Sun/Oracle JVM without JCE Unlimited Strength Jurisdiction Policy Files. Installing these files turned out to be really annoying, at least for me. Solutions:

  1. Use another JVM instead of Oracle’s one, that is allowing stronger cryptography. Here I’ve found something about it (but haven’t tested): http://derjan.io/blog/2013/03/15/nevermind-jce-unlimited-strength-use-openjdk
  2. Use another encryption library to create a solution that is not depending on a JVM used… which is why I’ve created this article.

Bouncy Castle to the rescue!

The JVM-independent solution for using 256-bit AES is to use Bouncy Castle library and stick to its own API. It should not be a problem as the library is really stable and alive. I’ve seen it for the first time in a production-running code in 2007 and the last version of the library was released in December 2016 (as of 09.01.2017 it was 1.56). My solution was based on this handy article: BouncyCastle Lightweight API encryption example by “ofsdeveloper99”.

Let’s add following imports to the above example:

import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.engines.AESEngine;
import org.bouncycastle.crypto.modes.CBCBlockCipher;
import org.bouncycastle.crypto.paddings.PKCS7Padding;
import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.crypto.params.ParametersWithIV;

Let’s add following methods:

	static PaddedBufferedBlockCipher getBcCipher(boolean forEncryption) {
		try {
			Key key = loadAes256bitKey();
			byte[] iv = loadIvBytes();
			CipherParameters params = new ParametersWithIV(new KeyParameter(key.getEncoded()), iv);
			PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(new CBCBlockCipher(new AESEngine()), new PKCS7Padding());
			cipher.init(forEncryption, params);
			return cipher;
		} catch (Exception ex) {
			throw new RuntimeException("Cannot intialize Bouncy Castle cipher. " + ex.getMessage(), ex);
		}
	}

	static String encode2(String value) {
		try {
			PaddedBufferedBlockCipher cipher = getBcCipher(true);
			byte[] input = value.getBytes(utf8Charset);
			byte[] output = new byte[cipher.getOutputSize(input.length)];
			int len = cipher.processBytes(input, 0, input.length, output, 0);
			len += cipher.doFinal(output, len);
			return Base64.encodeBytes(output, 0, len);
		} catch (Exception e) {
			throw new RuntimeException("Data encryption failed. " + e.getMessage(), e);
		}
	}

	static String decode2(String encodedStr) {
		try {
			PaddedBufferedBlockCipher cipher = getBcCipher(false);
			byte[] encoded = Base64.decode(encodedStr);
			byte[] output = new byte[cipher.getOutputSize(encoded.length)];
			int len = cipher.processBytes(encoded, 0, encoded.length, output, 0);
			len += cipher.doFinal(output, len);
			return new String(output, 0, len, utf8Charset);
		} catch (Exception e) {
			throw new RuntimeException("Data decryption failed. " + e.getMessage(), e);
		}
	}

And let’s change the main method to this:

	public static void main(String... args) {

		for (String inputText : Arrays.asList("", "a", "ab", "abc", "And here we have some longer message.")) {
			String encoded = encode(inputText);
			String encoded2 = encode2(inputText);
			String decoded = decode2(encoded);
			System.out.format("%40s => %s => '%s' (%b, %b)\n", inputText, encoded2, decoded, encoded.equals(encoded2), inputText.equals(decoded));
		}
	}

We need to add this dependency as well:

<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcprov-jdk15on</artifactId>
    <version>1.56</version>
</dependency>

Now the output should be:

                                         => 6cPvirI0U+bwdJzWNueojg== => '' (true, true)
                                       a => L854J/PY0dXgLD70k+z+sQ== => 'a' (true, true)
                                      ab => JOZH1E2V4fpZ+Ips93ZIfw== => 'ab' (true, true)
                                     abc => 6YtQ2v/uDI5Se7p4Weg3Ew== => 'abc' (true, true)
   And here we have some longer message. => LRY2Ny5DM1v2AMIhx1h7/edAZdHDOS+N0oywoERCSxAHpFvq45LtPC8wNkxapVXY => 'And here we have some longer message.' (true, true)

As you can see, both implementations of encryption/decryption with use of 256-bit AES are interchangeable. But the second one, based on Bouncy Castle, is JVM-independent. Forget JCE Unlimited Strength Jurisdiction Policy Files!!!

Posted in Java | Tagged , , , | Leave a comment

Turning a laptop into a Java application server in 10 steps

This is just my own proposition of a list of things needed to be done to turn a laptop into a Java application server based on Apache Tomcat under control of a Linux operating system, optionally using PostgreSQL as a database.

  1. Download and install Long-Term-Support (LTS) version of some Linux distribution, preferably a server variant. Example: Ubuntu Server 16.04 LTS. When selecting packages/services mark following (these options are available on Ubuntu Server installer):
    1. Open SSH server
    2. PostgreSQL – if the server is going to run a SQL database as well
  2. Configure the system so closing the laptop lid will not suspend the system.
    1. Edit the file /etc/systemd/logind.conf (sudo nano /etc/systemd/logind.conf) by adding line:
      HandleLidSwitch=ignore
    2. Restart the systemd daemon:
      sudo service systemd-logind restart
  3. Install a Server JRE (Apache Tomcat no longer needs JDK). Example: server-jre-8u101-linux-x64.tar.gz from Oracle Java SE download page. If installing manually it’s a common approach to put it into /opt directory. Example: /opt/jdk1.8.0_101
    1. You can use tar xf file.tar.gz command to extract the package
    2. Then move the whole extracted JRE directory to /opt
    3. Then change ownership of the JRE directory, example:
      sudo chown -R root.root /opt/jdk1.8.0_101
  4. Install Apache Tomcat. If installing manually I propose to put it into /home/tomcat directory. Thanks to this our Java applications will be stored on /home disk partition.
  5. Create a system user “tomcat” and configure Apache Tomcat to be run as a system service under this user. I followed this guide more or less: How To Install Apache Tomcat 8 on Ubuntu 16.04. Most important steps:
    1. Create a new user “tomcat” with commands:
      sudo groupadd tomcat
      sudo useradd -s /bin/false -g tomcat -d /opt/tomcat tomcat
    2. Change directory and file permissions such that user “tomcat” has read access to all under /home/tomcat and has write access only to following subdirectories: conf, logs, temp, webapps, work.
    3. Create a system service configuration file /etc/systemd/system/tomcat.service (for example by command: sudo nano /etc/systemd/system/tomcat.service) and put the below into the file:
      [Unit]
      Description=Apache Tomcat 8.5
      After=network.target
      
      [Service]
      Type=forking
      
      Environment=JAVA_HOME=/opt/jdk1.8.0_101
      Environment=CATALINA_PID=/home/tomcat/temp/tomcat.pid
      Environment=CATALINA_HOME=/home/tomcat
      Environment=CATALINA_BASE=/home/tomcat
      
      ExecStart=/home/tomcat/bin/startup.sh
      ExecStop=/home/tomcat/bin/shutdown.sh
      
      User=tomcat
      Group=tomcat
      RestartSec=10
      Restart=always
      
      [Install]
      WantedBy=multi-user.target
    4. Reload system services configuration, run and enable the service with below commands – thanks to this Apache Tomcat will be automatically started with the OS:
      sudo systemctl daemon-reload
      sudo systemctl start tomcat
      sudo systemctl enable tomcat
    5. Check Tomcat service status with command:
      sudo systemctl status tomcat
      

      It should present similar information:

         Loaded: loaded (/etc/systemd/system/tomcat.service; enabled; vendor preset: enabled)
         Active: active (running) since sob 2016-09-24 13:45:44 CEST; 1h 17min ago
        Process: 1063 ExecStart=/home/tomcat/bin/startup.sh (code=exited, status=0/SUCCESS)
       Main PID: 1195 (java)
          Tasks: 26
         Memory: 130.4M
            CPU: 16.798s
         CGroup: /system.slice/tomcat.service
                 └─1195 /opt/jdk1.8.0_102/bin/java -Djava.util.logging.config.file=/home/tomcat/conf/logging.properties -
  6. Configure an account to access Apache Tomcat console by editing the file /home/tomcat/conf/tomcat-users.xml (sudo nano /home/tomcat/conf/tomcat-users.xml) and adding following entries:
      <role rolename="manager-gui"/>
      <role rolename="admin-gui"/>
      <user username="you-user" password="your-password" roles="manager-gui,admin-gui"/>
  7. Configure PostgreSQL:
    1. Run the below command to stop PostgreSQL:
      sudo systemctl stop postgresql
    2. Change the default location of data held by PostgreSQL and it’s listening IP address by editing postgresql.conf file (in case of PostgreSQL 9.5 which is part of Ubuntu Server 16.04: sudo nano /etc/postgresql/9.5/main/postgresql.conf):
      1. data_directory variable should point to a directory of your choice, like /home/postgresql
      2. listen_addresses variable should be set to the value '*'
    3. Allow remote TCP connections to be accepted by editing pg_hba.conf file (sudo nano /etc/postgresql/9.5/main/pg_hba.conf):
      1. Modify line starting with “host”. To allow any connection it can be set to:
        host    all    all    0.0.0.0/0    md5
    4. Create the new data directory and change ownership to PostgreSQL user:
      sudo mkdir /home/postgresql
      sudo chown postgres.postgres /home/postgresql
    5. PostgreSQL is very sensitive in case of access rights to it’s data directory. I found it started to working after no access for group and others was set up:
      drwx------
    6. Run below commands to run & initialize PostgreSQL in the new directory and check its status (all statues should be “active”):
      sudo systemctl start postgresql
      sudo -u postgres /usr/lib/postgresql/9.5/bin/initdb -D /home/postgresql
      sudo systemctl status postgresql
      sudo systemctl -a|grep postgresql
  8. Create database, tables and user. I assume that you have SQL script for creation of tables and user. The second command below is based on the Running SQL scripts with psql article. The SQL script file must be accessible by “postgres” user.
    sudo -u postgres createdb your-db-name
    sudo -u postgres PGOPTIONS='--client-min-messages=warning' psql -X -q -v ON_ERROR_STOP=1 -d your-db-name -f path-to-sql-script
  9. Deploy your Java application WAR (assuming it has properly configured database connection inside the WAR). You can use Apache Tomcat console for this.
  10. Additional: check laptop’s battery and power status with a command-line tool so it can be done remotely later via ssh.
    1. Command for installation:
      sudo apt-get install acpi
    2. Command for checking:
      acpi -V

Now close the laptop lid and enjoy having the compact and silent server running your application!

Posted in database, Java, Linux, Tomcat | Leave a comment

Filters missing in AngularJS 1.5.x

Very quickly after beginning my adventure with AngularJS I’ve discovered that at least couple of obvious filters are missing. The list of built-in filters is here. The way to go is to add custom filters. So here are my propositions:

Percentage formatting filter

I’ve found very good implementation (because simple) on the GitHub: percent-filter.js by Jeff Johnson. I’m attaching his implementation below in a copy-and-paste ready form. BTW: this filter assumes the percentage value is given as a number such that 1 represents 100%, 0.35 represents 35%, etc.

app.filter('percentage', ['$filter', function ($filter) {
        return function (input, decimals) {
            return $filter('number')(input * 100, decimals) + '%';
        };
    }]);

Usage: {{value | percentage}} or {{value | percentage:n}} where “n” is the number of places after the decimal point.

File size formatting filter

The following filter formats given number as a file-size with automatically selected unit (bytes, kilobytes, megabytes, etc.) assuming that 1 KB = 1024 B, 1 MB = 1024 KB, etc. My implementation is an improved version of the filter found in stryju’s (tomasz stryjewski) comment (May 12, 2014) on this GitHub page. The improvement is for proper formatting of file size in bytes when the precision is given so we avoid ending with something like “0.0 B”. And I’ve added a condition so unit variable is a proper index for units array in any case.

app.filter('filesize', function () {
    var units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB'];

    return function (bytes, precision) {
        bytes = parseFloat(bytes);
        if (isNaN(bytes) || !isFinite(bytes)) {
            return '?';
        }

        var unit = 0;
        while (bytes >= 1024 && unit < (units.length - 1)) {
            bytes /= 1024;
            unit++;
        }
        if (unit == 0) {
            precision = 0;
        }

        return bytes.toFixed(precision) + ' ' + units[unit];
    };
});

Usage: {{value | filesize}} or {{value | filesize:n}} where “n” is the number of places after the decimal point and “value” is number of bytes.

Posted in JavaScript | Tagged | Leave a comment

Spring MVC, REST, Joda DateTime & Gson

When building REST web-service with Spring MVC the framework automatically configures message converters based on certain libraries found on the classpath (thanks to <mvc:annotation-driven/>). So it’s enough to have Gson (google-gson) as a dependency (in pom.xml) to make your REST service to produce/accept JSON formatted content. There are other JSON libraries as well but in this article I’m focusing on using Gson.

Unfortunately there is a problem with formatting Joda DateTime fields. By default the JSON output made by Gson for DateTime object looks like this:

 {"iMillis":1465070656778,"iChronology":{"iBase":{"iBase":{"iBase":{"iMinDaysInFirstWeek":4}},"iParam":{"iZone":{
"iTransitions":[-9223372036854775808,-2840145840000,-1717032240000,-1693706400000,-1680483600000,-1663455600000,-1650150000000,-1632006000000,-1618700400000,-1600473600000,-1587168000000,-1501725600000,-931734000000,-857257200000,-844556400000,-828226800000,-812502000000,-796608000000,-778726800000,-762660000000,-748486800000,-733273200000,-715215600000,-701910000000,-684975600000,-670460400000,-654130800000,-639010800000,-397094400000,-386812800000,-371088000000,-355363200000,-334195200000,-323308800000,-307584000000,-291859200000,-271296000000,-260409600000,-239846400000,-228960000000,-208396800000,-197510400000,-176342400000,-166060800000,228873600000,243993600000,260323200000,276048000000,291772800000,307497600000,323827200000,338947200000,354672000000,370396800000,386121600000,401846400000,417571200000,433296000000,449020800000,465350400000,481075200000,496800000000,512524800000,528249600000,543974400000,559699200000,575427600000,591152400000,606877200000,622602000000,638326800000,654656400000,670381200000,686106000000,701830800000,717555600000,733280400000,749005200000,764730000000,780454800000,796179600000,811904400000,828234000000,846378000000],
"iWallOffsets":[5040000,5040000,3600000,7200000,3600000,7200000,3600000,7200000,7200000,10800000,7200000,3600000,7200000,3600000,7200000,3600000,7200000,3600000,7200000,3600000,7200000,3600000,7200000,3600000,7200000,3600000,7200000,3600000,7200000,3600000,7200000,3600000,7200000,3600000,7200000,3600000,7200000,3600000,7200000,3600000,7200000,3600000,7200000,3600000,7200000,3600000,7200000,3600000,7200000,3600000,7200000,3600000,7200000,3600000,7200000,3600000,7200000,3600000,7200000,3600000,7200000,3600000,7200000,3600000,7200000,3600000,7200000,3600000,7200000,3600000,7200000,3600000,7200000,3600000,7200000,3600000,7200000,3600000,7200000,3600000,7200000,3600000,7200000,3600000],
"iStandardOffsets":[5040000,5040000,3600000,3600000,3600000,3600000,3600000,3600000,7200000,7200000,7200000,3600000,3600000,3600000,3600000,3600000,3600000,3600000,3600000,3600000,3600000,3600000,3600000,3600000,3600000,3600000,3600000,3600000,3600000,3600000,3600000,3600000,3600000,3600000,3600000,3600000,3600000,3600000,3600000,3600000,3600000,3600000,3600000,3600000,3600000,3600000,3600000,3600000,3600000,3600000,3600000,3600000,3600000,3600000,3600000,3600000,3600000,3600000,3600000,3600000,3600000,3600000,3600000,3600000,3600000,3600000,3600000,3600000,3600000,3600000,3600000,3600000,3600000,3600000,3600000,3600000,3600000,3600000,3600000,3600000,3600000,3600000,3600000,3600000],
"iNameKeys":["LMT","WMT","CET","CEST","CET","CEST","CET","CEST","EET","EEST","EET","CET","CEST","CET","CEST","CET","CEST","CET","CEST","CET","CEST","CET","CEST","CET","CEST","CET","CEST","CET","CEST","CET","CEST","CET","CEST","CET","CEST","CET","CEST","CET","CEST","CET","CEST","CET","CEST","CET","CEST","CET","CEST","CET","CEST","CET","CEST","CET","CEST","CET","CEST","CET","CEST","CET","CEST","CET","CEST","CET","CEST","CET","CEST","CET","CEST","CET","CEST","CET","CEST","CET","CEST","CET","CEST","CET","CEST","CET","CEST","CET","CEST","CET","CEST","CET"],
"iTailZone":{"iStandardOffset":3600000,"iStartRecurrence":{"iOfYear":{"iMode":"u","iMonthOfYear":3,"iDayOfMonth":-1,"iDayOfWeek":7,"iAdvance":false,"iMillisOfDay":3600000},"iNameKey":"CEST","iSaveMillis":3600000},"iEndRecurrence":{"iOfYear":{"iMode":"u","iMonthOfYear":10,"iDayOfMonth":-1,"iDayOfWeek":7,"iAdvance":false,"iMillisOfDay":3600000},"iNameKey":"CET","iSaveMillis":0},"iID":"Europe/Warsaw"},"iID":"Europe/Warsaw"},"iID":"Europe/Warsaw"}}}} 

To fix it we need to setup a message converter used by Spring MVC to cooperate with Gson. It turns out that GsonHttpMessageConverter class is used as a message converter in this case. This class has property named “gson” of type com.google.gson.Gson. Knowing this we can prepare a solution consisting of following 3 steps:

1. Create Gson TypeAdapter for Joda DateTime

I wanted to represent Joda DateTime objects as numbers of milliseconds so I’ve created the following Gson type-adapter (you can modify this part to obtain other representations):

package kt.data.gson;

import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
import com.google.gson.stream.JsonWriter;
import java.io.IOException;
import org.joda.time.DateTime;

/**
 * Gson adapter for serializing joda DateTime objects.
 */
public class DateTimeAdapter extends TypeAdapter<DateTime> {

	@Override
	public void write(JsonWriter writer, DateTime dt) throws IOException {
		if (dt == null) {
			writer.nullValue();
		} else {
			writer.value(dt.getMillis());
		}
	}

	@Override
	public DateTime read(JsonReader reader) throws IOException {
		if (reader.peek() == JsonToken.NULL) {
			reader.nextNull();
			return null;
		} else {
			return new DateTime(reader.nextLong());
		}
	}
}

2. Create Gson object factory bean

package kt.data.gson;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import org.joda.time.DateTime;
import org.springframework.beans.factory.FactoryBean;

public class GsonFactoryBean implements FactoryBean<Gson> {

	@Override
	public Gson getObject() throws Exception {
		return new GsonBuilder()
			.registerTypeAdapter(DateTime.class, new DateTimeAdapter())
			.create();
	}

	@Override
	public Class<?> getObjectType() {
		return Gson.class;
	}

	@Override
	public boolean isSingleton() {
		return false;
	}	
}

3. Configure Spring MVC

Instead of just <mvc:annotation-driven/> in our Spring context XML configuration file we now need:

    <mvc:annotation-driven>
        <mvc:message-converters>
            <bean class="org.springframework.http.converter.json.GsonHttpMessageConverter">
                <property name="gson">
                    <bean class="kt.data.gson.GsonFactoryBean"/>
                </property>
            </bean>
        </mvc:message-converters>
    </mvc:annotation-driven>  

This works at least for Spring Framework 4.2.6, Gson 2.3.1 and Joda Time 2.9.1.

Additional reading: SPRING: <MVC:MESSAGE-CONVERTERS> EXPLAINED.

Posted in Java, Spring | Tagged , , , | Leave a comment

MATE confirmed to cause video tearing

I hereby confirm that MATE Desktop Environment (at least in Linux Mint 17 MATE Edition) is causing a video tearing.

I was facing the problem for last couple of years but I thought it was related to AMD Radeon HD 6450 video card and its driver. The Catalyst driver provides an option to use VSync but then video playing stopped being smooth. I have even found comments in the Internet blaming AMD/ATI video cards in general of causing video tearing under Linux. Probably they are all wrong. Those comments suggested to switch to Nvidia.

So I switched to Nvidia GeForce GT 720 video card, installed its latest driver and… the video tearing was still happening. So I started digging about the problem without bias related to type of video card or video driver and… found out that under Linux Mint switching from MATE Desktop Environment to Cinnamon Desktop Environment may help. I’ve immediately installed it… AND IT HELPED!

What’s most beautiful in Linux is that I can have both: MATE and Cinnamon, selecting one when logging in. MATE is for lower resource usage and Cinnamon for perfect video playing (and probably as general video-related problem solver).

PS. Last time I’ve found this workaround for video tearing under Linux Mint MATE Edition: http://www.howtoeverything.net/linux/issues/finally-no-more-tearing-anywhere-mate-desktop-and-compiz I didn’t try it and it looks more complicated and kind of limited.

PS.2. It looks that Linux Mint 17.3 MATE Edition finally tried to address the issue of video tearing: http://www.linuxmint.com/rel_rosa_mate_whatsnew.php (search for “screen-tearing”). However it failed. After upgrade to Linux Mint 17.3 MATE the video tearing problem is still present. Hey, MATE team – stop claiming you’ve solved it!

Posted in Linux | Leave a comment

Install OpenOffice instead of damn LibreOffice

Last years Linux Mint maintainers have been forcing users to use a relatively new LibreOffice package instead of the well known and mature OpenOffice package. At the beginning it didn’t hurt. Things changed for me when I tried to create a multi-page document with page numbering. It turned out such a basic functionality as automatic page numbering is flawed in LibreOffice. LibreOffice aparently was restarting numbering at 2nd page in my case. I’ve waisted so much time thinking it was my fault or that there is an option to change this behaviour. THIS BUG IS A SCANDAL! Below is a shortened instruction (after https://www.youtube.com/watch?v=ZmJXIeeqllM) of how to replace LibreOffice with Apache OpenOffice:

  1. Run command: sudo apt-get purge libreoffice*
  2. Download tar.gz with DEB package for OpenOffice from www.openoffice.org
  3. Extract it (tar -xvf filename.tar.gz) to some directory
  4. Go to the directory – there will be a subdirectory named after language/locale of downloaded OpenOffice variant (in my case the subdirectory was named pl, for English variant it’s usually named en-US)
  5. In the subdirectory execute following commands:
    1. sudo dpkg -i DEBS/*.deb
    2. sudo dpkg -i DEBS/desktop-integration/*.deb
  6. Now you can remove downloaded tar.gz file and the directory with its extracted content.

It’s done! I verified it under Linux Mint 17.

Posted in Linux | Leave a comment