eBook – Guide Spring Cloud – NPI EA (cat=Spring Cloud)
announcement - icon

Let's get started with a Microservice Architecture with Spring Cloud:

>> Join Pro and download the eBook

eBook – Mockito – NPI EA (tag = Mockito)
announcement - icon

Mocking is an essential part of unit testing, and the Mockito library makes it easy to write clean and intuitive unit tests for your Java code.

Get started with mocking and improve your application tests using our Mockito guide:

Download the eBook

eBook – Java Concurrency – NPI EA (cat=Java Concurrency)
announcement - icon

Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.

Get started with understanding multi-threaded applications with our Java Concurrency guide:

>> Download the eBook

eBook – Reactive – NPI EA (cat=Reactive)
announcement - icon

Spring 5 added support for reactive programming with the Spring WebFlux module, which has been improved upon ever since. Get started with the Reactor project basics and reactive programming in Spring Boot:

>> Join Pro and download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Jackson – NPI EA (cat=Jackson)
announcement - icon

Do JSON right with Jackson

Download the E-book

eBook – HTTP Client – NPI EA (cat=Http Client-Side)
announcement - icon

Get the most out of the Apache HTTP Client

Download the E-book

eBook – Maven – NPI EA (cat = Maven)
announcement - icon

Get Started with Apache Maven:

Download the E-book

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

eBook – RwS – NPI EA (cat=Spring MVC)
announcement - icon

Building a REST API with Spring?

Download the E-book

Course – LS – NPI EA (cat=Jackson)
announcement - icon

Get started with Spring and Spring Boot, through the Learn Spring course:

>> LEARN SPRING
Course – RWSB – NPI EA (cat=REST)
announcement - icon

Explore Spring Boot 3 and Spring 6 in-depth through building a full REST API with the framework:

>> The New “REST With Spring Boot”

Course – LSS – NPI EA (cat=Spring Security)
announcement - icon

Yes, Spring Security can be complex, from the more advanced functionality within the Core to the deep OAuth support in the framework.

I built the security material as two full courses - Core and OAuth, to get practical with these more complex scenarios. We explore when and how to use each feature and code through it on the backing project.

You can explore the course here:

>> Learn Spring Security

Course – LSD – NPI EA (tag=Spring Data JPA)
announcement - icon

Spring Data JPA is a great way to handle the complexity of JPA with the powerful simplicity of Spring Boot.

Get started with Spring Data JPA through the guided reference course:

>> CHECK OUT THE COURSE

Partner – Moderne – NPI EA (cat=Spring Boot)
announcement - icon

Refactor Java code safely — and automatically — with OpenRewrite.

Refactoring big codebases by hand is slow, risky, and easy to put off. That’s where OpenRewrite comes in. The open-source framework for large-scale, automated code transformations helps teams modernize safely and consistently.

Each month, the creators and maintainers of OpenRewrite at Moderne run live, hands-on training sessions — one for newcomers and one for experienced users. You’ll see how recipes work, how to apply them across projects, and how to modernize code with confidence.

Join the next session, bring your questions, and learn how to automate the kind of work that usually eats your sprint time.

Course – LJB – NPI EA (cat = Core Java)
announcement - icon

Code your way through and build up a solid, practical foundation of Java:

>> Learn Java Basics

1. Overview

Nowadays, from social networking to banking, healthcare to government services, all activities are available online. Therefore, they rely heavily on web applications.

A web application enables users to consume/enjoy the online services provided by a company. At the same time, it acts as an interface to the backend software.

In this introductory tutorial, we’ll explore the Apache Tapestry web framework and create a simple web application using the basic features that it provides.

2. Apache Tapestry

Apache Tapestry is a component-based framework for building scalable web applications.

It follows the convention-over-configuration paradigm and uses annotations and naming conventions for configurations.

All the components are simple POJOs. At the same time, they are developed from scratch and have no dependencies on other libraries.

Along with Ajax support, Tapestry also has great exception reporting capabilities. It provides an extensive library of built-in common components as well.

Among other great features, a prominent one is the hot reloading of the code. Therefore, using this feature, we can see the changes instantly in the development environment.

