The DONTTOUCHIT! effect

I’ve always asked myself what makes a programmer – I am a programmer- actually say that. When I have found myself saying this to me – luckily not very often – it feels like giving full control of my life to a machine…

One good specimen of this effect are the [indiscriminate use of]DAOs. Don’t ask me why but DAOs seem to have some viral effect in large projects and their dead bodies tend to survive most generations of programmers involved on the project, i.e. the (very)undesirable DONTTOUCHIT! effect…

In some “advanced” programs we even find a facade for each and every DAO.

Stay calm. I won’t touch it…

 

Automatic Database Diffs of your Domain Model

One of the (many) nice thing of using a proper ORM is the ability to create automatic database schemas from your domain model. For example, in EclipseLink, this is acheived with the SchemaManager class. All you need is a persistence unit name and let there be it!

If we season this a bit with some little magic from the amazing Liquibase project, with some simple steps we can make automatic structual diffs of our domain model! Let’s take a look at the algorithm we use in [ki]DOIT.

In order to simplify database versioning we have a simple naming convention. Let’s say we have a persistence unit named foo.dev. We’ll (finally) find a (mvn) folder structure as follows:

/src/main/resources/dbchangelog/foo.dev/db.changelog-master.xml/src/main/resources/dbchangelog/foo.dev/db.changelog-initial.xml

These files will sound familiar to you if you’ve already used Liquibase. If not, what are you waiting for?

If you are using the diff project you’ll notice you have a dependency to hsqldb. This is used to simplify db generation without the need of additional installation.

Let’s go with (a simplified version of) the algorithm then:

  1. Is there a db.changelog-master.xml?
    • No: Fresh start. Generate the initial database.
    • Yes: Diff. Generate the database with current changelog.
  2. Generate the new database with the changes you’ve made to the domain model.
  3. Ask Liquibase to generate your diff.
  4. The generated file will be /src/main/resources/dbchangelog/foo.dev/db.changelog-[TIMESTAMP].xml. Inspect any possible mistakes. You’ll find little :)

Too simple? Yes!! And it works like a charm. Currently, the only main issue is some arbitrary changes on indexes if you use them.

 

Multiple Serialization Contexts

During a recent project we faced the (not so uncommon) problem of different serialization needs depending on the runtime context for our domain model. We have mechanisms inplace for this – multiple ifs in the serializer or even ConditionalSerialization.The issue is that I spend most of my time reading code, and I like meaningful class names. We need to find something better.

Serialization is done in a last phase so this couldln’t be tackled cleanly without some additional help. At first groups – the validation JSR303 way – seemed as the best approach but finally we took benefit of the polymorphic typeAdapter approach taken in GSON and it doesn’t seem like a terrible decision. Speaking in other words, when the annotation SerializationAdapter is used, the way serialization is handled is done using the following sequence (same applies to deserialization):

  1. If adapter extends TypeAdapter then give back as is. TypeAdapter will construct the appropiate serializer and – wishfully – return the correct value.
  2. If adapter doesn’t implement JsonSerializer then check for XmlTransient and if not present use default mechanism. Serialize null otherwise.
  3. If adapter doesn’t implement SerializationAdapterCondition serialize with JsonSerializer
  4. If it does, ask for permission to use serializer. If positive serialize with JsonSerializer
  5. If not, check for for XmlTransient and if not present use default mechanism. Serialize null otherwise

Since we now have a way to decide which context to use we can make a decision chain with the grouping annotation SerializationAdapters. The order in which they are specified is the order in which they are questioned for acceptance. It obviestly doesn’t make sense to have a list of adapters and have the first one not implement SerializationAdapterCondition or always return true since the other adapters will never be used. There is also a slight difference with how the single adapter works: if XmlTransient is present it will never fallback to the default mechanism.

Happy coding!

Examples:

    @XmlTransient
    @OneToOne(cascade = CascadeType.PERSIST)
    @SerializationAdapter(SerializeWhenUsingActionEngine.class)
    private InitialStatement initialStatement;
public class SerializeWhenUsingActionEngine implements SerializationAdapterCondition {

    @Inject
    private IThreadLocalRegistry threadLocalRegistry;

    @Override
    public boolean accepted() {
        return threadLocalRegistry.getValue(IActionEntityService.class) != null;
    }

}