RSS

Monthly Archives: June 2012

Nested field access with FEST Reflect

Abstract: For one reason or another it’s often needed to access fields which are nested (sometimes deeply nested) within other fields. Of course you can write the logic yourself or (from now on) you can simply use the light-weighted framework FEST Reflect v1.4 (compatible with Java 1.5 and above). This short blog will show you how.

Acknowledgement: My gratitude goes to the open source community and to the following people:
Joel Costigliola for his support and open mind
Jonathan Melly for inspiring the idea of accessing nested fields

Goal: Discover the nested field functionality coming with the new release of FEST Reflect.

The maven dependency for FEST Reflect is as follows:

  <dependency>
    <groupId>org.easytesting</groupId>
    <artifactId>fest-reflect</artifactId>
    <version>1.4</version>
  </dependency>

Example 1: Setting a 1st level nested field

For this example we are going to need a simple service to start with, let’s say BusinessService :

public class BusinessService {
    private final NotificationService notificationService;

    public BusinessService() {
      this.notificationService = new NotificationService();
    }

    public void doBusinessLogic() {
      // ...
      notificationService.notifySomeone();
    }
   
  }

Our BusinessService is doing some business logic and in the end is notifying someone by using the NotificationService:

public class NotificationService {
    private final Logger logger = new Logger();
    private final IClientStatusDao clientStatusDao;

    public NotificationService() {
      this.clientStatusDao = new ClientStatusDao();
    }

    public void notifySomeone() {
      // notification logic goes here
      logger.info("About to update client status");
      clientStatusDao.updateStatus("client notified");
    }
  }

Now, imagine that you have a strong desire to access the logger field member inside the notificationService instance variable of our mighty BusinessService (for example when doing some testing). The path to the logger is: businessService.notificationService.logger

Here is how (line 7) you can take advantage of FEST Reflect:

import static org.fest.reflect.core.Reflection.field;

public class SomeTestClass {
  public void someTestMethod(){
    //some pre-testing logic ...
    Logger loggerMock = Mockito.mock(Logger.class);
    field("notificationService.logger").ofType(Logger.class).in(businessService)//
      .set(loggerMock);
    //some testing logic ...
  }
}

Notice that I’ve specified only “notificationService.logger” as an argument of the org.fest.reflect.core.Reflection.field() method. That’s because we give the root (businessService) of the path as an argument of the in() method. Yes, you’ve guessed it, that’s why I call this example accessing 1st level nested field.

By the way you don’t need to be testing in order to use FEST Reflect there are other situation where you can profit from accessing nested fields.

Example 2: Getting a 2nd level nested generic type field

There is no limit at what level the field at which you are interested is located (as long as you type the correct path to it).
Let’s continue our example and explore the ClientStatusDao class:

public class ClientStatusDao implements IClientStatusDao {
    private final Session session;
    private final List<String> listOfNotifications = Arrays.asList("General Notification", "Greetings");

    public ClientStatusDao() {
      this.session = new SessionImpl();
    }

    public void updateStatus(String newStatus) {
      session.startTransaction();
      // here we can use somehow our list of notifications and update status
      session.stopTransaction();
    }
  }

This time we are going to access an instance variable with a bit more complex type, namely the listOfNotifications which is of a List<String> type. Here is the one and only line you need (assuming you’ve already imported the static field method member (or all static members) of org.fest.reflect.core.Reflection):

List<String> listOfNames = field("notificationService.clientStatusDao.listOfNames").ofType(new TypeRef<List<String>>() {}).in(businessService).get();

Well, that was all for now folks. Please, leave a comment if you would like to share your views,recommendations, use-cases or requests. If you would like to contribute you can do it via GitHub FEST Reflect (you can add your requests at GitHub FEST Project Issues).

P.S.
In case you are wondering what else you can do with FEST Reflect and how to play with field access don’t forget to check my previous post on how to decorate fields (yes, you can decorate nested fields as well).

Advertisements
 
1 Comment

Posted by on June 18, 2012 in Uncategorized

 

Skeleton of a JavaScript web application

Abstract: The present article will give a brief introduction to a way of building JavaScript based web applications using RequireJS (version 2.0.1), jQuery (version 1.7.2), Underscore (version 1.3.3.), Backbone.js (version 0.9.2), Backbone.Marionette (version 0.8.4), Handlebars (version 1.0.beta.6), TrafficCop (version 0.3.0), Maven(vesion 3.0.3), and Jetty (version 8.1.4.v20120524 used in embedded mode).

Acknowledgement
: My gratitude goes to the open source community, to the above mentioned projects, and to the following guys:
David Sulc – A simple Backbone.Marionette tutorial
Mavenizing Javascript Projects

Be aware: Since this example serves a static web content you may simply load the index.html file, however be aware that doing so may result in

XMLHttpRequest cannot load file:///… Origin null is not allowed by Access-Control-Allow-Origin.

If this happens you can either do as told below or look at: stackoverflow

The final goal of this tutorial will be to create a very simple modular structure for displaying project names. Let’s start. Here is what the structure of our final project will look like:

.
|-- pom.xml
`-- src
    |-- main
    |   `-- js
    |       `-- app
    |           `-- model
    |               `-- Project.js
    |               `-- Projects.js
    |           `-- view
    |               `-- ProjectView.js
    |               `-- ProjectsView.js
    |           `-- application.js
    |       `-- lib
    |           `-- backbone.js
    |           `-- backbone.marionette.js
    |           `-- handlebars-1.0.0.beta.6.js
    |           `-- require-jquery.js
    |           `-- TrafficCop.js
    |           `-- underscore.js
    |       `-- templates
    |           `-- project-template.html
    |           `-- projects-template.html
    |       `-- index.html
    |       `-- main.js
    `-- test
        `-- js