3. Setup

Apache Tapestry requires a simple set of tools to create a web application:

  • Java 1.6 or later
  • Build Tool (Maven or Gradle)
  • IDE (Eclipse or IntelliJ)
  • Application Server (Tomcat or Jetty)

In this tutorial, we’ll use the combination of Java 8, Maven, Eclipse, and Jetty Server.

To set up the latest Apache Tapestry project, we’ll use Maven archetype and follow the instructions provided by the official documentation:

$ mvn archetype:generate -DarchetypeCatalog=http://tapestry.apache.org

Or, if we have an existing project, we can simply add the tapestry-core Maven dependency to the pom.xml:

<dependency>
    <groupId>org.apache.tapestry</groupId>
    <artifactId>tapestry-core</artifactId>
    <version>5.4.5</version>
</dependency>

Once we’re ready with the setup, we can start the application apache-tapestry by the following Maven command:

$ mvn jetty:run

By default, the app will be accessible at localhost:8080/apache-tapestry:

homepage

4. Project Structure

Let’s explore the project layout created by Apache Tapestry:

tree structure

We can see a Maven-like project structure, along with a few packages based on conventions.

The Java classes are placed in src/main/java and categorized as components, pages, and services.

Likewise, src/main/resources hold our templates (similar to HTML files) — these have the .tml extension.

For every Java class placed under components and pages directories, a template file with the same name should be created.

The src/main/webapp directory contains resources like images, stylesheets, and JavaScript files. Similarly, testing files are placed in src/test.

Last, src/site will contain the documentation files.

For a better idea, let’s take a look at the project structure opened in Eclipse IDE:

project structure

5. Annotations

Let’s discuss a few handy annotations provided by Apache Tapestry for day-to-day use. Going forward, we’ll use these annotations in our implementations.

5.1. @Inject

The @Inject annotation is available in the org.apache.tapestry5.ioc.annotations package and provides an easy way to inject dependencies in Java classes.

This annotation is quite handy to inject an asset, block, resource, and service.

5.2. @InjectPage

Available in the org.apache.tapestry5.annotations package, the @InjectPage annotation allows us to inject a page into another component. Also, the injected page is always a read-only property.

5.3. @InjectComponent

Similarly, the @InjectComponent annotation allows us to inject a component defined in the template.

5.4. @Log

The @Log annotation is available in the org.apache.tapestry5.annotations package and is handy to enable the DEBUG level logging on any method. It logs method entry and exit, along with parameter values.

5.5. @Property

Available in the org.apache.tapestry5.annotations package, the @Property annotation marks a field as a property. At the same time, it automatically creates getters and setters for the property.

5.6. @Parameter

Similarly, the @Parameter annotation denotes that a field is a component parameter.

6. Page

So, we’re all set to explore the basic features of the framework. Let’s create a new Home page in our app.

First, we’ll define a Java class Home in the pages directory in src/main/java:

public class Home {
}

6.1. Template

Then, we’ll create a corresponding Home.tml template in the pages directory under src/main/resources.

A file with the extension .tml (Tapestry Markup Language) is similar to an HTML/XHTML file with XML markup provided by Apache Tapestry.

For instance, let’s have a look at the Home.tml template:

<html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_4.xsd">
    <head>
        <title>apache-tapestry Home</title>
    </head>
    <body>
        <h1>Home</h1>
    </body>   
</html>

Voila! Simply by restarting the Jetty server, we can access the Home page at localhost:8080/apache-tapestry/home:

home1

6.2. Property

Let’s explore how to render a property on the Home page.

For this, we’ll add a property and a getter method in the Home class:

@Property
private String appName = "apache-tapestry";

public Date getCurrentTime() {
    return new Date();
}

To render the appName property on the Home page, we can simply use ${appName}.

Similarly, we can write ${currentTime} to access the getCurrentTime method from the page.

6.3. Localization

Apache Tapestry provides integrated localization support. As per convention, a page name property file keeps the list of all the local messages to render on the page.

For instance, we’ll create a home.properties file in the pages directory for the Home page with a local message:

