Jodd µicro frameworks

Java is not just for the enterprise. Making web apps doesn't have to be complicated. You don't have to be a coding ninja to kickstart your idea... but if you are one, you would appreciate the simplicity.

Jodd is just that. Set of open-source micro frameworks, designed to make things simple, but not simpler. Get things done. Build your beautiful ideas. Run your startup. And enjoy the coding.

The best way to learn Jodd is through the example. That's what we have here: step-by-step example of how to build a web application with just Jodd. In just 30 minutes, you will get an overview of some cool Jodd micro frameworks.

TL;DR?

What can I expect from Jodd?

Developer-friendly experience Excellent performances Small memory footprint and code-base; under 1.5 MB Fast redeployments, matter of seconds Elegant web framework Slick and lightweight DI container The fastest and unique proxy creator Efficient and thin database layers Transactions manager Focused validation framework Fast and versatile HTML parser Decoration framework based on templates Fastest bean library Elegant and precise time class Powerful properties replacement Tiny and raw HTTP client Many carefully selected utilities... and more!

http://jodd.org

Think Lightweight, Be Awesome, Get Things Done!

Click on buttons
to see more details!
1

Prepare Yourself

Let's create webapp from scratch: simple app that shows messages and their responses.

Folders

In the project root, create standard Maven folder layout for web projects.


/root
    /src
        /main
            /java
            /resources
            /webapp
        /test
        

Gradle

We will use Gradle for building; be sure to have it installed. Create simple build.gradle script and add just two dependencies: Jodd Joy and MySql database driver. That's all what we need :)


apply plugin: 'java'        
version = '1.0'
repositories {
    mavenCentral()
}
dependencies {
    compile 'org.jodd:jodd-joy:3.5'
    runtime 'mysql:mysql-connector-java:5.1.26'
}           
        

Execute the following command in project root: gradle wrapper to initialize your Gradle project. This will create a shell script gradlew[.bat] in your root that you can use now on to run the build process.

IDE

Once when empty project can be built successfully from command line, import it in your IDE. Create web artifact that can be deployed from project folders. IntelliJ IDEA works very nicely with this setup.

Database

It's time to create the database: jodd-example in MySql. Create two tables: jd_message and jd_response; one message may have several responses.


CREATE TABLE jd_message (
    message_id INT UNSIGNED NOT NULL AUTO_INCREMENT,
    text VARCHAR(1000) NOT NULL,
    PRIMARY KEY (message_id)
);
CREATE TABLE jd_response (
    response_id INT UNSIGNED NOT NULL AUTO_INCREMENT,
    text VARCHAR(1000) NOT NULL,
    message_id INT UNSIGNED NOT NULL,
    PRIMARY KEY (response_id),
    FOREIGN KEY (message_id) REFERENCES jd_message(message_id)
);          
        

Add some dummy data to database.

Tomcat

Don't forget the Tomcat! Download and unzip Tomcat bundle. You may delete it's default web application. Setup your IDE to be aware of Tomcat installation.

View more »

2

Build The Core

The first and foremost is to build the simplest web app that works. Our application consists of two layers: the application core (unaware of the web layer); and the web application itself. Let's create these two classes:

  • AppCore - initializes and runs our application,
  • AppWebApplication - prepares web layer & binds AppCore to it.

Jodd already has convenient bases classes we can reuse.


public class AppCore extends DefaultAppCore {
    @Override
    protected void initLogger() {
        LoggerFactory.setLoggerFactory(
            new SimpleLoggerFactory(Logger.Level.DEBUG));
        super.initLogger();
    }
}
        

public class AppWebAplication extends DefaultWebApplication {
    @Override
    protected DefaultAppCore createAppCore() {
        return new AppCore();
    }
}
        

AppCore creates and registers everything needed for common web application. We just want to turn on the logger, using simple implementation that prints out to the console. AppWebAplication has just one task (for now) - to create the new application core, that runs the whole application.

web.xml

We need to register our web application in the web.xml. Common way is to define MadvocContextListener and pass web app class name as madvoc.webapp context parameter. We also need to register MadvocServletFilter to dispatch all requests to our web application.


