When Typing Gets in the Way

It's been slow going on the Cardbase front as I haven't had much free time. To try to get back into it, I decided to implement a relatively straightforward feature: filtering. I thought the design was great up until I ran into some typing issues, and now I am wondering if Java was really the right choice of language for this application.


Ideally, when perusing a cardbase, it should be possible to filter it in addition to sorting. Filtering and sorting combined are the foundation of the deck-building aspect of Cardbase, allowing the user to list only the cards that fulfil certain criteria without having to manually trawl through a huge box of cards.

The Current Design

Cards are currently stored as a collection of Card objects:

public class Card {
    public String name;
    public String layout;
    public String manaCost;
    public Integer cmc;
    public String type;
    public String rarity;
    public String text;
    public String flavor;
    public String artist;
    public String number;
    public String power;
    public String toughness;
    public Integer loyalty;
    public Integer multiverseid;
    public String imageName;
    public String watermark;

    // Not part of upstream JSON
    public String setCode;
    public String imageCode;

    // Methods omitted

Most fields are Strings with the occasional Integer. Sorting works by comparing fields; since the values of the same field from two different instances are being compared, the comparisons can be done generically without type checking beyond making sure that the type is Comparable. This is already a somewhat messy circumvention of the rigorous Java typing system, but I thought it was reasonable, if anything as an exercise in reflection.

For filtering, I went with a similar concept. Filtering is done by specifying a Card field, a filter type and a filter value:

public class CardFiltering {
    enum FilterType {
        EQUALS {
            public boolean doFilter(String value, String filter) {
                return value.equalsIgnoreCase(filter);
        },  CONTAINS {
            public boolean doFilter(String value, String filter) {
                return value.toLowerCase().contains(filter.toLowerCase());
        }, REGEX {
            public boolean doFilter(String value, String filter) {
                return value.matches(filter);

        public abstract boolean doFilter(String value, String filter);

    public static void filterByField(List<Card> cards, String fieldName, FilterType filterType, String filterValue) throws NoSuchFieldException {
        Field fieldToFilter = Card.class.getDeclaredField(fieldName);
        try {
            for (Iterator<Card> iterator = cards.iterator(); iterator.hasNext();) {
                if (!filterType.doFilter((String) fieldToFilter.get(iterator.next()), filterValue)) {
        } catch (IllegalArgumentException e) {
            System.out.println("Error: class Card does not define field \"" + fieldToFilter.getName() + "\".");
        } catch (IllegalAccessException e) {
            System.out.println("Error: field " + fieldToFilter.getName() + " in Card is not visible.");

Filtering is done in-place; every entry that does not fulfil the filter criterion is removed from the list. The problem here is that it relies on a value that comes from the user: filterValue. I made that a String because that's how it's parsed from the command line, but some fields are not strings. When I try filtering by converted mana cost, terrible things happen:

Error on JUnit test due to ClassCastException

This is not great, and I can think of a few ways to solve it.


Argument Conversion

The hacky solution would be to use toString right there in the doFilter method call to make sure that it gets what it expects:

if (!filterType.doFilter(fieldToFilter.get(iterator.next()).toString(), filterValue)) {

Thankfully, according to the Java documentation, if you call toString on a string:

This object (which is already a string!) is itself returned.

So this works. It will compare integers as strings, but equal integers are also equal strings so that filter would behave as expected. However, putting on the user hat for a second, I realise that I am not satisfied with only "equals", "contains" and "regex" as filter types. I also want "greater than" and "smaller than" for things like converted mana cost. This is critical, for example, if I decide to build a fast deck; in that case I would want to see only the cards which have a converted mana cost smaller than, say, 4. I could achieve this with a regular expression like [0123] but that is not a scalable solution.

Indirect Typing

Another option would be to create a completely new type hierarchy just for Card fields; something like a CardField abstract ancestor type and concrete extensions of it, like StringCardField and IntegerCardField. We could even crack open the can of worms that is generics and go with CardField<T>. CardField could define an abstract method for checking if the field is compatible with a specified filter. The program could use such a method to check before filtering and ultimately output error messages if the user tried an invalid filter configuration.

Use Another Language

The obvious question to ask now is: did I choose the wrong language? If I am contemplating writing a whole package dedicated to something that some languages do natively, maybe I should be using one of those languages in the first place. I chose Java for cross-platform support, but JavaScript also runs on just about any system (via browsers) and, although I don't have a lot of experience with it, I believe it would handle stuff like this on the fly and get it right most of the time.


Contemplating moving to a different language makes me feel like Java is a bad language. I know this isn't true though. Surely this is a problem that comes up a lot; how do people address it? If everybody chose to move away from Java, it wouldn't exist anymore by now. I am going to explore these solutions further and post back here when I figure out some way to fix this.

Apple iPod Classic Upgrade

I have had a 6th generation 80 GB iPod Classic since December 2007, when the 6th generation first came out. It has been a solid music player, but I decided to have some fun and see if I can't do some DIY upgrades on it.


I am not a huge fan of Apple as a company. I don't like the way they try to lock everything down and keep it hidden from us users; if I buy a gadget, I want full access to it so I can root/flash/format/mod to my heart's content. That being said, Apple does make some very handsome hardware. Nowadays MacBooks and iPhones get all the spotlight, but in my opinion the iPod Classic is their real masterpiece. It's simple, compact, does one thing and does it well. Most importantly though, it has a lot of storage. For some reason, companies don't sell music players with large amounts of memory anymore, so those of us who don't want to stream music are left with few choices.

Fortunately, the internet is a wonderful place full of people who enjoy modding things like iPods. With a little care and common sense, I was able to convert my iPod into a cool 500 GB portable music player.


The first thing I did with my iPod was to strip out Apple's whatever OS they put on it and replace it with Rockbox. They don't have a stable build for the 6th generation Classic, but the dodgy "unusable" port actually works just fine with the third party emCORE bootloader. As of August 2016 development appears to be active and a proper Rockbox port with a bootloader is in the works.

I actually originally Rockboxed my device in 2014, 7 years after I bought it. I started ripping some CDs into FLAC files, and since that is apparently too open for Apple, I was left with no choice but to switch to a better OS. I have been very pleased with Rockbox ever since. Battery life is fine, never had any problems playing any file formats and I can transfer files onto it without iTunes (don't get me started on iTunes). I even got to choose a theme! (If you're up for a laugh, check out the themes they have. I'm not sure what they were thinking, but some of them are unbelievable).


I had thought about the possibility of swapping the HDD with an SSD before, but that was back when SSDs only went up to 32 GB and cost more than a new computer. Nowadays SSDs are fairly cheap and have incredible storage space, so I decided to revisit the idea. As it turns out many people also had this idea, and the good folks (folk?) over at iFlash actually put together a really neat mSATA board for the iPod Classic. I read some good reviews online, so I decided to pick one up and give it a go. For an SSD, I went with Samsung's 500 GB EVO 850.

Open iPod with iFlash board

Opening the iPod was a bit tricky, but nothing like the horror stories I've read online. With a bit of care and affection I was able to crack it open without any damage to the case. The iFlash board fit very nicely in place of the HDD, and it even came with a thermal filler sticker which helps cool down the SSD and prevents the whole board from moving around the case once it is shut.


The original battery, amazingly, still works! It does behave rather strangely, though. The indicator goes through the top 20% in a matter of minutes, and then sits on the 20-80% range for a long time. I wasn't sure if this is caused by battery wear or Rockbox issues, but since I was going to open the iPod, I decided to get a new battery as well.

Replacing the battery is very easy once the device is open, but considering that the iPod Classic is no longer made, finding a legitimate battery for it can be a challenge. For this reason I kept it open for a few days and used it fairly heavily to check the battery life. My tests show that it lasts as long as the old one, if not longer, and the indicator appears to behave correctly.

Final Result

Satisfied with the battery and SSD, I put the iPod back together. Rockbox reports as follows:

Rockbox system status screen showing long battery life and 465 GB disk space

Not too bad. The battery doesn't actually last that long with constant music playback. By my estimates it should go for about 14 hours, though that's based on tests with FLAC files. Transferring files is also a bit tricky; according to iFlash, some newer SSDs have a power-loss safety feature which disables them if the current goes below a certain threshold. Since they tend to draw a lot of power during writes, copying large amounts of data across at once could drain the battery and trigger the power-loss conditions. The best thing to do is to copy the files a little bit at a time, allowing the SSD to cool down and the battery to recharge in between bursts.

Overall I am quite satisfied, though the real question is whether it will stand the test of time. I'm going to be using this iPod as my main music player now (since my phone only has 8 GB storage), and hopefully it will continue to behave as well as it has so far.

Strict Transport Security

Catching up on my backlog of Information Security questions I came across HTTP Strict Transport Security, or HSTS. This seemed like a neat security feature, so I decided to have a go at implementing it on this site.


Using HTTPS ensures that all traffic between client and server is encrypted and allows the client to verify that they are indeed looking at the website they intended to access. However, this level of security relies on the client explicitly accessing the site using https:// as the protocol. It is unrealistic to expect the majority of internet users to type out this protocol (or any protocol at all), and it is also not possible to guarantee that all hyperlinks pointing to this site use it. The solution is to force secure access by responding with a 301 containing the secure URL whenever the server is accessed via HTTP.

Modern browsers are usually clever enough to cache these 301 redirects, meaning subsequent accesses will automatically use HTTPS. However, the first request must go through the redirection step; not a huge concern when accessing a blog like this, but consider the following scenario: a user checks their email via the browser on a public machine, such as a library computer; if the browser is configured to discard the cache at the end of the session, it will access the server via HTTP. A malicious third party could hijack the connection and redirect the user to a fake URL. Once the user logs in, their credentials are compromised. HSTS was designed to address the "first access" use case by allowing the browser to bypass the HTTP request altogether.


To implement HSTS, the first step is to make sure that the server allows it. This is done by including the Strict-Transport-Security header in the HTTPS requests:

HTTP/1.1 200 OK
Date: Tue, 12 Jul 2016 07:16:35 GMT
Server: Apache/2.4.10 (Debian)
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
Last-Modified: Wed, 11 May 2016 17:42:49 GMT
ETag: "55e8-532949200bdc0"
Accept-Ranges: bytes
Content-Length: 21992
Vary: Accept-Encoding
Content-Type: text/html; charset=UTF-8

This header represents a promise; clients can assume that from now until the end of the max-age period (in seconds), the host will support HTTPS. Browsers can store this information locally and use the safer protocol, even if the browsing history and cache are wiped. With this, browsers become more secure the longer they are used, and even machines configured to wipe the cache at the end of the session can benefit from the added security.

The last step is to cover the very first access so that, out-of-the-box, the browser knows which domains support HTTPS. This is done by preloading the domain onto a verified list. It is a much more "casual" procedure than acquiring a certificate, since HSTS does not authenticate the host. If a host is on the list and does not in fact support HTTPS, the browser can transparently fall back to HTTP and relatively little harm is done. Adding a domain to the list is as simple as entering it here: https://hstspreload.appspot.com/.

equalparts.eu pending submission to the HSTS preload list

Note that the submission is only completed if the response header is configured to "preload". This is to prevent domains from being added by someone other than the owner.


That's it! Quite an easy upgrade, but nice to have. It shouldn't be long until the domain is added to the list.

A+ SSL report from SSL Labs
Not bad.