Skip to content

3.2.2 Defining repository interfaces

Fortunately, we’ve already created IngredientRepository and OrderRepository, so much of the work in defining our repositories is already done. But we’ll need to make a subtle change to them in order to use them with Spring Data JDBC.

Spring Data will automatically generate implementations for our repository interfaces at run time. But it will do that only for interfaces that extend one of the repository interfaces provided by Spring Data. At the very least, our repository interfaces will need to extend Repository so that Spring Data knows to create the implementation automatically. For example, here’s how you might write IngredientRepository such that it extends Repository:

java
package tacos.data;
import java.util.Optional;
import org.springframework.data.repository.Repository;
import tacos.Ingredient;

public interface IngredientRepository
    extends Repository<Ingredient, String> {

  Iterable<Ingredient> findAll();

  Optional<Ingredient> findById(String id);

  Ingredient save(Ingredient ingredient);

}

As you can see, the Repository interface is parameterized. The first parameter is the type of the object to be persisted by this repository—in this case, Ingredient. The second parameter is the type of the persisted object’s ID field. For Ingredient, that’s String.

Although IngredientRepository will work as shown here by extending Repository, Spring Data also offers CrudRepository as a base interface for common operations, including the three methods we’ve defined in IngredientRepository. So, instead of extending Repository, it’s often easier to extend CrudRepository, as shown next.

java
package tacos.data;

import org.springframework.data.repository.CrudRepository;

import tacos.Ingredient;

public interface IngredientRepository
      extends CrudRepository<Ingredient, String> {
}

Similarly, our OrderRepository can extend CrudRepository as shown in the next listing.

java
package tacos.data;

import org.springframework.data.repository.CrudRepository;

import tacos.TacoOrder;

public interface OrderRepository
      extends CrudRepository<TacoOrder, Long> {

}

In both cases, because CrudRepository already defines the methods you need, there’s no need to explicitly define them in the IngredientRepository and OrderRepository interfaces.

And now you have your two repositories. You might be thinking that you need to write the implementations for both repositories, including the dozen methods defined in CrudRepository. But that’s the good news about Spring Data—there’s no need to write an implementation! When the application starts, Spring Data automatically generates an implementation on the fly. This means the repositories are ready to use from the get-go. Just inject them into the controllers and you’re done.

What’s more, because Spring Data automatically creates implementations of these interfaces at run time, you no longer need the explicit implementations in JdbcIngredientRepository and JdbcOrderRepository. You can delete those two classes and never look back!

Released under the MIT License.