<web-app ...>

    <listener>
        <listener-class>
            jodd.madvoc.MadvocContextListener
        </listener-class>
    </listener>

    <context-param>
        <param-name>madvoc.webapp</param-name>
        <param-value>
            jodd.example.AppWebAplication
        </param-value>
    </context-param>
    <context-param>
        <param-name>madvoc.params</param-name>
        <param-value>/madvoc.props</param-value>
    </context-param>

    <listener>
        <listener-class>
            jodd.servlet.RequestContextListener
        </listener-class>
    </listener>

    <filter>
        <filter-name>madvoc</filter-name>
        <filter-class>
            jodd.madvoc.MadvocServletFilter
        </filter-class>
    </filter>
    <filter-mapping>
        <filter-name>madvoc</filter-name>
        <url-pattern>/*</url-pattern>
        <dispatcher>REQUEST</dispatcher>
    </filter-mapping>

    <jsp-config>
        <jsp-property-group>
            <url-pattern>*.jsp</url-pattern>
            <page-encoding>UTF-8</page-encoding>
        </jsp-property-group>
    </jsp-config>    
</web-app>
        

We have more stuff in web.xml that we gonna actually use (e.g. RequestContextListener). That's fine - it's to good to have it all here.

app.props

By convention, default application properties are stored in file app.props, located in classpath root. Of course, we should use Jodd Props for more powerful properties. The initial content of this file is just settings of the database connection and the pool.


# database
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/jodd-example
jdbc.username=root
jdbc.password=root!

# db pool
dbpool.driver=${jdbc.driverClassName}
dbpool.url=${jdbc.url}
dbpool.user=${jdbc.username}
dbpool.password=${jdbc.password}
dbpool.maxConnections=50
dbpool.minConnections=5
dbpool.waitIfBusy=true
        

Run!

That is all for this step - you have just built the simplest Jodd application using Joy.

This is how project looks like:

Yes, you can start Tomcat if you want and check that everything works. There is nothing special to see as we haven't added any logic yet. Just observe Tomcat's log.

View more »

3

Show Some Messages

We can start coding our application now! Let's display last 10 messages on the index page.

Model

We need two model classes: Message and Response. These will be mapped to database tables. As they are simple POJOs, we just need to mark them with appropriate database mapping annotations.

Message class:


@DbTable
public class Message {

    @DbId
    private long messageId;

    @DbColumn
    private String text;

    // ...getters and setters...
}
        

... and response class:


@DbTable
public class Response {

    @DbId
    private long responseId;

    @DbColumn
    private String text;

    @DbColumn
    private long messageId;

    // ...getters and setters...
}
        

Once again, simple POJO beans with annotations.

Note that we didn't said anything about relationship between these two entities. We will discuss this in more details later; for now just keep in mind that Jodd is all about mapping, so relations are not defined up in front. Instead, you define them with your queries when needed.

Database conventions

An addition is required in application properties: app.props. We need to describe the database mapping naming conventions. In our case all tables have the prefix and both table and column names are in lowercase. Note that naming convention depends on target database!


# db manager
db.debug=true

# db orm manager
dboom.schemaName=PUBLIC
dboom.tableNames.prefix=jd_
dboom.tableNames.uppercase=false
dboom.columnNames.uppercase=false
        

We have also turned on 'debug' mode for more verbose logs.

Java Service

Finally, it's time to read the database and return results. We are going to write a bean containing the (business) logic. This bean will be marked as @PetiteBean to become registered in the application's Petite container. No other registration is required!

AppCore creates application's Petite container.

Since our method is accessing database, it has to run under database transaction. To enable database session for the method we just need to mark it with transactional annotation.

Instead of SQL, we will write queries using T-SQL (Template SQL). It's an extension to common SQL that provides special macros that may reference our Java entities. This significantly simplifies writing of native SQL queries!


@PetiteBean
public class AppService {
    
    @Transaction
    public List<Message> findLastMessages(int count) {
        DbSqlBuilder dbsql =
            sql("select $C{m.*} from $T{Message m} " + 
            "order by $m.messageId desc limit :count");
        DbOomQuery dbquery = query(dbsql);
        dbquery.setInteger("count", count);

        return dbquery.list(Message.class);
    }
}
        

Our service is simple POJO class, annotated with @PetiteBean annotation. Nothing else is needed, no XML files, registration etc. Moreover, you may use plain SQL queries instead if wish so.

Noticed the @Transaction annotation? Yeah, that is all what is required to supply your database code with transactional database session. Here is one tip: you may even define your own annotations to shorten and simplify annotations! For example, you may define e.g. @ReadOnlyTransaction or @WriteTransaction and use them instead.

Awesome, right?!

View

For our web layer, we need Java class action and JSP that renders the result. Action is simple bean, annotated with @MadvocAction. Created on every request, action is aware of container context so you can inject your services very easily.

    
@MadvocAction
public class IndexAction {

    @PetiteInject
    AppService appService;

    @Out
    List<Message> messages;

    @Action
    public void view() {
        messages = appService.findLastMessages(10);
    }
}
        

Madvoc actions are automatically registered by default. You can change that and use manual registration instead.

Madvoc actions uses simple conventions and smart annotation to define input and outputs, and target JSP. In our example we have just one output, the list of messages.

    
<%@ taglib prefix="j" uri="/jodd" %>
<html>
<body>
<h1>Messages</h1>

<ul>
<j:iter items="${messages}" var="msg">
    <li>${msg.messageId} ${msg.text}
</j:iter>
</ul>
</body>
</html>
        

Another gem for you: there is entire powerful tag library you can use in your JSPs!

Run!

Start Tomcat and go to http://localhost:8080/index.html. If you have some data in the database, you will see last 10 messages!

View more »

4

Messages and Responses

It's time to display related responses of the messages.

Model

Add list of Response objects to the Message class as a simple property. It will hold responses, but only when we want so. That is important to remember: the related responses will not be automatically pre- or lazy-fetched. Instead, we just map them and use when we want to have them.

    
@DbTable
public class Message {

    ...

    private List<Response> responses;

    public List<Response> getResponses() {
        return responses;
    }

}
        

Note how responses is a read-only property. There is no special rule about this, it's just how you want to have it.

Service

To fetch all messages and their (optional) responses, we need left join between two tables. If we just change the query and add an additional mapping, then each row of result set will be mapped to Object[2]: message and it's single response. But we want instead single message filled with all its responses (stored in the new property). Here is how we can do this in an easy way.

First is injection of responses into messages. By using hints we can tell in T-SQL that one result object is going to be injected or added into the property of another resulting object. In our case, we can define that Response object is going to be added into the new list property of Message class.

Second is to prevent repetition of messages with the same id. When message has more then one response, same message data will be repeated in the join results for every response. This would give us many Message instances of the same entity (i.e. with the same ID). To fix this, we just need to enable entityAware mode that caches entities during the life of a query.

    
@Transaction
public List<Message> findLastMessagesWithResponses(int count) {
    DbSqlBuilder dbsql = sql(
            "select $C{m.*}, $C{m.responses:r.*} " +
            "from $T{Message m} " +
            "left join $T{Response r} using ($.messageId) " +
            "order by $m.messageId desc limit :count");

    DbOomQuery dbquery = query(dbsql);
    dbquery.entityAwareMode(true);
    dbquery.setInteger("count", count);
    
    return dbquery.list(Message.class, Response.class);
}
        

When entityAware mode is enabled two effects will happen. First, all entities during the life of a query will be cached, so no two instances of the same entity will exist. Second, result set rows will be compacted if needed. For example, if one message has two responses, that would give two rows in result set. By compacting we will get one message with two responses in the list.

View

Change in the web layer is trivial. Our action has to call the new method and JSP to display message responses.

    
<ul>
<j:iter items="${messages}" var="msg">
    <li>${msg.messageId} ${msg.text}
        <ul>
            <j:iter items="${msg.responses}" var="resp">
                <li>${resp.responseId} ${resp.text}</li>
            </j:iter>
        </ul>
    </li>
</j:iter>
</ul>
        

View more »

5

Add New Message

Let's see now how to add new messages.

Service

Jodd offers shortcuts for common database operation. You don't have to write queries for storing entities, finding them by id or property value, updating, deleting etc. With help of DbEntitySql you can write simple one-liner calls in Java to achieve the same.

    
@Transaction(propagation=PROPAGATION_SUPPORTS, readOnly=false)
public void addMessage(Message message) {
    DbEntitySql
            .insert(message)
            .query().executeUpdateAndClose();
}
        

This time, however, we need to mark service method with different transaction annotation, notifying that transaction is not read-only.

View

Web layer needs more changes this time. We need two more actions: one for showing page with a form, and the other one for handling form submissions. Both actions can be defined in same class. Form handler will also have different extension (e.g. .do) and will catch only POST requests.

    
@MadvocAction
public class MessageAction {

    @PetiteInject
    AppService appService;

    @Action
    public void view() {
    }

    @In
    Message message;

    @Action(extension="do", method="POST")
    public String add() {
        appService.addMessage(message);
        return "redirect:/<index>";
    }
}
        

We have two mappings here: /message.html is mapped to #view() method and /message.add.do to #add() method. First method just renders the form on message.jsp page. Second method stores new message.

    
<html>
<body>
<h1>Add Message</h1>

<form action="/message.add.do" method="POST">
    <textarea name="message.text" rows="5" cols="50">
    </textarea>
    <button type="submit">Submit</button>
</form>

</body>
</html>
        

There is one thing to notice here: the name of the parameter: "message.text". It specifies where input value will be injected to. Since we have message property of the action marked with @In, text value will be inserted into message property text, after new instance of Message is created.

After new message is submitted and stored in database, we need to redirect to index page. While we can do this by hardcoding the index path, there are better ways for doing the same. One is using aliases. Every action method can be named and that name can be used as a handle to real path. So however you change your code, Jodd will find the target path.

    
@MadvocAction
public class IndexAction {

    @Action(alias = "index")
    public void view() {
        ....
    }
}
        

Index action is aliased as: "index".

Alternative

There is even shorter alternative shortcut for basic manipulation over an entity. By using GenericDao (or somewhat enhanced AppDao) you can perform basic database operation using just single method call.


@PetiteInject
AppDao appDao;

@Transaction(propagation=PROPAGATION_SUPPORTS, readOnly=false)
public void addMessageAlt(Message message) {
    appDao.store(message);
}
        

There is another alternative: use Result to specify redirection in web action. With this helper class you will be able to define handle to any action method by virtually calling it! Then you don't need to define any custom alias for actions.

    
@MadvocAction
public class MessageAction {

    final Result result = new Result();

    @Action(extension="do", method="POST")
    public void add() {
        appService.addMessageAlt(message);
        result.redirectTo(IndexAction.class).view();            
    }

}
        

Result instances may not be explicitly instantiated like above. Moreover, you may use any subclass of Result with your additional helper methods.

Alternative code works the same. It's up to you what to use :)

Run

Run your web application again. Go to message page and add new messages. It's fun! :)

View more »

6

What We Have Learned

We hope we were able to show how Jodd can be used to build web applications. You have learned essentials of core Jodd micro-frameworks. There is Petite dependency-injection container for gluing the components. We used Madvoc for the web layer. We talked to database using DbOom mapper, enabling JTX transaction using Proxetta proxies. And all our application components were simple beans, marked just with annotations.

In our example we were using Jodd Joy - an application template for faster web application development. It is quite configurable and it combines the best Jodd practices with pragmatic approach.

Maybe the most important thing to learn from this example is that Jodd does not offer out-of box solution that claims to magically solve all problems. Instead, Jodd provides solid, but lightweight frameworks; giving you the freedom to code your solutions the way you want.

And Beyond!

Many features of Jodd are not covered in this short example. There are more micro-frameworks you would like to have in your application... You may continue by adding Decora page templates for entire site. Then you can optimize resources using HtmlStapler. Why not add authentication and authorization interceptors? Forms may be validated using VTor. Or you can add more proxies using Proxetta. Or you may need to send some emails, fire few HTTP requests, parse some HTML as simple as using jQuery; or just need simple utility methods... It's all there.

http://jodd.org

Built by Igor & friends with LOVE.