CodeGym /Courses /Java Server /Scaffold ReadLater Starter

Scaffold ReadLater Starter

Java Server
Level 2, Lesson 2
Available

1. Project scaffold

A project is not just the Main class that gets launched. At the start, it is easy to think: “I created a file, clicked Run — so the project already exists.” But as soon as a second file appears, or you try to run it again a week later, or you start it on another machine, it turns out that a “folder with code” has no memory. It does not explain how to build and run itself.

A Gradle project scaffold is, in essence, an explicit agreement between you and your future self (and also your classmates, reviewer, employer, and your cat, which accidentally pressed Delete). This agreement states where the code lives, where the resources live, which files are considered “official,” what the project is called, which class is the entry point, and why launching happens from the project root with one command rather than the “I checked a box in IDEA” approach.

You can make a rough but useful analogy: a Java file is an ingredient, and the project scaffold is a recipe with temperatures, time, and steps. Ingredients without a recipe can sometimes still be eaten, but the result is often “a salad of everything that was in the fridge.”

2. The final shape of ReadLater Starter

Now we will assemble a minimal structure in which it is immediately clear that this is a Gradle project, it runs through Wrapper, it has build files, code, and resources. This is not the “perfect” structure for all time, but it is a stable base on which we will calmly build the next topics in the course.

And one more important agreement: Wrapper files are not written by hand in this tree. They are already part of the starter project scaffold and are later committed to the repository as part of a single entry point. Below is the exact minimal scaffold that we will later verify through build and run.

Here is the reference tree (the bare minimum):

readlater-starter/
├─ gradlew
├─ gradlew.bat
├─ gradle/
│  └─ wrapper/
│     ├─ gradle-wrapper.jar
│     └─ gradle-wrapper.properties
├─ settings.gradle.kts
├─ build.gradle.kts
├─ README.md
└─ src/
   └─ main/
      ├─ java/
      │  └─ com/
      │     └─ example/
      │        └─ readlater/
      │           ├─ ReadLaterApplication.java
      │           └─ ConsoleBanner.java
      └─ resources/
         └─ application.properties

To keep this tree from remaining just a “scary picture,” it is useful to understand the role of each element once. Below is a compact table you will return to many times. And that is normal.

