Skip to content

Very basic framework that is inspired on Spring Boot with demo application

Notifications You must be signed in to change notification settings

pino-02/custom-java-framework

Repository files navigation

MVC Framework

Author: Pepijn Theuns


Overview

Welcome to MVC Framework, a lightweight server-side web framework inspired by Spring Web. This framework supports MVC architecture with dynamic view rendering and provides built-in support for controllers, routing, path variables, query parameters, and multiple HTTP verbs.


Getting Started

Create a Web Application Entry Point

Annotate your main application class with @WebApplication to mark it as the starting point:

@WebApplication("be.kdg.prog3")
public class Main {
    public static void main(String[] args) {
        Application.run(Main.class);
    }
}

Here:

  • "be.kdg.prog3" is the base package where the framework will scan for controllers.

Create a Controller

Controllers are annotated with @MvcController and can define route methods with @Get, @Post, etc.

@MvcController
@ControllerPath("/movies")
public class MovieController {

    @Get
    public ModelView getMovies() {
        ModelView modelView = new ModelView();
        modelView.setViewName("movies");

        List<Movie> movies = MovieService.getAllMovies();

        modelView.addObject("movies", movies);
        modelView.addObject("isAdmin", true);
        return modelView;
    }

    @Post("/add")
    public ModelView AddMovie(@QueryVariable("title") String title, @QueryVariable("director") String director, @QueryVariable("year") int year) {
        Movie movie = MovieService.addMovie(title, director, year);

        ModelView modelView = new ModelView();
        modelView.setViewName("detail");
        modelView.addObject("title", movie.getTitle());
        modelView.addObject("director", movie.getDirector());
        modelView.addObject("year", movie.getYear());

        return modelView;
    }
}

Path & Query Variables

Example:

GET http://localhost:8080/movies/1
    @Get("/{id}")
    public ModelView getMovieById(@PathVariable("id") int movieId) {
        ModelView modelView = new ModelView();
        modelView.setViewName("detail");

        Movie movie = MovieService.getMovieById(movieId);

        modelView.addObject("title", movie.getTitle());
        modelView.addObject("director", movie.getDirector());
        modelView.addObject("year", movie.getYear());
        return modelView;
    }

Returning View:

<html>
    <h1>The Shawshank Redemption</h1>
    <table>
        <tr>
            <th>Director</th>
            <td>Frank Darabont</td>
        </tr>
        <tr>
            <th>Year</th>
            <td>1994</td>
        </tr>
    </table>
</html>

View Template

This framework uses a custom XML-based template language defined with ANTLR. These view files should be placed in the folder views inside a resource directory

Supported Tags

  • Variable: ${variableName}
  • If: <if condition="\${conditionVar}"> ... </if>
  • For loop: <for var="item" items="\${listVar}"> ... </for>
  • Plain HTML tags: <html>, <div>, <p>, <span>, <h1>… (see grammar below)
  • Input tag: <input type="text" name="fieldName"/>

Example View

/views/movies.xml

<html>
  <h1>Movie overview</h1>
  <a href="/">Return to home page</a>
  <a href="/movies/watchlist">Watchlist</a>

  <form action="/movies/name" method="GET">
    <input type="text" name="name" placeholder="Search movie by name"/>
    <button type="submit">Search</button>
  </form>

  <ul>
    <for var="movie" items="${movies}">
      <li><a href="/movies/${movie.id}">${movie}</a></li>
    </for>
  </ul>
  <if condition="${isAdmin}">
    <button onclick="location.href= '/movies/form'">Add movie</button>
  </if>
</html>

Processed Output

Variables:

  • Movies: Inception, Goodfellas, The Matrix
  • isAdmin: true
<html>
    <h1>Movie overview</h1>
    <a href="/">Return to home page</a>
    <a href="/movies/watchlist">Watchlist</a>

    <form action="/movies/name" method="GET">
        <input type="text" name="name" placeholder="Search movie by name"/>
        <button type="submit">Search</button>
    </form>

    <ul>
        <li>
            <a href="/movies/1">Inception</a>
        </li>

        <li>
            <a href="/movies/2">Goodfellas</a>
        </li>

        <li>
            <a href="/movies/3">The Matrix</a>
        </li>

    </ul>
    <button onclick="location.href= '/movies/form'">Add movie</button>
