Version: 1.0.0
Author: Hasina JY
Winter is a work-in-progress clone of the Spring MVC framework written in Java, designed for educational purposes. It implements key MVC features, such as request routing, controller scanning, and view rendering, while remaining lightweight and extensible. This documentation provides instructions for setup, usage, and understanding the framework’s current capabilities.
- Java: Compatible with Java 8 or higher.
- Jakarta EE: Requires Jakarta EE 10 APIs (formerly javax.ee) for servlet functionality.
- Dependencies:
- Gson (for JSON serialization in REST responses).
- No pre-configured build system (manual compilation required).
Winter v1.0.0 is available as a pre-built JAR file, winter.jar
, for easy integration. Alternatively, you can build it manually from source if customization is needed. Choose one of the following options:
-
Download the JAR:
- Obtain
winter.jar
from the Release v1.0.0 assets on GitHub.
- Obtain
-
Add to Your Project:
- Copy
winter.jar
to your web application’s library directory (e.g.,WEB-INF/lib
). - Ensure Jakarta EE 10 libraries (e.g.,
jakarta.servlet-api
) are included in your project’s classpath.
- Copy
Winter does not yet include a pre-configured build system (e.g., Maven, Gradle). Follow these steps to build and install manually:
-
Compile the Source Code:
- Navigate to the
src/
directory. - Compile all
.java
files using a Java compiler (e.g.,javac
).- VS Code Users: Compilation output defaults to the
bin
directory. - Other IDEs: Adjust the output directory as needed.
- VS Code Users: Compilation output defaults to the
- Example command (Linux/macOS):
javac -d bin src/winter/**/*.java
- Navigate to the
-
Package into a JAR:
- Use the provided scripts in the
packaging/
directory:- Linux/macOS: Run
./packaging/package.sh
- Windows: Double-click
packaging/package.bat
- Linux/macOS: Run
- The script generates
winter.jar
in alib/
directory. - Adjust the script if your compilation directory differs from
bin
.
- Use the provided scripts in the
-
Add to Your Project:
- Copy
winter.jar
to your web application’s library directory (e.g.,WEB-INF/lib
). - Ensure Jakarta EE 10 libraries are included in your project’s classpath.
- Copy
Note: For most use cases, Option 1 is recommended for simplicity. Use Option 2 if you need to modify the source code (see Contributing for details).
Configure Winter in your web application’s web.xml
file to enable the front controller and specify the controller package:
<!-- Front controller mapping -->
<servlet>
<servlet-name>FrontController</servlet-name>
<servlet-class>winter.FrontController</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>FrontController</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- Map the path to the package to scan for controllers -->
<context-param>
<param-name>ControllersPackage</param-name>
<param-value>com.example.controllers</param-value>
</context-param>
- FrontController: Maps all URLs (
/
) towinter.FrontController
, which handles request routing. - ControllersPackage: Specifies the package (e.g.,
com.example.controllers
) containing classes annotated with@Controller
.
-
FrontController:
- Located at
src/winter/FrontController.java
. - Intercepts all incoming requests, routes them to mapped controller methods, and handles responses (HTML or JSON).
- Supports multipart requests via
@MultipartConfig
.
- Located at
-
ControllerScanner:
- Scans the specified package for
@Controller
-annotated classes during initialization. - Registers URL mappings in a static
Map<String, Mapping>
.
- Scans the specified package for
-
ControllerHandler:
- Invokes controller methods, manages parameter binding (via
@RequestParam
), and injectsSession
objects.
- Invokes controller methods, manages parameter binding (via
-
ExceptionHandler:
- Logs exceptions and sends styled HTML error responses (e.g., 404, 500) using Tailwind CSS.
-
@Controller
:- Marks a class as a controller for scanning and routing.
- Example:
@Controller public class UserController {}
-
@UrlMapping
:- Defines URL paths for classes or methods (e.g.,
@UrlMapping("/users")
). - Can be class-level (prefix) or method-level (endpoint).
- Defines URL paths for classes or methods (e.g.,
-
@GET
,@POST
:- Maps methods to HTTP GET or POST verbs.
- Example:
@GET @UrlMapping("/list") public String listUsers() {}
-
@Rest
:- Marks methods as REST endpoints, returning JSON instead of rendering views.
- Example:
@Rest @GET @UrlMapping("/api/data") public String getData() {}
-
@RequestParam
:- Binds request parameters to method arguments or fields.
- Attributes:
value
(name),type
(e.g.,TEXT
,EMAIL
),required
(true/false). - Example:
@RequestParam(value = "email", type = RequestParamType.EMAIL, required = true)
-
Mapping
:- Stores a URL’s associated controller class and methods, keyed by HTTP verbs.
-
MappingMethod
:- Encapsulates a controller method, its verb, and authentication roles.
-
ModelView
:- Holds a JSP URL and a data map for view rendering.
- Example:
return new ModelView("users.jsp").addObject("users", userList);
-
JsonString
:- Wraps a string for JSON responses in REST methods.
-
Session
:- Abstracts
HttpSession
for session management (e.g.,session.add("user", userObj)
).
- Abstracts
- HTTP 404: Sent when no mapping matches the requested URL (
MappingNotFoundException
). - HTTP 500: Sent for critical errors, including:
- Missing package provider (
PackageProviderNotFoundException
). - Invalid package name (
InvalidPackageNameException
). - Duplicate mappings (
DuplicateMappingException
). - Invalid return types (
InvalidReturnTypeException
). - Unexpected exceptions.
- Missing package provider (
package com.example.controllers;
import winter.data.annotation.Controller;
import winter.data.annotation.http.requestverb.GET;
import winter.data.annotation.http.UrlMapping;
import winter.data.client.ModelView;
@Controller
@UrlMapping("/users")
public class UserController {
@GET
@UrlMapping("/list")
public ModelView listUsers() {
ModelView mv = new ModelView("users.jsp");
mv.addObject("message", "User List");
return mv;
}
}
- URL:
/users/list
- Result: Forwards to
users.jsp
with"message"
attribute.
package com.example.controllers;
import winter.data.annotation.Controller;
import winter.data.annotation.Rest;
import winter.data.annotation.http.requestverb.GET;
import winter.data.annotation.http.UrlMapping;
@Controller
@UrlMapping("/api")
public class ApiController {
@Rest
@GET
@UrlMapping("/data")
public String getData() {
return "Hello there!";
}
}
- URL:
/api/data
- Result: Returns
Hello there!
as JSON.
package com.example.controllers;
import winter.data.annotation.Controller;
import winter.data.annotation.http.RequestParam;
import winter.data.annotation.http.requestverb.POST;
import winter.data.annotation.http.UrlMapping;
import winter.data.client.ModelView;
import winter.data.enumdata.RequestParamType;
@Controller
public class FormController {
@POST
@UrlMapping("/submit")
public ModelView submitForm(@RequestParam(value = "email", type = RequestParamType.EMAIL, required = true) String email) {
ModelView mv = new ModelView("result.jsp");
mv.addObject("email", email);
return mv;
}
}
- URL:
/submit
(POST) - Result: Validates
email
parameter; forwards toresult.jsp
or sets error attributes if invalid.
package com.controller.session;
import winter.data.annotation.Controller;
import winter.data.annotation.http.UrlMapping;
import winter.data.servletabstraction.Session;
@Controller
public class SessionSetController {
private Session session;
public void setSession(Session session) {
this.session = session;
}
@UrlMapping("/set-session")
public String setSessionValue() {
session.add("session", "Hasina");
session.add("auth", "manager");
return "Session has been set";
}
}
- URL:
/set-session
- Result: Adds
"session"
and"auth"
attributes to the session with values"Hasina"
and"manager"
, respectively, and returns a confirmation string. TheSession
object is automatically injected byControllerHandler
. The setter method needs to be present.
package com.controller;
import com.models.Person;
import winter.data.annotation.Controller;
import winter.data.annotation.http.RequestParam;
import winter.data.annotation.http.UrlMapping;
import winter.data.annotation.http.requestverb.POST;
import winter.data.client.FormData;
import winter.data.client.ModelView;
@Controller
public class FormController {
@UrlMapping("/person-form")
public ModelView displayPersonForm() {
ModelView modelView = new ModelView("WEB-INF/jsp/person-form.jsp");
modelView.addObject("formData", new FormData());
return modelView;
}
@POST
@UrlMapping("/person-form")
public ModelView processPersonForm(@RequestParam(value = "person") Person person) {
ModelView modelView = new ModelView("WEB-INF/jsp/person-details.jsp");
modelView.addObject("errorUrl", "WEB-INF/jsp/person-form.jsp");
if (person != null) {
modelView.addObject("name", person.getName());
modelView.addObject("age", person.getAge());
}
return modelView;
}
}
- URL:
- GET
/person-form
: Displays the form. - POST
/person-form
: Processes form submission.
- GET
- Result:
- The GET method renders
person-form.jsp
with an emptyFormData
object for initial form display. - The POST method maps form data to a
Person
object using@RequestParam
, expecting fields likeperson.name
andperson.age
. It rendersperson-details.jsp
with the extracted data or redirects toperson-form.jsp
on validation errors (viaerrorUrl
).
- The GET method renders
-
winter.FrontController
:- Methods:
init()
,doGet()
,doPost()
,getUrlMappings()
. - Handles all requests and initializes mappings.
- Methods:
-
winter.service.ControllerScanner
:- Method:
scanControllers(ServletContext)
. - Scans and registers controllers.
- Method:
-
winter.data.client.ModelView
:- Methods:
addObject(String, Object)
,setRequestAttributes(HttpServletRequest)
,getJsonData()
. - Manages view data and JSP forwarding.
- Methods:
@Controller
: Marks controller classes.@UrlMapping
: Defines URL paths.@GET
,@POST
: Specifies HTTP verbs.@Rest
: Indicates REST endpoints.@RequestParam
: Binds request parameters.
- 404 Not Found: Ensure the URL matches a
@UrlMapping
and the verb is supported. - 500 Internal Server Error:
- Check
web.xml
for correctControllersPackage
. - Verify package name syntax (e.g.,
com.example.controllers
). - Ensure unique
@UrlMapping
values. - Confirm controller methods return
String
orModelView
.
- Check
- Add support for additional HTTP verbs (e.g., PUT, DELETE).
- Implement dependency injection.
- Enhance validation for
@RequestParam
. - Add a build system (e.g., Maven).
Contributions are welcome! To contribute:
- Fork the repository.
- Implement features or improvements.
- Add Javadoc and comments where applicable.
- Submit a pull request.
Focus areas:
- Replicating more Spring MVC features.
- Code optimization.
- Documentation expansion.
Licensed under the MIT License. See LICENSE for details.