… and here is our pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>project-name</groupId>
    <artifactId>project-id</artifactId>
    <version>1.0</version>

    <build>
        <plugins>
            <plugin>
                <groupId>org.mortbay.jetty</groupId>
                <artifactId>jetty-maven-plugin</artifactId>
                <version>8.1.4.v20120524</version>
                <configuration>
                    <webAppConfig>
                        <contextPath>/${project.artifactId}</contextPath>
                        <baseResource implementation="org.eclipse.jetty.util.resource.ResourceCollection">
                            <resourcesAsCSV>src/main/js/,src/main/js/app</resourcesAsCSV>
                        </baseResource>
                    </webAppConfig>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

The first thing we’re going to need is a base index.html file:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
    <title>Project Knowledge Management</title>
    <script data-main="main" src="lib/require-jquery.js"></script>
</head>
<body>
<h1>Projects</h1>
<div id="content"></div>
</body>
</html>

As you can see (within the first highlighted row, line 5), this file has two references one to main which is actually a reference to main.js and one to require-jquery.js which you can download from here (this file contains jQuery inside, thus you don’t need a separate jQuery). Note that the second highlighted row (line 9) will contain our future content (this is going to be our hook point linked to application.js). So what’s inside main.js? Here it is:

require.config( {
    paths:{
        underscore:'lib/underscore',
        backbone:'lib/backbone',
        marionette:'lib/backbone.marionette',
        handlebars:'lib/handlebars-1.0.0.beta.6',
        TrafficCop:'lib/TrafficCop',
        app:'app/application',
        projects:'app/model/Projects',
        project:'app/model/Project'
    }
} );

require([ 'jquery', 'TrafficCop', 'underscore', 'backbone', 'marionette', 'handlebars', 'app','projects', 'project'],
        function ( $, TrafficCop, _, Backbone, Marionette, Handlebars, App, Projects, Project) {
                  Backbone.Marionette.TemplateCache.loadTemplate = function(templateId, callback){
                    var tmpId = templateId.replace("#", "");
                    var url = "templates/" + tmpId + ".html";
                    var promise = $.trafficCop(url);
                    promise.done(function(template){
                      callback.call(this, Handlebars.compile($(template).html()));
                    });
                  }

            var projects = new Projects([
                             new Project({ name: 'First Project' }),
                             new Project({ name: 'Second Project }),
                             new Project({ name: 'Third Project' })
                             ]);
                    App.start({projects: projects});
        }
);

Yes, you’ve guessed it, the fun start here. The necessary ingredients you can download (and place in the lib folder) from here: underscore, backbone, backbone.marionette, handlebars, TrafficCop. Well that was all of the external libs, now comes the time to build our internal business project structure. First we are going to need a model of a project, thus we are going to create a simple Backbone.js model within a file called Project.js:

define(['backbone'], function(Backbone){
         var Project = Backbone.Model.extend({});
         return Project;
});

As you can see, there is not much interesting inside since our example is really only a skeleton. After we have our main domain model, we are going to need a collection of them, thus comes the Projects.js:

define(['backbone', 'model/Project'], function(Backbone, Project){
         var Projects = Backbone.Collection.extend({
           model: Project

         });
         return Projects;
});

So far so good. Next we are going to need an entry point, that being the application.js:

define(['view/ProjectsView'], function(ProjectsView){
var App = new Backbone.Marionette.Application();
         App.addRegions({
           mainRegion: "#content"
         });

         App.addInitializer(function(options){
           var projectsView = new ProjectsView({
             collection: options.projects
           });
           App.mainRegion.show(projectsView);
         });
         return App;
});

Note line 4, this is the reference to our hook point in the index.html file. As you can see from line 8, our App has a reference to a view called ProjectsView for which we have a JavaScript file called ProjectsView.js and having the following content:

define(['marionette', '../view/ProjectView'], function(Marionette, ProjectView){
         var ProjectsView = Backbone.Marionette.CompositeView.extend({
         tagName: 'table',
         id: 'projects',
         className: 'table-striped table-bordered',
         template: '#projects-template',
         itemView: ProjectView,

         appendHtml: function(collectionView, itemView){
         collectionView.$("tbody").append(itemView.el);
         }
         });
         return ProjectsView;
});

The ProjectsView is a composite view based on ProjectView described in ProjectView.js:

define(['marionette'], function(Marionette){
         var ProjectView = Backbone.Marionette.ItemView.extend({
          template: '#project-template',
          tagName: 'tr',
          className: 'project'
         });
         return ProjectView;
}); 

The highlighted rows in both ProjectsView.js and ProjectView.js indicate the names of the required templates which can be found in templates directory. The first, projects-template.html, looks like this:

<script id="projects-template" type="text/x-handlebars-template">
    <thead>
    <tr class='header'>
        <th>Project Name</th>
    </tr>
    </thead>
    <tbody>
    </tbody>
</script>

The second, project-template.html, looks like this:

<script id="project-template" type="text/x-handlebars-template">
    {{name}}
</script>

Running our example is as simple as doing mvn jetty:run. Oh, and of course you can go to localhost:8080 and browse the result.