Jodd µicro frameworks

We want to inspire the world to create. To use tech skills and build something truly... Awesome. Beautiful. Helpful. Changing. Now you are free to code lightweight and focus to unleash your potential. Jodd is set of developer friendly and open-source Java micro-frameworks; designed to make things simple, but not simpler.

This tutorial is a good place to get an overview of how Jodd works. That's what we have here: a step-by-step example of how to build a web application with just Jodd. In just 30 minutes, you will get from "zero to hero".

Tutorial explains the making of a simple web app from scratch: one that shows messages and message comments stored in the database; like a simple blog.

Let's go!

http://jodd.org

1

Prepare Yourself

The first step is not about the Jodd at all. We will prepare the infrastructure instead: project folders, Gradle, Tomcat and MySql.

Please checkout the tutorial - we have all the files you need already prepared for you!

Folders

In the project's 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 a simple build.gradle script and add the single dependency to Jodd Joy. That's all what we need for now :)

                  
apply plugin: 'war'
version = '1.0'
repositories {
    mavenCentral()
}
dependencies {
    compile 'org.jodd:jodd-joy:4.1.1'
}
          

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

IDE

Once when gradle is set, open the project in your IDE. Create web artifact that can be deployed. IntelliJ IDEA works very nicely with this setup.

Database

It's time to set up the database: jodd-tutorial in the MySql. We have just two tables: jd_message and jd_response: one message may have several comments. Yes, we made a bad decision by naming the 'comments' as 'responses'; please forgive us.

Thanx to Docker, everything is set for you:

            
> cd docker
> docker-compose up -d
          

Tomcat

Don't forget the Tomcat! Download and unzip latest Tomcat bundle. You may delete the default web application. Register new Tomcat installation in your IDE.

View snippets »

2

Build The Core

The first and foremost is to build the simplest web app possible that just works. Let's start!

There are only 3 things we have to do now:

  • Add gradle dependecies,
  • Register web application,
  • Set database connection properties.

Again, the source for this step awaits you on the GitHub!

Gradle dependencies

Obviously, we need to add some more dependencies: for MySql driver and servlets jars.

                
dependencies {
    compile 'org.jodd:jodd-joy:4.1.1'
    runtime 'mysql:mysql-connector-java:5.1.45'

    providedRuntime 'javax.servlet:javax.servlet-api:4.1.0'
    providedRuntime 'javax.servlet.jsp:javax.servlet.jsp-api:2.3.1'
}
          

Web application

While we can register it in web.xml, more convenient way would be to simply create a WebListener based on JoyContextListener class. That is all we need for now: just an empty subclass annotated with @WebListener annotation.

                
@WebListener
  public class AppContextListener extends JoyContextListener {

  }
          

Properties

By default, Jodd Joy properties are stored in the file joy.props, located in the classpath root. Props file is a powerful extension of Java properties. The initial properties just set the database connection and the connection pool.

                
# database
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/jodd-tutorial?useSSL=false
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
      

Make sure that *.props files are being recognized as resources by your IDE.

Run!

And that is all! Just 3 simple steps is all you need to run the web application :)

This is how the project looks like:

Layout

Yes, you can start the Tomcat now and check that everything works. Just watch the Tomcat's log - the app should be up in couple of seconds!

View snippets »

3

Show Me Some Messages

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

This step requires somewhat more coding. Download it all instead! Or go ahead and fire up that keyboard!

Model

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

Message class:

                
@DbTable
public class Message {

    @DbId
    private long messageId;

    @DbColumn
    private String text;

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

... and comments class:

                
@DbTable
public class Response {

    @DbId
    private long responseId;

    @DbColumn
    private String text;