What it is Where it lives Why it is needed
Wrapper scripts gradlew,
gradlew.bat
A single project entry point: we run Gradle “from the project,” not “from the system.”
Wrapper settings gradle/wrapper/* Pin the Gradle version and allow the required Gradle to be downloaded automatically.
Build name settings.gradle.kts Tells Gradle what the project is called and where the build even begins.
Build rules build.gradle.kts The main file that describes how to build and run the project.
Launch documentation README.md So the project can be launched not “by word of mouth,” but by instructions in the repository.
Java code src/main/java The application’s “production” code: not tests and not configs.
Resources src/main/resources Non-Java files: configs, templates, sample JSON, and so on.

If you are looking at this now and thinking, “Too many folders for a single line in the console,” congratulations — that is the classic correct reaction. That is why in real projects the scaffold is often generated. But in this course, it is important to assemble it by hand once so that the structure is not perceived as magic.

3. Project root: navigation and the foundation for Gradle

The repository root is not the place for “everything at once.” The root is like a dashboard: you glance at it and understand where launching is, where building is, where documentation is, and where the code is. If the root contains dozens of random files, the project starts to look like a Windows desktop after a rough week — everything is somewhere, but you cannot find anything.

In our scaffold, the root contains only what truly is responsible for the project’s life as an artifact: Wrapper, two Gradle files, README, and the src folder. And note an important habit: we do not place Java files next to build.gradle.kts. Code lives in src/main/java because Gradle, and Java ecosystems in general, expect that exact layout. That means fewer surprises.

One more thing worth knowing in advance: later you will get folders like build/ and .gradle/. Gradle creates them itself. These are generated directories, and in a “clean” repository they are usually not kept as source files. We are not creating them by hand now and not examining them in detail yet — just do not be alarmed when you see them.

4. settings.gradle.kts: project name

The settings.gradle.kts file is short but important: it helps Gradle understand what kind of build is in front of it and sets the project name. Beginners often confuse it with build.gradle.kts — and, honestly, their names are not the friendliest. But the roles are different. settings is more about the project as a whole, while build is about build and launch rules.

In our course, we keep settings.gradle.kts as simple as possible. It lives in the root and contains one line that sets the build name. That name will then be visible in logs, in artifact names, and in the general feeling of “what am I building right now.”

Create a settings.gradle.kts file in the root and put this inside:

// Project name that will be visible in logs and artifacts
rootProject.name = "readlater-starter"

Here, the exact name matters less — it can be slightly different — and the principle matters more: the name should be stable, clear, and match what you call the repository. If the repository is called readlater-starter and the Gradle project is called demo-final-v3-real-last, that is, of course, funny... but only for the first 30 seconds.

5. build.gradle.kts: the minimum for building

build.gradle.kts is the main file that usually scares people the most. It looks like code, but it is not your Java code; it is a build description written in Kotlin DSL. It is important to immediately develop a calm attitude: you do not need to understand all of Gradle in order to start normally. At this stage, it is enough for the file to be minimal, readable, and aligned with the course technical baseline: Java 25, Kotlin DSL, and launching through Gradle.

We will now make build.gradle.kts as small as possible while still being useful enough for the project to compile and — a little later — run via ./gradlew run. At the same time, we are deliberately not diving into plugin and dependency details: that will be a separate level. Here we are simply fixing the scaffold.

Let us start with the minimal plugins block. We connect two basic plugins: java and application.

plugins {
    // Plugin for compiling Java code
    java
    // Plugin for launching the application via `gradlew run`
    application
}

These two lines give the project the needed behavior: Gradle starts understanding that Java code must be compiled, and it adds the ability to run the application as a program. Do not think of this as magic — think of it as “turned on Java project mode.”

Now let us add a repository. Even if we are not connecting external libraries yet, a repository is a standard part of the scaffold: later Gradle will download dependencies from there. We use mavenCentral() — this is the most basic option, and it is sufficient for the whole course.

repositories {
    // Main dependency repository for the course
    mavenCentral()
}

Next comes a very important part specifically for our educational baseline: we pin Java 25 through toolchain. This helps keep the project within one “language corridor” and reduces the number of surprises if someone locally has a different JDK version.

java {
    toolchain {
        // Pin the Java version for building, regardless of the local JDK
        languageVersion = JavaLanguageVersion.of(25)
    }
}

And finally, the “glue” that connects the Gradle launch to your entry class. We will agree in advance that the application entry point is called ReadLaterApplication and lives in the com.example.readlater package.

application {
    // Fully qualified name of the class with `public static void main(...)`
    mainClass = "com.example.readlater.ReadLaterApplication"
}

If you put everything together, you get a short and readable build.gradle.kts. I will show it in full, but keep in mind: this is not the “only correct” version, just the minimally sufficient scaffold for the course.

plugins {
    // Compile Java code
    java
    // Add the `run` task to launch the application
    application
}

repositories {
    // Gradle will download dependencies from here
    mavenCentral()
}

java {
    toolchain {
        // Use Java 25 in all environments
        languageVersion = JavaLanguageVersion.of(25)
    }
}

application {
    // Application entry point
    mainClass = "com.example.readlater.ReadLaterApplication"
}

The most useful exercise right now is not to “memorize,” but to learn to recognize these blocks by sight. See plugins — that means “enabled behavior.” See repositories — that means “we know where to download libraries from.” See java.toolchain — that means “we are on Java 25.” See application.mainClass — that means “the application has a clear entry point.”

To connect all this into one picture, you can imagine Gradle doing roughly the following route when launched:

flowchart TD
    A["./gradlew ..."] --> B["settings.gradle.kts
build name"] A --> C["build.gradle.kts
build rules"] C --> D["src/main/java
Java compilation"] C --> E["src/main/resources
resources on classpath"] C --> F["application.mainClass
application launch"]

And yes, it looks like “too many steps for Hello World.” But backend life is like that: it is better to have predictable rules than magic and surprises.

6. src/main/java: application code

The src/main/java folder is the standard place for the main application code. And the important word here is “standard”: Gradle expects the code there by default. If you put ReadLaterApplication.java in the project root or in src/java, you will not “beat the system” — you will just buy yourself a set of strange errors for no reason.

Within the course, we discipline ourselves right away: code goes in src/main/java, and the folder structure inside mirrors the package structure. This simple rule saves a huge amount of time because the IDE, Gradle, and you begin to think the same way.

For now we do not need a complicated package set — we are just starting. So at the current level, one base package com.example.readlater and a couple of classes are enough. Later the project will grow, but the start should be simple and confident.

7. Package com.example.readlater: package and folders

Packages in Java are not decorative text you write “because that is the convention.” A package is the address of your class inside the project. And the address must be consistent: if a class declares package com.example.readlater;, then the file must live in the com/example/readlater folder.

Create the folders:

src/main/java/com/example/readlater

And then put classes there. Why do we use com.example instead of your real domain? Because this is a learning project. In a real product, you would use the company domain in reverse order. Right now it is more important to build a stable habit than to argue about “ideal naming” (spoiler: in a year you will be renaming it anyway).

8. ReadLaterApplication: entry point and banner

A project should have one obvious starting point. In our course, that is ReadLaterApplication. Right now this will be a simple class with main that prints a “I am alive” message and calls a small banner. No business logic and no “architectural” decisions. We only need to prove that the structure is correct and that the project is truly a project, not a single file.

Create the file src/main/java/com/example/readlater/ReadLaterApplication.java:

package com.example.readlater;

public class ReadLaterApplication {
    public static void main(String[] args) {
        // Print the banner — a simple marker that the application started
        ConsoleBanner.print();

        // Main startup message (for now without logging)
        System.out.println("ReadLater Starter is running"); // ReadLater Starter is running
    }
}

Now let us add a second class so you can immediately feel that a project is not one file, and that is normal. Create src/main/java/com/example/readlater/ConsoleBanner.java:

package com.example.readlater;

public final class ConsoleBanner {
    private ConsoleBanner() {
        // Prevent instantiation: this is a utility class
    }

    public static void print() {
        // Banner in the console so the startup is visible by eye
        System.out.println("=== ReadLater Starter ==="); // === ReadLater Starter ===
    }
}

Pay attention to a small engineering detail: ConsoleBanner is marked final and has a private constructor. This is not a “mandatory rule,” but simply an honest way to show intent: this is a utility class, and we do not need instances of it. Yes, we could have kept it simpler. But it is better to get used to neatness where it does not increase cognitive load.

And one more thing: right now we use System.out.println() specifically as a visible startup marker. Later, when we move to logging, you will see a more mature approach. For now, we need the application to make noise and for that to be visible.

9. src/main/resources: configs and resources

The src/main/resources folder is often perceived as “some mysterious thing the IDE creates.” In reality it is a very practical part of the project: this is where files go that should end up in the build and be available to the application as resources. Configuration, templates, sample JSON for mock modes, logback.xml — all of this usually lives here.

Today we will not read resources from Java code and will not build a configuration system — that comes much later. But we create the folder right away because it is part of the scaffold. Even an empty folder works as an anchor: you already know where to put non-Java files, and you do not create chaos with config/, resources2/, new_config_final/.

Create the file src/main/resources/application.properties with minimal placeholder content:

# Application name (for now just a placeholder for the resources structure)
app.name=readlater-starter

Right now this file does not affect program execution at all, and that is normal. We are creating it not for an “instant effect,” but for structural discipline. In real projects, configuration almost never lives in Java code, and the earlier you get used to a separate place for it, the calmer the rest of the course will be.

10. README.md: build and run commands

For a beginner, README often looks like “well, it is a text file, I can do it later.” But README is what makes your project friendly both to another person and to yourself a month later. And friendliness here is measured very simply: if I cloned the repository, opened the README, and immediately understood what to type in the terminal, then the project is speaking to me.

Today we need the minimum: name, requirements, and build/run commands written directly in the repository. We will immediately fix a version for macOS/Linux and Windows so the project does not look like it can only be brought to life from one specific shell.

Create README.md in the root:

# ReadLater Starter

A course project for `Java Server`.

## Requirements
- JDK 25

## Build & Run (macOS / Linux)
./gradlew build
./gradlew run

## Build & Run (Windows)
gradlew.bat build
gradlew.bat run

This looks simple, but it already makes a huge difference compared to a README with just one line, “Open in the IDE and click Run.” Such a README honestly ties execution to the project rather than to personal habits.

11. Common mistakes when assembling a project scaffold

Mistake #1: The Java class is placed “next to build.gradle.kts” instead of in src/main/java.
This often happens when you create a file “quickly, just to test the idea.” Then Gradle cannot find the sources, the IDE pretends to understand everything, and CLI execution falls apart. The fix is one habit: code always lives in src/main/java, without exceptions.

Mistake #2: The folder and the package do not match.
For example, the file is located at src/main/java/com/example/readlater/ReadLaterApplication.java, but inside it says package com.example.app;. The IDE may highlight this, but if you are not used to looking carefully, it is easy to miss. Then strange “Class not found” errors appear at launch. The discipline is simple: the folder path must repeat the package.

Mistake #3: Confusion between settings.gradle.kts and build.gradle.kts.
Beginners sometimes try to write plugins { ... } in settings.gradle.kts or set rootProject.name in build.gradle.kts. Technically there are scenarios where that is possible, but at the start it only causes confusion. Remember the simple model: project name goes in settings, build rules go in build.

Mistake #4: An incorrect mainClass string — a typo or the wrong package.
If build.gradle.kts contains mainClass = "com.example.ReadLaterApplication", but the real class is com.example.readlater.ReadLaterApplication, Gradle will not be able to launch the application. This error is unpleasant because it looks like “Gradle is broken,” while in fact one line is wrong. Check the package in the file and the mainClass line as a pair.

Mistake #5: Creating “extra pockets” for resources.
Sometimes folders like resources/ in the root or src/resources appear. Then configs are placed there, then something else somewhere else — and a week later nobody remembers where anything is. At the start, the cheapest discipline is to immediately create src/main/resources and put non-Java files there, even if they are not used yet.

1
Task
Java Server, level 2, lesson 2
Locked
Base project skeleton with a single entry point
Base project skeleton with a single entry point
Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION