CatImpl

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

import curam.inheritance.Cat;
import curam.inheritance.struct.AnimalDtls;
import curam.test.codetable.ANIMAL_TYPE;
import curam.util.persistence.EntityInfo;
import curam.util.persistence.helper.SingleTableEntityImpl;

public class CatImpl extends AnimalImpl implements Cat {

  protected CatImpl() {
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public void setEntityInfo(
      EntityInfo<Long, SingleTableEntityImpl<AnimalDtls>,
      AnimalDtls>
      entityInfo) {
    super.setEntityInfo(entityInfo);

    // check that this object has been constructed with an
    // appropriate row
    if (getID() != null
        && !getDtls().animalType.equals(ANIMAL_TYPE.CAT)) {
      throw new RuntimeException("Expected to be a cat");
    }
  }

  public int getNumberOfLivesRemaining() {
    return getDtls().numberOfLivesRemaining;
  }

  public void setNumberOfLivesRemaining(final int value) {
    getDtls().numberOfLivesRemaining = value;
  }

  public void speak() {
    System.out.println("Miaow!  My name is " + getName()
        + " and I have " + getNumberOfLivesRemaining()
        + " lives remaining");
  }

  public void crossFieldValidation() {
    // none required
  }

  public void crossEntityValidation() {
    // none required
  }

  public void mandatoryFieldValidation() {
    // none required
  }

  public void setNewInstanceDefaults() {
    getDtls().animalType = ANIMAL_TYPE.CAT;
  }

}

Class declaration

public class CatImpl extends AnimalImpl implements Cat {
The class:
  • extends the AnimalImpl class created above. As there is only a single database table, no parameters are required; and
  • implements the Cat interface (which in turn extends the Animal interface).

Protected constructor

protected CatImpl() {
  }

The class has a protected constructor, as is the norm for the implementation classes.

Confirming that the correct type has been retrieved

/**
   * {@inheritDoc}
   */
  @Override
  public void setEntityInfo(
      EntityInfo<Long, SingleTableEntityImpl<AnimalDtls>,
      AnimalDtls>
      entityInfo) {
    super.setEntityInfo(entityInfo);

    // check that this object has been constructed with an
    // appropriate row
    if (getID() != null &&
        !getDtls().animalType.equals(ANIMAL_TYPE.CAT)) {
      throw new RuntimeException("Expected to be a cat");
    }
  }

If the CatDAO is used to retrieve a Cat instance, it is important to check that the Animal row retrieved actually contains the correct discriminator value for a Cat, to guard against client code trying to retrieve a Cat based on a Dog 's ID.

Getters and Setters

The getters and setters make use of the SingleTableEntityImpl.getDtls method to access the AnimalDtls row data.

Implementations for the getters and setters for the Animal fields are inherited from AnimalImpl.

speak

public void speak() {
    System.out.println("Miaow!  My name is " + getName() +
        " and I have " + getNumberOfLivesRemaining() +
        " lives remaining");
  }

This class must provide an implementation of the Animal.speak method - recall that this method is not implemented in AnimalImpl, as the logic differs between CatImpl and DogImpl.

Specifying the discriminator value for new instances

public void setNewInstanceDefaults() {
    getDtls().animalType = ANIMAL_TYPE.CAT;
              }

When a new Cat is created, its discriminator value must be set. This is done in the setNewInstanceDefaults method.