    @DbColumn
    private long messageId;

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

Once again, simple POJOs with Jodd annotations.

Note that we didn't say 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 configuration

It is a good practice to have a prefix for database tables used by the application. We can specify it in Jodd's annotations, but better way would be to specify the default prefix for all entity beans. This is done in joy.props. While there, we can also enable the debug mode for more verbose logs.

                
db.debug=true
db.dbOomConfig.tableNames.prefix=jd_
        
      

Java Service

Finally, it's time to read the database and return the data! 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!

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 {

    @ReadOnlyTransaction
    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 @ReadOnlyTransaction annotation? Yeah, that is all what is required to supply your database code with transactional database session.

Awesome, right?!

View

For the web layer, we need a Madvoc action and JSP that renders the result. Madvoc action is a simple bean, annotated with @MadvocAction. Created on every request, Madvoc action is aware of container's context and you can inject your services 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. You will see last 10 messages!

View snippets »

4

Messages and Comments

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

Only few changes ahead! Still, you may checkout the updates.

Model

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

                
@DbTable
public class Message {

    ...

    private List<Response> responses;

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

}
      

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

Service

To fetch all messages and their (optional) comments, we need a left join between these two tables. If we just change the query and add an additional mapping, then each row of the result set will be mapped to Object[2], holding a message and it's single comment. We don't want that! Instead we want to have a single message filled up with all its comments (stored in the new property). Here is how we can do this in an easy way.

First is to inject comments into messages. By using DbOom 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 comment, the same message data will be repeated in the joined results for every comment. 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 lifetime 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 be applied. First, all entities during the lifetime 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 comments, that would give two rows in the result set. By compacting we will get one message with two comments in the list.

View

The change in the web layer is trivial. Our action has to call the new method and JSP has to display message's comments.

                
<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>
      

If everything goes well, the output should look like this:

output

View snippets »

5

Add A New Message

So far we have been just reading from the database. Let's see now how to add some new messages.

Congratulations, we are almost done! Keep the track with code changes or just type them along with us!

Service

Jodd provides 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.

                
@ReadWriteTransaction
public void addMessage(Message message) {
    DbEntitySql
            .insert(message)
            .query()
            .autoClose()        // not mandatory, but nice
            .executeUpdate();
}
      

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

View

Obviously, the web layer will get more changes. We need two more actions: one for showing a page with a form, and the other for handling form submissions. Both actions can be defined in the same class, which is convenient. The form handler will not have any extension and will handle only POST requests.

          
@MadvocAction
public class MessageAction {

    @PetiteInject
    AppService appService;

    @Action
    public void view() {
    }

    @In
    Message message;

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

This action defines two mappings: /message.html mapped to the #view() method and /message.add mapped to the #add() method. The first action handler just renders the form with the message.jsp page. The second action handler stores submitted message.

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

<form action="/message.add" 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 the submitted value will be injected into. Since we have the 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 the new message is submitted and stored in the database, we want to redirect to the index page. While we can do this by hardcoding the page's path, there are better ways to do the same. One way is using aliases. Every action method has it's alias name and that alias handle represents the path of the action. So even if you change your code and rename the handler method, Jodd will find the aliased target path.

Alternative

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

                
@PetiteInject
AppDao appDao;

@ReadWriteTransaction
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();

    @POST @Action
    public void add() {
        appService.addMessageAlt(message);
        result.redirectTo(IndexAction.class).view();
    }

}
      

Result instances doesn't have to 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 :) That makes Jodd beautiful :)

Run

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

View snippets »

6

Give Me Some REST!

Jodd is very flexible: there are always few different ways how to achieve the same thing. Adding REST api is easy: instead of using @Action, we can use @RestAction instead! Note that each annotation comes with different configuration. The @RestAction uses different mapping convention: action method names now should start with HTTP method names.

Let's add a new action class: MessageAction and action method get(). There is also a nice way how to specify path patterns that will be matched and populated into the @In parameters, just use string template and {} macros.

                
@MadvocAction
public class MessageAction {

    @PetiteInject
    AppService appService;

    @RestAction("{messageId}")
    public Message get(@In long messageId) {
        return appService.findMessageById(messageId);
    }
          

See the REST code changes - there are more tricks inside!

And that's it! Return a message object and it will be serialized to JSON.

What We Have Learned?

We hope this tutorial was enough to get you interested in Jodd. You have learned essentials of core Jodd micro-frameworks. There is Petite dependency-injection container for gluing the components. We use 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 tutorial we are 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 the single 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 tutorial. 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... Jodd has it all.

http://jodd.org

Built by Igor & friends with .