introMsg=Welcome to the Apache Tapestry Tutorial

The message properties are different from the Java properties.

For the same reason, the key name with the message prefix is used to render a message property — for instance, ${message:introMsg}.

6.4. Layout Component

Let’s define a basic layout component by creating the Layout.java class. We’ll keep the file in the components directory in src/main/java:

public class Layout {
    @Property
    @Parameter(required = true, defaultPrefix = BindingConstants.LITERAL)
    private String title;
}

Here, the title property is marked required, and the default prefix for binding is set as literal String.

Then, we’ll write a corresponding template file Layout.tml in the components directory in src/main/resources:

<html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_4.xsd">
    <head>
        <title>${title}</title>
    </head>
    <body>
        <div class="container">
            <t:body />
            <hr/>
            <footer>
                <p>&copy; Your Company</p>
            </footer>
        </div>
    </body>
</html>

Now, let’s use the layout on the home page:

<html t:type="layout" title="apache-tapestry Home" 
    xmlns:t="http://tapestry.apache.org/schema/tapestry_5_4.xsd">
    <h1>Home! ${appName}</h1>
    <h2>${message:introMsg}</h2>
    <h3>${currentTime}</h3>
</html>

Note, the namespace is used to identify the elements (t:type and t:body) provided by Apache Tapestry. At the same time, the namespace also provides components and attributes.

Here, the t:type will set the layout on the home page. And, the t:body element will insert the content of the page.

Let’s take a look at the Home page with the layout:

homepage2-1

7. Form

Let’s create a Login page with a form, to allow users to sign-in.

As already explored, we’ll first create a Java class Login:

public class Login {
    // ...
    @InjectComponent
    private Form login;

    @Property
    private String email;

    @Property
    private String password;
}

Here, we’ve defined two properties — email and password. Also, we’ve injected a Form component for the login.

Then, let’s create a corresponding template login.tml:

<html t:type="layout" title="apache-tapestry com.example"
      xmlns:t="http://tapestry.apache.org/schema/tapestry_5_3.xsd"
      xmlns:p="tapestry:parameter">
    <t:form t:id="login">
        <h2>Please sign in</h2>
        <t:textfield t:id="email" placeholder="Email address"/>
        <t:passwordfield t:id="password" placeholder="Password"/>
        <t:submit class="btn btn-large btn-primary" value="Sign in"/>
    </t:form>
</html>

Now, we can access the login page at localhost:8080/apache-tapestry/login:

login-1

8. Validation

Apache Tapestry provides a few built-in methods for form validation. It also provides ways to handle the success or failure of the form submission.

The built-in method follows the convention of the event and the component name. For instance, the method onValidationFromLogin will validate the Login component.

Likewise, methods like onSuccessFromLogin and onFailureFromLogin are for success and failure events respectively.

So, let’s add these built-in methods to the Login class:

public class Login {
    // ...
    
