Camel bindy определяет заголовок как " отдельную запись заголовка в начале файла / потока " и нижний колонтитул как " одну запись нижнего колонтитула в конце файла / потока", см. [Документ о верблюде-бинди] [1].
Ваши тестовые данные содержат метаданные до и после части с несколькими полезными нагрузками в одной строке, вы не можете использовать модели верхнего и нижнего колонтитула Bindy для анализа этого.
Вместо этого создайте независимые модели Bindy для заголовка, нижнего колонтитула и одного тела (по существу удаляя заголовок = VoLTEHeader.class, footer = VoLTEFooter.class "из VoLTEBody) и индивидуально обработайте заголовок, нижний колонтитул и тела:
public class MyRouteBuilderTest extends CamelTestSupport {
@Produce(uri="direct:start")
private ProducerTemplate producer;
@Override
protected RouteBuilder createRouteBuilder() {
return new RouteBuilder() {
public void configure() {
DataFormat bindyHeader = new BindyFixedLengthDataFormat(VoLTEHeader.class);
DataFormat bindyFooter = new BindyFixedLengthDataFormat(VoLTEFooter.class);
DataFormat bindyOneBody = new BindyFixedLengthDataFormat(VoLTEBody.class);
from("direct:start")
// assuming the raw record is in the body, we keep a copy in a Camel-header
.setHeader("record", body())
// get the VoLTE header string into the Camel-body and unmarshal, then put VoLTE header object into Camel-header for later use
.setBody().groovy("request.body.substring(0,20)")
.unmarshal(bindyHeader)
.setHeader("header", body())
// restore VoLTE record string to Camel-body, get the VoLTE footer string into the Camel-body and unmarshal, then put footer VoLTE object into Camel-header for later use
.setBody().header("record")
.setBody().groovy("request.body.substring(request.body.length()-20,request.body.length())")
.unmarshal(bindyFooter)
.setHeader("footer", body())
// restore VoLTE record string to Camel-body, get the multi-bodies string into the Camel-body
.setBody().header("record")
.setBody().groovy("request.body.substring(20,request.body.length()-20)")
// Split VoLTE bodies string to each 20 char length, unmarshal each and finally put the list of VoLTE body objects into a Camel-header
.setBody().groovy("request.body.split('(?<=\\\\G.{20})')")
.split(body(), AggregationStrategies.flexible().storeInHeader("bodyList").accumulateInCollection(ArrayList.class))
.unmarshal(bindyOneBody)
.end()
// now do something with the unmarshalled objects in Camel-headers "header" (type VoLTEHeader), "footer" (type VoLTEFooter) and "bodyList" (type List<VoLTEBody>)
.log("VoLTEHeader: ${header.header}")
.log("VoLTEBody*: ${header.bodyList}")
.log("VoLTEFooter: ${header.footer}")
;
}
};
}
@Test
public void test() throws Exception {
producer.sendBody("1VOLTE20190515 32010123456782019051520101234567820190516201012345678201905173AAAA.DAT ");
}
}
@FixedLengthRecord(length = 20, paddingChar = ' ')
public class VoLTEHeader {
@DataField(pos = 1, length = 1, trim = true)
String record_type;
@DataField(pos = 2, length = 5, trim = true)
String service_type;
@DataField(pos = 7, length = 8, trim = true)
String creation_date;
@DataField(pos = 15, length = 6, trim = true, align = "R")
String custom_flag;
@Override
public String toString() {
return String.format("VoLTEHeader[record_type=%s, service_type=%s, creation_date=%s, custom_flag=%s]", record_type, service_type, creation_date, custom_flag);
}
}
@FixedLengthRecord(length = 20)
public class VoLTEBody {
@DataField(pos = 1, length = 1, trim = true)
String record_type;
@DataField(pos = 2, length = 11, trim = true)
String mobile_number;
@DataField(pos = 13, length = 8, trim = true)
String call_start_date;
@Override
public String toString() {
return String.format("VoLTEBody[record_type=%s, mobile_number=%s, call_start_date=%s]", record_type, mobile_number, call_start_date);
}
}
@FixedLengthRecord(length = 20, paddingChar = ' ')
public class VoLTEFooter {
@DataField(pos = 1, length = 1, trim = true)
String record_type;
@DataField(pos = 2, length = 19, trim = true)
String file_name;
@Override
public String toString() {
return String.format("VoLTEFooter[record_type=%s, file_name=%s]", record_type, file_name);
}
}
Выход:
[main] INFO route1 - VoLTEHeader: VoLTEHeader[record_type=1, service_type=VOLTE, creation_date=20190515, custom_flag=3]
[main] INFO route1 - VoLTEBody*: [VoLTEBody[record_type=2, mobile_number=01012345678, call_start_date=20190515], VoLTEBody[record_type=2, mobile_number=01012345678, call_start_date=20190516], VoLTEBody[record_type=2, mobile_number=01012345678, call_start_date=20190517]]
[main] INFO route1 - VoLTEFooter: VoLTEFooter[record_type=3, file_name=AAAA.DAT ]
В конце маршрута у вас должен быть объект типа VoLTEHeader в заголовке Camel-заголовка, объект типа VoLTEFooter в заголовке Camel-заголовка и список VoLTEBody в заголовке Camel-bodyList , Теперь вы можете обработать их.