I have a batch job that retrieves records from a database, processes them, and passes the result into the writer. The bean passed to the writer has four fields that need to be written to separate xml files. One of the fields is a bean representing the original record, and the other three fields are collections of child elements associated with the record.
I initially tried to use jackson to parse the beans and generate the files, but I found that approach had trouble when applied to the batch model.
Next, I've shifted to using StaxEventItemWriter
s for each child field, which individually seem perfectly adequate, but I'm having trouble implementing a writer that can handle all the various sub-types. I've looked into the CompositeItemWriter
and ClassifierCompositeItemWriter
, but they seem more suited to having multiple writers for the same type of bean, whereas I need multiple writers appropriate for differing types. Any advice would be greatly appreciated!
Domain example:
public class MyBean {
private RecordBean recordBean;
private List<ChildTypeA> aBeans;
private List<ChildTypeB> bBeans;
private List<ChildTypeC> cBeans;
}
@XmlRootElement(name = "RECORD")
public class RecordBean extends MyAbstractBean {
@XmlElement(name = "ID")
private String recordId;
@XmlElementWrapper(name = "A_CHILDREN")
@XmlElement(name="CHILD_TYPE_A")
List<Long> aChildIds}
@XmlElementWrapper(name = "B_CHILDREN")
@XmlElement(name="CHILD_TYPE_B")
List<Long> bChildIds}
@XmlElementWrapper(name = "C_CHILDREN")
@XmlElement(name="CHILD_TYPE_C")
List<Long> cChildIds}
}
@XmlRootElement(name = "CHILD_TYPE_A")
public class ChildTypeA extends MyAbstractBean {
@XmlElement(name = "ID") private String aId;
}
@XmlRootElement(name = "CHILD_TYPE_B")
public class ChildTypeB extends MyAbstractBean {
@XmlElement(name = "ID") private String bId;
}
@XmlRootElement(name = "CHILD_TYPE_C")
public class ChildTypeC extends MyAbstractBean {
@XmlElement(name = "ID") private String cId;
}
For each container bean passed to the writer, I need to create a unique XML file for each RecordBean
e.g. record_1.xml, and I need to write each collection into an aggregate file that will serve as a library of all children for that child type, across all the records.
Output example: record_1.xml
<?xml version="1.0" encoding="UTF-8"?>
<RECORD>
<ID>1</ID>
<A_CHILDREN>
<CHILD_TYPE_A>1</CHILD_TYPE_A>
<CHILD_TYPE_A>2</CHILD_TYPE_A>
</A_CHILDREN>
<B_CHILDREN>
<CHILD_TYPE_B>1</CHILD_TYPE_B>
<CHILD_TYPE_B>2</CHILD_TYPE_B>
</B_CHILDREN>
<A_CHILDREN>
<CHILD_TYPE_C>1</CHILD_TYPE_C>
<CHILD_TYPE_C>2</CHILD_TYPE_C>
</A_CHILDREN>
</RECORD>
</xml>
record_2.xml
<?xml version="1.0" encoding="UTF-8"?>
<RECORD>
<ID>2</ID>
<A_CHILDREN>
<CHILD_TYPE_A>3</CHILD_TYPE_A>
<CHILD_TYPE_A>4</CHILD_TYPE_A>
</A_CHILDREN>
<B_CHILDREN>
<CHILD_TYPE_B>3</CHILD_TYPE_B>
<CHILD_TYPE_B>4</CHILD_TYPE_B>
</B_CHILDREN>
<A_CHILDREN>
<CHILD_TYPE_C>3</CHILD_TYPE_C>
<CHILD_TYPE_C>4</CHILD_TYPE_C>
</A_CHILDREN>
</RECORD>
</xml>
a_children.xml
<?xml version="1.0" encoding="UTF-8"?>
<A_CHILDREN>
<CHILD_TYPE_A>
<ID>1</ID>
</CHILD_TYPE_A>
<CHILD_TYPE_A>
<ID>2</ID>
</CHILD_TYPE_A>
<CHILD_TYPE_A>
<ID>3</ID>
</CHILD_TYPE_A>
<CHILD_TYPE_A>
<ID>4</ID>
</CHILD_TYPE_A>
</A_CHILDREN>
</xml>
<!-- Decide which format to use -->
b_children.xml & c_children.xml are the same as a_children.xml.
So after the better part of two days, I decided to take a different approach. I think it would be possible to create a set of writers to handle the task, but I think it would require a fair amount of customization, and a complex hierarchy of delegation.
For example:
CompositeItemWriter
delegates to:ClassifierCompositeItemWriter
classifies, and delegates to:StaxEventItemWriter
for ChildTypeAStaxEventItemWriter
for ChildTypeBStaxEventItemWriter
for ChildTypeCMultiResourceItemWriter
Dynamically assigns FilesystemResource for each RecordBean.Despite the fact that it probably could be done, I realized that it's just simpler to write the XML as strings wherever I want. Something along the lines of:
Anyway, I hope this helps anyone digging into the Spring Batch weeds like I was. Cheers!