</html>

Custom Error view

This framework supports custom error pages for HTTP status codes such as 404 Not Found, 500 Internal Server Error, etc.

The ViewHandler will:

  1. Look for a corresponding XML template in /views/errors/<statusCode>.xml.
  2. If the template exists, it will render it as the error page.
  3. If it does not exist, it will fall back to a default minimal HTML error page.

Example file: /resources/views/errors/404.xml

<html>
  <h1>Page Not Found</h1>
  <p>The page you are looking for does not exist.</p>
  <a href="/">Return Home</a>
</html>

ANTLR Grammar

grammar ViewTemplate;

view
    : element+ EOF
    ;

element
    : tag
    | VARIABLE
    | TEXT
    ;

tag
    : ifTag
    | forTag
    | inputTag
    | plainTag
    ;

ifTag
    : OPEN_IF_TAG element* CLOSE_IF_TAG WS*
    ;

forTag
    : OPEN_FOR_TAG element* CLOSE_FOR_TAG WS*
    ;

inputTag
    : OPEN_INPUT WS*
    ;

plainTag
    : OPEN_PLAIN_TAG element* CLOSE_PLAIN_TAG WS*
    ;

OPEN_IF_TAG
    : '<if condition="' VARIABLE '">'
    ;

CLOSE_IF_TAG
    : '</if>'
    ;

OPEN_FOR_TAG
    : '<for var="' ID '" items="' VARIABLE '">'
    ;

CLOSE_FOR_TAG
    : '</for>'
    ;

OPEN_INPUT
    : '<input' ATTRIBUTE* '/>'
    ;

OPEN_PLAIN_TAG
    : '<' KEYWORD ATTRIBUTE* '>'
    ;

CLOSE_PLAIN_TAG
    : '</' KEYWORD '>'
    ;

ATTRIBUTE
    : TEXT '=' STRING
    ;

VARIABLE
    : '${' ID '}'
    ;

TEXT
    : ~[<${}]+
    ;
ID
    : [a-zA-Z_][a-zA-Z0-9_.()]*
    ;

STRING
    : '"' (~["])* '"'
    ;

KEYWORD
    : 'html'
    | 'div'
    | 'p'
    | 'span'
    | 'h1'
    | 'h2'
    | 'h3'
    | 'ul'
    | 'ol'
    | 'li'
    | 'a'
    | 'button'
    | 'table'
    | 'tr'
    | 'th'
    | 'td'
    | 'form'
    ;
WS
    : [ \t\r\n]+ -> skip
    ;

Components

Application

  • Entry point for running your app.
  • Validates @WebApplication annotation.
  • Scans for controllers and registers them.

ComponentScanner

  • Uses Reflections to find classes annotated with @MvcController.

ControllerRegistry

  • Holds:
    • Controller instances
    • Mappings of HTTP method + path → controller method
    • Regex route matching for {variables}

HttpListener

  • Minimal raw socket HTTP listener (no servlet container).
  • Parses request lines, headers, query parameters, and body.
  • Handles /shutdown command for stopping the server.

HttpHandler

  • Finds matching route in ControllerRegistry.
  • Extracts parameters using ArgumentHandler.
  • Invokes controller method & returns HttpResponse.

ArgumentHandler

  • Maps @PathVariable and @QueryVariable values to method parameters.
  • Performs type conversion (String, int, long, double, boolean).

ViewHandler

  • Loads view templates from resources.
  • Returns error pages for missing templates.

ViewRenderer & ViewVisitor

  • Parses templates with ANTLR grammar.
  • Supports:
    • Variable interpolation
    • if conditions
    • for loops
    • Tag rendering

About

Very basic framework that is inspired on Spring Boot with demo application

Resources

Stars

Watchers

Forks

Packages