Step-by-step instructions

These instructions follow on from what was achieved in the previous lesson.

Add model subproject

  1. in settings.gradle.kts add model to list of subprojects to include

    include("app", "model")
    
  2. see new subproject by running ./gradlew projects

  3. add model directory

  4. add build.gradle.kts in model directory

  5. in build script apply java-library plugin

    plugins {
        `java-library`
    }
    
  6. in model add directories src/main/java

  7. add com.tomgregory.maxirail.model package

  8. add TrainTime.java class

    package com.tomgregory.maxirail.model;
    
    import java.time.LocalTime;
    
    public record TrainTime(String departureStation, String destinationStation,
                            LocalTime departureTime, LocalTime arrivalTime) {
    }
    
  9. Run ./gradlew build and see build directory is created in model

Add service subproject

  1. in settings.gradle.kts add service to list of subprojects to include

    include("app", "model", "service")
    
  2. add service directory

  3. add build.gradle.kts in service directory

  4. in build script apply java-library plugin

    plugins {
        `java-library`
    }
    
  5. in build script add spring-boot-starter dependency

    dependencies {
        implementation("org.springframework.boot:spring-boot-starter:2.6.4")
    }
    
  6. in build script add Maven Central repository

    repositories {
        mavenCentral()
    }
    
  7. create a src/main/java directory

  8. add com.tomgregory.maxirail.service package

  9. add a TrainTimeService.java class

    package com.tomgregory.maxirail.service;
    
    import com.tomgregory.maxirail.model.TrainTime;
    import org.springframework.stereotype.Service;
    
    import java.time.LocalTime;
    import java.util.Arrays;
    import java.util.List;
    
    @Service
    public class TrainTimeService {
        public List<TrainTime> getTrainTimes() {
            return Arrays.asList(
                    new TrainTime("London", "Brighton", LocalTime.of(9, 35), LocalTime.of(10, 30)),
                    new TrainTime("London", "Brighton", LocalTime.of(15, 5), LocalTime.of(16, 0)),
                    new TrainTime("Brighton", "London", LocalTime.of(11, 0), LocalTime.of(12, 0)),
                    new TrainTime("Brighton", "London", LocalTime.of(16, 30), LocalTime.of(17, 30))
            );
        }
    }
    
  10. Notice how TrainTime isn’t available though? Add this project dependency to service’s build script.

    api(project(":model"))
    

Update MaxiRailController

  1. in app subproject’s build script add a dependency on service subproject

    implementation(project(":service"))
    
  2. modify MaxiRailController class to inject TrainTimeService and call its getTrainTimes method

    package com.tomgregory.maxirail.controller;
    
    import com.tomgregory.maxirail.model.TrainTime;
    import com.tomgregory.maxirail.service.TrainTimeService;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    import java.util.List;
    
    @RestController
    public class MaxiRailController {
        private final TrainTimeService trainTimeService;
    
        public MaxiRailController(TrainTimeService trainTimeService) {
            this.trainTimeService = trainTimeService;
        }
    
        @GetMapping(path = "/")
        public List<TrainTime> getTimes() {
            return trainTimeService.getTrainTimes();
        }
    }
    
  3. run ./gradlew bootRun

  4. see updated API response at localhost:8080

Well done! You just created a layered multi-project Java application.

GitHub repository

The gradle-multi-project-masterclass repository contains the final code solution for lessons 2-5.