    void onValidateFromLogin() {
        if (email == null)
            System.out.println("Email is null);

        if (password == null)
            System.out.println("Password is null);
    }

    Object onSuccessFromLogin() {
        System.out.println("Welcome! Login Successful");
        return Home.class;
    }

    void onFailureFromLogin() {
        System.out.println("Please try again with correct credentials");
    }
}

9. Alerts

Form validation is incomplete without proper alerts. Not to mention, the framework also has built-in support for alert messages.

For this, we’ll first inject the instance of the AlertManager in the Login class to manage the alerts. Then, replace the println statements in existing methods with the alert messages:

public class Login {
    // ...
    @Inject
    private AlertManager alertManager;

    void onValidateFromLogin() {
        if(email == null || password == null) {
            alertManager.error("Email/Password is null");
            login.recordError("Validation failed"); //submission failure on the form
        }
    }
 
    Object onSuccessFromLogin() {
        alertManager.success("Welcome! Login Successful");
        return Home.class;
    }

    void onFailureFromLogin() {
        alertManager.error("Please try again with correct credentials");
    }
}

Let’s see the alerts in action when the login fails:

loginfail-1

10. Ajax

So far, we’ve explored the creation of a simple home page with a form. At the same time, we’ve seen the validations and support for alert messages.

Next, let’s explore the Apache Tapestry’s built-in support for Ajax.

First, we’ll inject the instance of the AjaxResponseRenderer and Block component in the Home class. Then, we’ll create a method onCallAjax for processing the Ajax call:

public class Home {
    // ....

    @Inject
    private AjaxResponseRenderer ajaxResponseRenderer;
    
    @Inject
    private Block ajaxBlock;

    @Log
    void onCallAjax() {
        ajaxResponseRenderer.addRender("ajaxZone", ajaxBlock);
    }
}

Also, we need to make a few changes in our Home.tml.

First, we’ll add the eventLink to invoke the onCallAjax method. Then, we’ll add a zone element with id ajaxZone to render the Ajax response.

Last, we need to have a block component that will be injected in the Home class and rendered as Ajax response:

<p><t:eventlink event="callAjax" zone="ajaxZone" class="btn btn-default">Call Ajax</t:eventlink></p>
<t:zone t:id="ajaxZone"></t:zone>
<t:block t:id="ajaxBlock">
    <hr/>
    <h2>Rendered through Ajax</h2>
    <p>The current time is: <strong>${currentTime}</strong></p>
</t:block>

Let’s take a look at the updated home page:

home-1

Then, we can click the Call Ajax button and see the ajaxResponseRenderer in action:

homeAjax

11. Logging

To enable the built-in logging feature, the instance of the Logger is required to be injected. Then, we can use it to log at any level like TRACE, DEBUG, and INFO.

So, let’s make the required changes in the Home class:

public class Home {
    // ...

    @Inject
    private Logger logger;

    void onCallAjax() {
        logger.info("Ajax call");
        ajaxResponseRenderer.addRender("ajaxZone", ajaxBlock);
    }
}

Now, when we click the Call Ajax button, the logger will log at the INFO level:

[INFO] pages.Home Ajax call

12. Conclusion

In this article, we’ve explored the Apache Tapestry web framework.

To begin with, we’ve created a quickstart web application and added a Home page using basic features of Apache Tapestry, like components, pages, and templates.

Then, we’ve examined a few handy annotations provided by Apache Tapestry to configure a property and component/page injection.

Last, we’ve explored the built-in Ajax and logging support provided by the framework.

The code backing this article is available on GitHub. Once you're logged in as a Baeldung Pro Member, start learning and coding on the project.
Baeldung Pro – NPI EA (cat = Baeldung)
announcement - icon

Baeldung Pro comes with both absolutely No-Ads as well as finally with Dark Mode, for a clean learning experience:

>> Explore a clean Baeldung

Once the early-adopter seats are all used, the price will go up and stay at $33/year.

eBook – HTTP Client – NPI EA (cat=HTTP Client-Side)
announcement - icon

The Apache HTTP Client is a very robust library, suitable for both simple and advanced use cases when testing HTTP endpoints. Check out our guide covering basic request and response handling, as well as security, cookies, timeouts, and more:

>> Download the eBook

eBook – Java Concurrency – NPI EA (cat=Java Concurrency)
announcement - icon

Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.

Get started with understanding multi-threaded applications with our Java Concurrency guide:

>> Download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

Course – LS – NPI EA (cat=REST)

announcement - icon

Get started with Spring Boot and with core Spring, through the Learn Spring course:

>> CHECK OUT THE COURSE

Partner – Moderne – NPI EA (tag=Refactoring)
announcement - icon

Modern Java teams move fast — but codebases don’t always keep up. Frameworks change, dependencies drift, and tech debt builds until it starts to drag on delivery. OpenRewrite was built to fix that: an open-source refactoring engine that automates repetitive code changes while keeping developer intent intact.

The monthly training series, led by the creators and maintainers of OpenRewrite at Moderne, walks through real-world migrations and modernization patterns. Whether you’re new to recipes or ready to write your own, you’ll learn practical ways to refactor safely and at scale.

If you’ve ever wished refactoring felt as natural — and as fast — as writing code, this is a good place to start.

eBook Jackson – NPI EA – 3 (cat = Jackson)