/freemapper

A Java Annotation Processor for generating ResultSet mapper classes

Primary LanguageJava

FreeMapper

FreeMapper is a Java Annotation Processor that automatically generates classes for mapping from SQL ResultSets to POJOs without reflection. Traditional ORMs add a ton of complexity and can have a huge impact on performance. The goal of FreeMapper is to get most of the developer-friendly features of ORMs without any of the hidden complexity or performance impact.

Usage

FreeMapper expects your POJOs to have a Builder child class that functions just like a builder class created by FreeBuilder. For example, given the following class:

import org.inferred.freebuilder.FreeBuilder;
import org.joeyb.freemapper.Field;
import org.joeyb.freemapper.FreeMapper;

import java.util.Date;
import java.util.Optional;

@FreeBuilder
@FreeMapper
public interface User {

  @Field(name = "email")
  String getEmail();

  @Field(name = "name")
  Optional<String> getName();

  @Field(name = "age")
  Optional<Integer> getAge();

  @Field(name = "is_admin")
  boolean isAdmin();

  @Field(name = "created_at")
  Date getCreatedAt();

  class Builder extends User_Builder { }

  class Mapper extends User_Mapper { }
}

FreeMapper will build a User_Mapper class that looks like this:

import java.lang.FunctionalInterface;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;

abstract class User_Mapper {
  public static User.Builder mapBuilder(ResultSet rs) throws SQLException {
    User.Builder b = new User.Builder();
    b.setEmail(rs.getString("email"));
    b.setName(getOptionalValue(rs, () -> rs.getString("name")));
    b.setAge(getOptionalValue(rs, () -> rs.getInt("age")));
    b.setAdmin(rs.getBoolean("is_admin"));
    b.setCreatedAt(rs.getTimestamp("created_at"));
    return b;
  }

  public static User map(ResultSet rs) throws SQLException {
    return mapBuilder(rs).build();
  }

  public static List<User> mapAll(ResultSet rs) throws SQLException {
    List<User> list = new LinkedList<User>();
    while(rs.next()) {
      list.add(map(rs));
    }
    return list;
  }

  private static <T> Optional<T> getOptionalValue(ResultSet rs, ResultSetSupplier<T> getValue) throws SQLException {
    T value = getValue.get();
    return rs.wasNull() ? Optional.empty() : Optional.of(value);
  }

  @FunctionalInterface
  private interface ResultSetSupplier<T> {
    T get() throws SQLException;
  }
}