AnimalDAOImpl

Figure 1. One table for the whole hierarchy - DAO implementation for the abstract class
package curam.inheritance;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import com.google.inject.Inject;
import com.google.inject.Singleton;

import curam.inheritance.struct.AnimalDtls;
import curam.test.codetable.ANIMAL_TYPE;
import curam.util.persistence.BaseDAOImpl;
import curam.util.persistence.ReaderDAO;
import curam.util.persistence.RowManager;

@Singleton
public class AnimalImpl extends
    BaseDAOImpl<Long, Animal, AnimalDtls> implements AnimalDAO {
  private static final AnimalAdapter adapter = new AnimalAdapter();

  @Inject
  private CatDAO catDAO;

  @Inject
  private DogDAO dogDAO;

  /**
   * Protected no-arg constructor for use only by Guice
   */
  protected AnimalImpl() {
    super(adapter, Animal.class);
  }

  @Override
  protected String getDiscriminator(
      final RowManager<Long, AnimalDtls> rowManager) {
    return rowManager.getDtls().animalType;
  }

  @Override
  protected Map<String, ReaderDAO<Long, ? extends Animal>>
    getConcreteReaderDAOs() {
    final Map<String, ReaderDAO<Long, ? extends Animal>>
      concreteReaderDAOs =
      new HashMap<String, ReaderDAO<Long, ? extends Animal>>();

    concreteReaderDAOs.put(ANIMAL_TYPE.CAT, catDAO);
    concreteReaderDAOs.put(ANIMAL_TYPE.DOG, dogDAO);
    return concreteReaderDAOs;
  }

  public Set<Animal> readAllAnimals() {
    return newSet(adapter.readAll());
  }
}

Class declaration

public class AnimalImpl extends BaseDAOImpl<Long, Animal, AnimalDtls>
  implements AnimalDAO {

The class extends the BaseDAOImpl class, which provides support for reading instances of abstract classes (by calling back to the implementation to decide which concrete class to instantiate). AnimalDAOImpl is responsible for retrieving a Cat or Dog instance, according to the value of the discriminator column, i.e. Animal.animalType.

Adapter

private static final AnimalAdapter adapter = new AnimalAdapter();

The class contains an adapter variable, as is the norm for DAO implementations.

DAO instances

@Inject
  private CatDAO catDAO;

  @Inject
  private DogDAO dogDAO;

The class contains injected instances of the DAO interfaces for the concrete classes.

These DAOs will be used to "dish up" the appropriate concrete type when a calling requests to read or search for Animal instances.

Protected constructor

/**
   * Protected no-arg constructor for use only by Guice
   */
  protected AnimalDAO() {
    super(adapter, Animal.class);
              }

The class contains a protected constructor, as is the norm for DAO implementations. This constructor passes the adapter and the entity class to the super constructor.

Get discriminator value from a row read from the database

@Override
  protected String getDiscriminator(
    final RowManager<Long, AnimalDtls> rowManager) {
    return rowManager.getDtls().animalType;
  }

You must override the BaseDAOImpl.getDiscriminator method to return the discriminator value from an abstract row read from the database (in this example, the value of Animal.animalID is returned from the row read).

Map discriminator values to DAO instances

@Override
  protected Map<String, ReaderDAO<Long, ? extends Animal>>
    getConcreteReaderDAOs() {
    final Map<String, ReaderDAO<Long, ? extends Animal>>
      concreteReaderDAOs =
      new HashMap<String, ReaderDAO<Long, ? extends Animal>>();

    concreteReaderDAOs.put(ANIMAL_TYPE.CAT, catDAO);
    concreteReaderDAOs.put(ANIMAL_TYPE.DOG, dogDAO);
    return concreteReaderDAOs;
  }

You must override the BaseDAOImpl.getConcreteReaderDAOs method to return a map of DAOs which can read the concrete instances of your entity.

The persistence infrastructure uses this map to retrieve a Cat or Dog as appropriate, depending on the value of Animal.animalID.