JBatch is great as a way to standardize batch writing but there is nothing in the spec itself to do anything concrete (JPA, JDBC, …). In JavaSE you feel quite naked (even if BatchEE and Spring-Batch try to fill this providing some components) but in JavaEE it looks quite obvious: your JBatch components are CDI beans so you get easily injected your EntityManager and then do what you want as easily as saying it!…or almost. It is quite trivial for reader/writer but you rarely want to persist what you read when your batch is a database to database one.
That’s where the new ModelMapper integration module from BatchEE will help you.
If you don’t know ModelMapper you should have a look even for Entity/DTO mapping. The idea is to delegate to a mapper the mapping of an instance of a class A to an instance of B. The force of ModelMapper is to get nice defaults/conventions and a very nice way to override the config when needed (simply writing what the framework has to do – this is based on proxies which makes a really user friendly API :)).
Back to our simple batch doing DATABASE1 (Entity1) -> DATABASE2 (Entity2). Using JBatch we’ll pretty quickly use a chunk.
The ItemReader will query the database and return entities Entity1 (think to use pagination here), the ItemWriter will simply get a list of Entity2 to persist (it is great to align the commit interval of the chunk to the pagination of the reader). Both are quite simple so I’ll not detail them here…but we miss the way to get entities Entity2 in the writer since we read Entity1 in the reader.
I’ll suppose ModelMapper is able to map Entity1 to Entity2 without additional config (but if that’s not the case just override the BatchEE ModelMapperItemProcessor to customize the ModelMapper).
Here is what it will look like (without any code for the processor once batchee-modelmapper is imported):
<?xml version="1.0" encoding="UTF-8"?> <job id="modelmapper-processor" xmlns="http://xmlns.jcp.org/xml/ns/javaee" version="1.0"> <step id="step1"> <chunk> <reader ref="org.superbiz.Database1Reader" /> <processor ref="modelMapperProcessor"> <!-- shortname is a batchee feature, use qualified name for portability --> <properties> <property name="destinationType" value="org.superbiz.Entity2" /> </properties> </processor> <writer ref="org.superbiz.Database2Writer" /> </chunk> </step> </job>
This use case was a database to database but in fact it works pretty well for all mapped object to another mapped object flow (JAXB, JPA, XmlBeans, Jackson, …).