I used to use a library called Dozer for development using Spring Framework, but since it was a convenient library, I decided to use it with the Play Framework I am currently using, so I wrote the code. The created source is uploaded to GitHub.
A library that maps data between objects. It is very useful when passing data between layers with the MVC framework. First, let's look at a normal implementation that does not use Dozer. You will often write code like the following when passing data from the current layer to the next layer.
Normal mapping
//Current layer
//Pass data to the next layer bean
BeanB beanB = new BeanB();
beanB.field1 = beanA.field1;
beanB.field2 = beanA.field2;
beanB.field3 = beanA.field3;
.
.
.
//Processing of the next layer
service.run(beanB);
The above is a simple pattern, but if the bean implements a setter or getter, or if you are doing type conversion because the types are different between the beans, the readability is poor and the more parameters there are, the more verbose code It will be. In addition, if the bean increases or decreases parameters, the mapping must be modified each time. The following is an example using Dozer.
Dozer mapping
//Current layer
//Bean mapping by Dozer
Mapper mapper = new DozerBeanMapper();
BeanB beanB = mapper.map(beanA, BeanB.class);
//Processing of the next layer
service.run(beanB);
If you pass the copy source object in the first argument of the map method and the copy destination class in the second argument, the object of the copy destination class that holds the copy source data will be returned. This is because Dozer maps the data of the copy source to the parameter of the same name of the copy destination. Furthermore, if the type supports type conversion, type conversion will be performed automatically. For more information on type conversion support, see here (http://dozer.sourceforge.net/documentation/simpleproperty.html).
Let's try Dozer. I made an app that just inputs the name and amount from the screen and registers it, so I would like to introduce Dozer there. Installation is not particularly difficult as it can be used simply by adding it to build.sbt.
First, add the following to build.sbt and reload and update.
libraryDependencies += "net.sf.dozer" % "dozer" % "5.5.1"
After that, you can generate DozerBeanMapper in the layer that uses Dozer and use it, but this time I would like to define it in DI. Create a MappingModule class that inherits AbstractModule and define the dependencies.
MappingModule
//import omitted
public class MappingModule extends AbstractModule {
@Override
protected void configure() {
bind(Mapper.class).to(DozerBeanMapper.class);
}
}
Register the created MappingModule in applications.conf.
application.conf
play.modules {
enabled += modules.MappingModule
}
The beans used in each layer are defined as follows.
Bean | layer |
---|---|
Form | Client - Controller |
Dto | Controller - Service |
Model | Service - Repository |
Inject Mapper into the class you want to use Dozer. Since the following is the Controller class, we are mapping data from Form to Dto.
IndexController
package controllers;
//import omitted
public class IndexController extends Controller {
@Inject
private FormFactory formFactory;
@Inject
private Mapper mapper; //this
@Inject
private IndexService service;
//Other methods omitted
public Result post() {
Form<IndexForm> f = formFactory.form(IndexForm.class).bindFromRequest();
IndexDto dto = mapper.map(f.get(), IndexDto.class); //Mapping here
switch(f.get().action){
case "regist":
service.regist(dto);
break;
case "delete":
service.delete(dto);
break;
default:
}
return ok(views.html.index.render(f, dto));
}
}
After making a RequestBind to Form, data is mapped to Dto and processing is moved to the next layer (Service). Form and Dto are defined as follows.
IndexForm
package forms;
public class IndexForm {
/**Screen action*/
public String action;
/**name*/
public String name;
/**Amount of money*/
public String amount;
/**Delete ID*/
public String id;
}
IndexDto
package dtos;
//import omitted
public class IndexDto {
/**name*/
public String name;
/**Amount of money*/
public BigDecimal amount;
/**Delete ID*/
public Long id;
/**Data list*/
public List<Person> personList;
}
The type of the amount and the deletion ID are different, but the type conversion is performed in Mapper.
Since the server is actually started and the operation is confirmed, the source is uploaded to GitHub. Dozer can be customized to allow mapping between fields with different names and complex mapping, but I couldn't write because I didn't know how to set it in Play. I would like to investigate and update it.
Recommended Posts